加入很多新内容,这波一块交了
This commit is contained in:
@@ -3,6 +3,11 @@ using System.Collections;
|
||||
|
||||
public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
{
|
||||
private sealed class PooledJudgeTag : MonoBehaviour
|
||||
{
|
||||
public GameObject prefabSource;
|
||||
}
|
||||
|
||||
public static Animation_GenerateJudgementSituationPrefab Instance;
|
||||
|
||||
[Header("Inspector")]
|
||||
@@ -42,6 +47,9 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
// Track last scene to detect scene changes
|
||||
private int lastSceneIndex = -1;
|
||||
private Coroutine prewarmJudgeCoroutine;
|
||||
private readonly System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<GameObject>> judgePools
|
||||
= new System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<GameObject>>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -147,7 +155,10 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
if (JudgeManager.IsDebugEnabled) Debug.Log($"[Animation_Generate] Spawning judge prefab: color={color}, result={judgeResult}, prefab={prefabToUse.name}");
|
||||
|
||||
GameObject instance = Instantiate(prefabToUse, spawnPoint);
|
||||
GameObject instance = GetPooledJudge(prefabToUse, spawnPoint);
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
instance.transform.localPosition = Vector3.zero;
|
||||
|
||||
// Documentation text normalized.
|
||||
@@ -159,6 +170,52 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
StartCoroutine(AnimateSprite(instance));
|
||||
}
|
||||
|
||||
public void PrewarmJudgePrefabs(int perPrefab = 1)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
if (prewarmJudgeCoroutine != null)
|
||||
{
|
||||
StopCoroutine(prewarmJudgeCoroutine);
|
||||
}
|
||||
|
||||
prewarmJudgeCoroutine = StartCoroutine(PrewarmJudgePrefabsRoutine(Mathf.Max(1, perPrefab)));
|
||||
}
|
||||
|
||||
public IEnumerator PrewarmJudgePrefabsRoutine(int perPrefab = 1)
|
||||
{
|
||||
GameObject[] prefabs =
|
||||
{
|
||||
perfect_judge_prefab,
|
||||
great_judge_prefab,
|
||||
good_judge_prefab,
|
||||
miss_judge_prefab
|
||||
};
|
||||
|
||||
int count = Mathf.Max(1, perPrefab);
|
||||
foreach (GameObject prefab in prefabs)
|
||||
{
|
||||
if (prefab == null)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
GameObject instance = null;
|
||||
try
|
||||
{
|
||||
instance = CreatePooledJudge(prefab);
|
||||
ReturnJudgeToPool(instance);
|
||||
}
|
||||
catch { }
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
prewarmJudgeCoroutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator AnimateSprite(GameObject obj)
|
||||
{
|
||||
if (obj == null) yield break;
|
||||
@@ -232,7 +289,76 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
// Documentation text normalized.
|
||||
|
||||
if (obj != null) Destroy(obj);
|
||||
if (obj != null) ReturnJudgeToPool(obj);
|
||||
}
|
||||
|
||||
private GameObject GetPooledJudge(GameObject prefab, Transform parent)
|
||||
{
|
||||
if (prefab == null || parent == null)
|
||||
return null;
|
||||
|
||||
if (!judgePools.TryGetValue(prefab, out var pool))
|
||||
{
|
||||
pool = new System.Collections.Generic.Stack<GameObject>();
|
||||
judgePools[prefab] = pool;
|
||||
}
|
||||
|
||||
GameObject instance = null;
|
||||
while (pool.Count > 0 && instance == null)
|
||||
{
|
||||
instance = pool.Pop();
|
||||
}
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
instance = CreatePooledJudge(prefab);
|
||||
}
|
||||
|
||||
if (instance == null)
|
||||
return null;
|
||||
|
||||
instance.transform.SetParent(parent, false);
|
||||
instance.SetActive(true);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private GameObject CreatePooledJudge(GameObject prefab)
|
||||
{
|
||||
if (prefab == null)
|
||||
return null;
|
||||
|
||||
GameObject instance = Instantiate(prefab, transform);
|
||||
var tag = instance.GetComponent<PooledJudgeTag>();
|
||||
if (tag == null)
|
||||
tag = instance.AddComponent<PooledJudgeTag>();
|
||||
tag.prefabSource = prefab;
|
||||
instance.SetActive(false);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void ReturnJudgeToPool(GameObject instance)
|
||||
{
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
var tag = instance.GetComponent<PooledJudgeTag>();
|
||||
if (tag == null || tag.prefabSource == null)
|
||||
{
|
||||
Destroy(instance);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!judgePools.TryGetValue(tag.prefabSource, out var pool))
|
||||
{
|
||||
pool = new System.Collections.Generic.Stack<GameObject>();
|
||||
judgePools[tag.prefabSource] = pool;
|
||||
}
|
||||
|
||||
instance.transform.SetParent(transform, false);
|
||||
instance.transform.localPosition = new Vector3(99999f, 99999f, 0f);
|
||||
instance.transform.localRotation = Quaternion.identity;
|
||||
instance.SetActive(false);
|
||||
pool.Push(instance);
|
||||
}
|
||||
|
||||
private Transform GetSpawnPoint(string color)
|
||||
|
||||
@@ -9,6 +9,7 @@ public class NoteData
|
||||
public string color; // Documentation text normalized.
|
||||
public string type; // Documentation text normalized.
|
||||
public float length; // Documentation text normalized.
|
||||
public string noteFunction;
|
||||
|
||||
// New fields for judgement recording
|
||||
// judgeOffsetMs: signed offset in milliseconds recorded at judgement time
|
||||
|
||||
@@ -326,6 +326,9 @@ public class GameManager : MonoBehaviour
|
||||
{
|
||||
Debug.Log("GameManager Start() initialized");
|
||||
|
||||
// Move first-hit one-time setup cost into scene load instead of the first judged note.
|
||||
StartCoroutine(PrewarmGameplayFirstHitPath());
|
||||
|
||||
// --- Initialize Statistics ---
|
||||
currentSong = BeatmapManager.pendingSongData ?? SongDataHolder.SelectedSongData;
|
||||
if (currentSong != null && !GameConfig.autoPlayEnabled)
|
||||
@@ -489,6 +492,34 @@ public class GameManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PrewarmGameplayFirstHitPath()
|
||||
{
|
||||
yield return null;
|
||||
|
||||
try
|
||||
{
|
||||
Note.PrewarmRuntimeCaches();
|
||||
HoldNote.PrewarmRuntimeCaches();
|
||||
|
||||
var judgeFx = Animation_GenerateJudgementSituationPrefab.Instance
|
||||
?? FindAnyObjectByType<Animation_GenerateJudgementSituationPrefab>();
|
||||
judgeFx?.PrewarmJudgePrefabs(1);
|
||||
|
||||
var fxEvent = effectEventController.Instance ?? FindAnyObjectByType<effectEventController>();
|
||||
if (fxEvent != null && fxEvent.isActiveAndEnabled)
|
||||
{
|
||||
// Cache target and pre-create SmoothShake via OnEnable/Awake path already present.
|
||||
}
|
||||
|
||||
var globalFx = globalNoteEffect.Instance ?? FindAnyObjectByType<globalNoteEffect>();
|
||||
globalFx?.PrewarmRuntime();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[GameManager] Gameplay prewarm failed: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Detect Space or yellow note key to request start (only before gameplay starts)
|
||||
|
||||
@@ -99,6 +99,18 @@ public class HoldNote : BaseNote
|
||||
return beatmapManagerCache;
|
||||
}
|
||||
|
||||
public static void PrewarmRuntimeCaches()
|
||||
{
|
||||
GetBeatmapManagerCached();
|
||||
if (allyCache == null || allyCache.Length < 10)
|
||||
allyCache = new AllyCombatant[10];
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
GetAllyForTrackCached(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static float JudgeToPmMultiplier(string judgeResult)
|
||||
{
|
||||
switch (judgeResult)
|
||||
@@ -326,9 +338,10 @@ public class HoldNote : BaseNote
|
||||
}
|
||||
|
||||
private float cachedTravelTime = 1.0f; // Cached travel time for distance optimization
|
||||
private bool isSyncNote;
|
||||
|
||||
public void Setup(int id, int trackIndex, float speed, float time, float delay,
|
||||
bool isEnd, float scheduledEnd, string color, KeyCode key, string type, float travelTimeSeconds, NoteJudgeConfig judgeConfig, NoteData noteData)
|
||||
bool isEnd, float scheduledEnd, string color, KeyCode key, string type, float travelTimeSeconds, NoteJudgeConfig judgeConfig, NoteData noteData, bool isSync = false)
|
||||
{
|
||||
this.id = id;
|
||||
// Ensure singletons are up to date if they were re-initialized (e.g. on scene reload)
|
||||
@@ -347,6 +360,7 @@ public class HoldNote : BaseNote
|
||||
this.key = key;
|
||||
this.type = type;
|
||||
this.judgeConfig = judgeConfig;
|
||||
this.isSyncNote = isSync;
|
||||
|
||||
this.noteID = id.ToString();
|
||||
this.keyToPress = key;
|
||||
@@ -659,6 +673,13 @@ public class HoldNote : BaseNote
|
||||
InputManager.Instance?.ShowJudgeResult(trackIndex, result);
|
||||
teamUIController.Instance?.OnJudgeResult(result);
|
||||
JudgeSoundManager.Instance?.PlayJudgeSound(result);
|
||||
|
||||
if (isSyncNote)
|
||||
{
|
||||
effectEventController.TryTriggerMultiNoteShake();
|
||||
}
|
||||
|
||||
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D collision)
|
||||
@@ -975,6 +996,16 @@ public class HoldNote : BaseNote
|
||||
{
|
||||
ScheduleReturnToPool(0.2f);
|
||||
}
|
||||
|
||||
if (segment == NoteSegment.Start && isSyncNote && result != "Miss")
|
||||
{
|
||||
effectEventController.TryTriggerMultiNoteShake();
|
||||
}
|
||||
|
||||
if (segment == NoteSegment.Start && result != "Miss")
|
||||
{
|
||||
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator DelayedReturn()
|
||||
|
||||
@@ -11,6 +11,7 @@ public class Note : BaseNote
|
||||
private bool hasLock = false; // track whether we hold the track lock
|
||||
|
||||
private NoteData noteData;
|
||||
private bool isSyncNote;
|
||||
|
||||
[Header("Inspector")]
|
||||
public NoteJudgeConfig judgeConfig; // Documentation text normalized.
|
||||
@@ -42,6 +43,18 @@ public class Note : BaseNote
|
||||
return beatmapManagerCache;
|
||||
}
|
||||
|
||||
public static void PrewarmRuntimeCaches()
|
||||
{
|
||||
GetBeatmapManagerCached();
|
||||
if (allyCache == null || allyCache.Length < 10)
|
||||
allyCache = new AllyCombatant[10];
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
GetAllyForTrackCached(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static float JudgeToPmMultiplier(string judgeResult)
|
||||
{
|
||||
switch (judgeResult)
|
||||
@@ -150,7 +163,7 @@ public class Note : BaseNote
|
||||
controller = GetComponent<NoteController>();
|
||||
}
|
||||
|
||||
public void Setup(KeyCode key, int trackIndex, float speed, float hitTime, string color, NoteJudgeConfig judgeConfig, NoteData data)
|
||||
public void Setup(KeyCode key, int trackIndex, float speed, float hitTime, string color, NoteJudgeConfig judgeConfig, NoteData data, bool isSync = false)
|
||||
{
|
||||
keyToPress = key;
|
||||
noteColor = color;
|
||||
@@ -161,6 +174,7 @@ public class Note : BaseNote
|
||||
hasLock = false;
|
||||
this.judgeConfig = judgeConfig;
|
||||
this.noteData = data;
|
||||
this.isSyncNote = isSync;
|
||||
|
||||
// Set miss deadline: hitTime + missRange (the latest time to judge before auto-miss)
|
||||
float missRange = (judgeConfig?.missRange ?? 0.5f);
|
||||
@@ -279,6 +293,13 @@ public class Note : BaseNote
|
||||
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { }
|
||||
LogTapJudge(judgeResult, 0f, false, true, pressTime);
|
||||
|
||||
if (isSyncNote)
|
||||
{
|
||||
effectEventController.TryTriggerMultiNoteShake();
|
||||
}
|
||||
|
||||
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
|
||||
|
||||
Judge();
|
||||
}
|
||||
|
||||
@@ -437,6 +458,13 @@ public class Note : BaseNote
|
||||
|
||||
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { }
|
||||
LogTapJudge(judgeResult, rawOffsetMs, rewrittenToPerfect, false, pressTime);
|
||||
|
||||
if (isSyncNote && judgeResult != "Miss")
|
||||
{
|
||||
effectEventController.TryTriggerMultiNoteShake();
|
||||
}
|
||||
|
||||
globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null);
|
||||
}
|
||||
|
||||
Judge();
|
||||
|
||||
@@ -390,7 +390,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
if (noteScript != null)
|
||||
{
|
||||
// Setup note script with timing parameters
|
||||
noteScript.Setup(key, noteData.trackIndex, noteSpeed, realtimeHit, noteData.color, judgeConfig, noteData);
|
||||
noteScript.Setup(key, noteData.trackIndex, noteSpeed, realtimeHit, noteData.color, judgeConfig, noteData, isSync);
|
||||
|
||||
// Configure controller for absolute positioning (replaces relative Translate)
|
||||
if (noteController != null)
|
||||
@@ -476,7 +476,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
if (holdNote != null)
|
||||
{
|
||||
// pass realtime hit time (startTime + note.time) and delay 0, include globalHitDelay
|
||||
holdNote.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, 0f, false, scheduledEndTime, noteData.color, key, "start", travelTime, judgeConfig, noteData);
|
||||
holdNote.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, 0f, false, scheduledEndTime, noteData.color, key, "start", travelTime, judgeConfig, noteData, isSync);
|
||||
|
||||
// 使用流速倍率 sm 直接进行缩放,确保长条音符在 0.5-2.0 范围内依然能完美衔接
|
||||
float visualScale = sm;
|
||||
@@ -508,7 +508,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
if (holdSeg != null)
|
||||
{
|
||||
// Documentation text normalized.
|
||||
holdSeg.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, segmentDelay, false, scheduledEndTime, noteData.color, key, "middle", travelTime, judgeConfig, noteData);
|
||||
holdSeg.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, segmentDelay, false, scheduledEndTime, noteData.color, key, "middle", travelTime, judgeConfig, noteData, false);
|
||||
|
||||
// 应用与开始段一致的流速缩放
|
||||
float visualScaleMid = sm;
|
||||
@@ -540,7 +540,7 @@ public class NoteSpawner : MonoBehaviour
|
||||
HoldNote holdEnd = endObj.GetComponent<HoldNote>();
|
||||
if (holdEnd != null)
|
||||
{
|
||||
holdEnd.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, endDelay, true, scheduledEndTime, noteData.color, key, "end", travelTime, judgeConfig, noteData);
|
||||
holdEnd.Setup(holdNoteId, noteData.trackIndex, noteSpeed, baseHit, endDelay, true, scheduledEndTime, noteData.color, key, "end", travelTime, judgeConfig, noteData, false);
|
||||
|
||||
// 同样应用流速缩放
|
||||
float visualScaleEnd = sm;
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
using SmoothShakeFree;
|
||||
using UnityEngine;
|
||||
|
||||
public class effectEventController : MonoBehaviour
|
||||
{
|
||||
public enum CameraOffsetAxis
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
}
|
||||
|
||||
public static effectEventController Instance { get; private set; }
|
||||
|
||||
[Header("Multi Note Screen Shake")]
|
||||
public bool enableMultiNoteScreenShake = true;
|
||||
public float multiNoteScreenShakeAmplitude = 0.08f;
|
||||
|
||||
[Header("Camera Drift")]
|
||||
public bool enableCameraDrift = false;
|
||||
public Vector2 cameraDriftRange = new Vector2(0.15f, 0.08f);
|
||||
public float cameraDriftSpeed = 0.3f;
|
||||
|
||||
[Header("Player Skill 10 Camera Offset")]
|
||||
public float playerSkillCameraOffsetAmount = 0.6f;
|
||||
public CameraOffsetAxis playerSkillCameraOffsetAxis = CameraOffsetAxis.Y;
|
||||
|
||||
private Transform cachedShakeTarget;
|
||||
private Transform cachedCameraDriftPivot;
|
||||
private Transform cachedCameraSkillPivot;
|
||||
private Vector3 cameraDriftBaseLocalPosition;
|
||||
private Vector3 cameraSkillBaseLocalPosition;
|
||||
private float cameraDriftSeedX;
|
||||
private float cameraDriftSeedY;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
cameraDriftSeedX = Random.Range(0f, 1000f);
|
||||
cameraDriftSeedY = Random.Range(1000f, 2000f);
|
||||
CacheShakeTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
CacheShakeTarget();
|
||||
ResetCameraDriftIfNeeded();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
UpdateCameraDrift();
|
||||
UpdatePlayerSkillCameraOffset();
|
||||
}
|
||||
|
||||
private void CacheShakeTarget()
|
||||
{
|
||||
if (Camera.main != null)
|
||||
{
|
||||
cachedShakeTarget = Camera.main.transform;
|
||||
PrewarmShakeComponent();
|
||||
EnsureCameraDriftPivot();
|
||||
EnsureCameraSkillPivot();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrewarmShakeComponent()
|
||||
{
|
||||
if (cachedShakeTarget == null)
|
||||
return;
|
||||
|
||||
SmoothShake shake = cachedShakeTarget.GetComponent<SmoothShake>();
|
||||
if (shake == null)
|
||||
{
|
||||
shake = cachedShakeTarget.gameObject.AddComponent<SmoothShake>();
|
||||
}
|
||||
|
||||
if (shake.positionShake == null) shake.positionShake = new Shaker();
|
||||
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
|
||||
if (shake.shakers == null || shake.shakers.Length != 2)
|
||||
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
|
||||
if (shake.sum == null || shake.sum.Length != 2)
|
||||
shake.sum = new Vector3[2];
|
||||
}
|
||||
|
||||
private void EnsureCameraDriftPivot()
|
||||
{
|
||||
if (cachedShakeTarget == null)
|
||||
return;
|
||||
|
||||
if (cachedCameraDriftPivot != null)
|
||||
return;
|
||||
|
||||
Transform currentParent = cachedShakeTarget.parent;
|
||||
if (currentParent != null && currentParent.name == "__effect_event_camera_drift_pivot")
|
||||
{
|
||||
cachedCameraDriftPivot = currentParent;
|
||||
cameraDriftBaseLocalPosition = cachedCameraDriftPivot.localPosition;
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject pivotObject = new GameObject("__effect_event_camera_drift_pivot");
|
||||
Transform pivot = pivotObject.transform;
|
||||
|
||||
if (currentParent != null)
|
||||
{
|
||||
pivot.SetParent(currentParent, false);
|
||||
pivot.localPosition = cachedShakeTarget.localPosition;
|
||||
pivot.localRotation = cachedShakeTarget.localRotation;
|
||||
pivot.localScale = Vector3.one;
|
||||
}
|
||||
else
|
||||
{
|
||||
pivot.position = cachedShakeTarget.position;
|
||||
pivot.rotation = cachedShakeTarget.rotation;
|
||||
}
|
||||
|
||||
cachedShakeTarget.SetParent(pivot, true);
|
||||
cachedShakeTarget.localRotation = Quaternion.identity;
|
||||
|
||||
cachedCameraDriftPivot = pivot;
|
||||
cameraDriftBaseLocalPosition = cachedCameraDriftPivot.localPosition;
|
||||
}
|
||||
|
||||
private void EnsureCameraSkillPivot()
|
||||
{
|
||||
if (cachedShakeTarget == null)
|
||||
return;
|
||||
|
||||
if (cachedCameraSkillPivot != null)
|
||||
return;
|
||||
|
||||
Transform currentParent = cachedShakeTarget.parent;
|
||||
if (currentParent != null && currentParent.name == "__effect_event_camera_skill_pivot")
|
||||
{
|
||||
cachedCameraSkillPivot = currentParent;
|
||||
cameraSkillBaseLocalPosition = cachedCameraSkillPivot.localPosition;
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject pivotObject = new GameObject("__effect_event_camera_skill_pivot");
|
||||
Transform pivot = pivotObject.transform;
|
||||
|
||||
if (currentParent != null)
|
||||
{
|
||||
pivot.SetParent(currentParent, false);
|
||||
pivot.localPosition = cachedShakeTarget.localPosition;
|
||||
pivot.localRotation = cachedShakeTarget.localRotation;
|
||||
pivot.localScale = Vector3.one;
|
||||
}
|
||||
else
|
||||
{
|
||||
pivot.position = cachedShakeTarget.position;
|
||||
pivot.rotation = cachedShakeTarget.rotation;
|
||||
pivot.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
cachedShakeTarget.SetParent(pivot, true);
|
||||
cachedShakeTarget.localPosition = Vector3.zero;
|
||||
cachedShakeTarget.localRotation = Quaternion.identity;
|
||||
|
||||
cachedCameraSkillPivot = pivot;
|
||||
cameraSkillBaseLocalPosition = cachedCameraSkillPivot.localPosition;
|
||||
}
|
||||
|
||||
private void UpdateCameraDrift()
|
||||
{
|
||||
if (cachedShakeTarget == null)
|
||||
{
|
||||
CacheShakeTarget();
|
||||
}
|
||||
|
||||
if (cachedShakeTarget == null)
|
||||
return;
|
||||
|
||||
EnsureCameraDriftPivot();
|
||||
if (cachedCameraDriftPivot == null)
|
||||
return;
|
||||
|
||||
if (!enableCameraDrift)
|
||||
{
|
||||
ResetCameraDriftIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
float speed = Mathf.Max(0f, cameraDriftSpeed);
|
||||
float time = Time.time * speed;
|
||||
float offsetX = (Mathf.PerlinNoise(cameraDriftSeedX, time) - 0.5f) * 2f * Mathf.Abs(cameraDriftRange.x);
|
||||
float offsetY = (Mathf.PerlinNoise(cameraDriftSeedY, time) - 0.5f) * 2f * Mathf.Abs(cameraDriftRange.y);
|
||||
|
||||
cachedCameraDriftPivot.localPosition = cameraDriftBaseLocalPosition + new Vector3(offsetX, offsetY, 0f);
|
||||
}
|
||||
|
||||
private void ResetCameraDriftIfNeeded()
|
||||
{
|
||||
if (cachedCameraDriftPivot == null)
|
||||
return;
|
||||
|
||||
cachedCameraDriftPivot.localPosition = cameraDriftBaseLocalPosition;
|
||||
}
|
||||
|
||||
private void UpdatePlayerSkillCameraOffset()
|
||||
{
|
||||
if (cachedShakeTarget == null)
|
||||
{
|
||||
CacheShakeTarget();
|
||||
}
|
||||
|
||||
if (cachedShakeTarget == null)
|
||||
return;
|
||||
|
||||
EnsureCameraSkillPivot();
|
||||
if (cachedCameraSkillPivot == null)
|
||||
return;
|
||||
|
||||
Vector3 targetLocalPosition = cameraSkillBaseLocalPosition;
|
||||
if (PlayerSkillService.IsSkillEnabled(10))
|
||||
{
|
||||
float offset = playerSkillCameraOffsetAmount;
|
||||
switch (playerSkillCameraOffsetAxis)
|
||||
{
|
||||
case CameraOffsetAxis.X:
|
||||
targetLocalPosition.x += offset;
|
||||
break;
|
||||
case CameraOffsetAxis.Y:
|
||||
targetLocalPosition.y += offset;
|
||||
break;
|
||||
case CameraOffsetAxis.Z:
|
||||
targetLocalPosition.z += offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cachedCameraSkillPivot.localPosition != targetLocalPosition)
|
||||
{
|
||||
cachedCameraSkillPivot.localPosition = targetLocalPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RefreshPlayerSkillCameraOffset()
|
||||
{
|
||||
effectEventController controller = Instance != null ? Instance : FindAnyObjectByType<effectEventController>();
|
||||
if (controller == null)
|
||||
return;
|
||||
|
||||
controller.CacheShakeTarget();
|
||||
controller.UpdatePlayerSkillCameraOffset();
|
||||
}
|
||||
|
||||
public static void TryTriggerMultiNoteShake()
|
||||
{
|
||||
effectEventController controller = Instance != null ? Instance : FindAnyObjectByType<effectEventController>();
|
||||
if (controller == null)
|
||||
return;
|
||||
|
||||
controller.TriggerMultiNoteShakeInternal();
|
||||
}
|
||||
|
||||
private void TriggerMultiNoteShakeInternal()
|
||||
{
|
||||
if (!enableMultiNoteScreenShake)
|
||||
return;
|
||||
|
||||
if (cachedShakeTarget == null)
|
||||
{
|
||||
CacheShakeTarget();
|
||||
}
|
||||
|
||||
if (cachedShakeTarget == null)
|
||||
return;
|
||||
|
||||
float amplitudeValue = Mathf.Max(0f, multiNoteScreenShakeAmplitude);
|
||||
if (amplitudeValue <= 0f)
|
||||
return;
|
||||
|
||||
SmoothShake shake = cachedShakeTarget.GetComponent<SmoothShake>();
|
||||
if (shake == null)
|
||||
{
|
||||
shake = cachedShakeTarget.gameObject.AddComponent<SmoothShake>();
|
||||
}
|
||||
|
||||
if (shake.positionShake == null) shake.positionShake = new Shaker();
|
||||
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
|
||||
|
||||
shake.positionShake.noiseType = Shaker.NoiseType.SineWave;
|
||||
shake.positionShake.amplitude = new Vector3(amplitudeValue, amplitudeValue, 0f);
|
||||
shake.positionShake.frequency = new Vector3(20f, 20f, 0f);
|
||||
shake.rotationShake.amplitude = Vector3.zero;
|
||||
shake.rotationShake.frequency = Vector3.zero;
|
||||
|
||||
shake.timeSettings.constantShake = false;
|
||||
shake.timeSettings.fadeInDuration = 0.03f;
|
||||
shake.timeSettings.holdDuration = 0.04f;
|
||||
shake.timeSettings.fadeOutDuration = 0.05f;
|
||||
|
||||
if (shake.timeSettings.fadeInCurve == null || shake.timeSettings.fadeInCurve.length == 0)
|
||||
shake.timeSettings.fadeInCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
||||
if (shake.timeSettings.fadeOutCurve == null || shake.timeSettings.fadeOutCurve.length == 0)
|
||||
shake.timeSettings.fadeOutCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
|
||||
|
||||
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
|
||||
shake.sum = new Vector3[2];
|
||||
shake.StartShake();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f65edb710af433c479467d8c932e5d59
|
||||
@@ -0,0 +1,361 @@
|
||||
using SmoothShakeFree;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class globalNoteEffect : MonoBehaviour
|
||||
{
|
||||
public static globalNoteEffect Instance { get; private set; }
|
||||
|
||||
[Header("Camera Shake Event")]
|
||||
public float cameraShakeAmplitude = 0.12f;
|
||||
|
||||
[Header("Flash Blink Event")]
|
||||
public Image flashBlinkImage;
|
||||
public float flashBlinkFadeDuration = 0.2f;
|
||||
|
||||
[Header("Camera Dash Event")]
|
||||
public float targetCameraZPosition = -6.5f;
|
||||
public AnimationCurve cameraDashCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
||||
public float cameraDashDuration = 0.12f;
|
||||
|
||||
[Header("Camera Wave FX")]
|
||||
public float cameraWaveEnterDuration = 0.12f;
|
||||
public float cameraWaveRecoverDuration = 0.12f;
|
||||
|
||||
[Header("Camera Glitch FX")]
|
||||
public float cameraGlitchEnterDuration = 0.08f;
|
||||
public float cameraGlitchRecoverDuration = 0.12f;
|
||||
|
||||
[Header("Camera Monochrome FX")]
|
||||
public float cameraMonochromeEnterDuration = 0.1f;
|
||||
public float cameraMonochromeRecoverDuration = 0.14f;
|
||||
|
||||
[Header("Screenshot Scale FX")]
|
||||
public float screenshotScaleStartOpacity = 0.5f;
|
||||
public float screenshotScaleFadeDuration = 0.22f;
|
||||
public float screenshotScaleEndScale = 1.12f;
|
||||
|
||||
private Transform cachedCameraTransform;
|
||||
private Coroutine flashBlinkCoroutine;
|
||||
private Coroutine cameraDashCoroutine;
|
||||
private float cameraBaseLocalZ;
|
||||
private bool hasCameraBaseLocalZ;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else if (Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
CacheCameraTransform();
|
||||
PrewarmRuntime();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
SetFlashImageAlpha(0f);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
CacheCameraTransform();
|
||||
SetFlashImageAlpha(0f);
|
||||
PrewarmRuntime();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (cachedCameraTransform == null)
|
||||
{
|
||||
CacheCameraTransform();
|
||||
}
|
||||
|
||||
if (cachedCameraTransform != null && cameraDashCoroutine == null)
|
||||
{
|
||||
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
|
||||
hasCameraBaseLocalZ = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheCameraTransform()
|
||||
{
|
||||
if (Camera.main != null)
|
||||
{
|
||||
cachedCameraTransform = Camera.main.transform;
|
||||
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
|
||||
hasCameraBaseLocalZ = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void PrewarmRuntime()
|
||||
{
|
||||
CacheCameraTransform();
|
||||
|
||||
if (cachedCameraTransform != null)
|
||||
{
|
||||
SmoothShake shake = cachedCameraTransform.GetComponent<SmoothShake>();
|
||||
if (shake == null)
|
||||
{
|
||||
shake = cachedCameraTransform.gameObject.AddComponent<SmoothShake>();
|
||||
}
|
||||
|
||||
if (shake.positionShake == null) shake.positionShake = new Shaker();
|
||||
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
|
||||
if (shake.shakers == null || shake.shakers.Length != 2)
|
||||
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
|
||||
if (shake.sum == null || shake.sum.Length != 2)
|
||||
shake.sum = new Vector3[2];
|
||||
}
|
||||
|
||||
GlobalDistortionRuntimeController.EnsureInstance();
|
||||
GlobalGlitchRuntimeController.EnsureInstance();
|
||||
GlobalMonochromeRuntimeController.EnsureInstance();
|
||||
GlobalAfterimageRuntimeController.EnsureInstance();
|
||||
}
|
||||
|
||||
public static void TryTrigger(string noteFunction)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(noteFunction))
|
||||
return;
|
||||
|
||||
globalNoteEffect controller = GetOrCreateInstance();
|
||||
if (controller == null)
|
||||
return;
|
||||
|
||||
controller.TriggerInternal(noteFunction.Trim());
|
||||
}
|
||||
|
||||
private static globalNoteEffect GetOrCreateInstance()
|
||||
{
|
||||
if (Instance != null)
|
||||
return Instance;
|
||||
|
||||
globalNoteEffect found = FindAnyObjectByType<globalNoteEffect>();
|
||||
if (found != null)
|
||||
{
|
||||
Instance = found;
|
||||
return found;
|
||||
}
|
||||
|
||||
GameObject runtimeObject = new GameObject("__global_note_effect_runtime");
|
||||
return runtimeObject.AddComponent<globalNoteEffect>();
|
||||
}
|
||||
|
||||
private void TriggerInternal(string noteFunction)
|
||||
{
|
||||
switch (noteFunction)
|
||||
{
|
||||
case "CameraShakeEvent":
|
||||
TriggerCameraShake();
|
||||
break;
|
||||
case "FlashBlinkEvent":
|
||||
TriggerFlashBlink();
|
||||
break;
|
||||
case "CameraScaleEvent":
|
||||
TriggerCameraDash();
|
||||
break;
|
||||
case "CameraWaveFX":
|
||||
TriggerCameraWaveFx();
|
||||
break;
|
||||
case "CameraGlitchFX":
|
||||
TriggerCameraGlitchFx();
|
||||
break;
|
||||
case "CameraMonochromeFX":
|
||||
TriggerCameraMonochromeFx();
|
||||
break;
|
||||
case "ScreenshotScale":
|
||||
TriggerScreenshotScaleFx();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerCameraShake()
|
||||
{
|
||||
CacheCameraTransform();
|
||||
if (cachedCameraTransform == null)
|
||||
return;
|
||||
|
||||
float amplitudeValue = Mathf.Max(0f, cameraShakeAmplitude);
|
||||
if (amplitudeValue <= 0f)
|
||||
return;
|
||||
|
||||
SmoothShake shake = cachedCameraTransform.GetComponent<SmoothShake>();
|
||||
if (shake == null)
|
||||
{
|
||||
shake = cachedCameraTransform.gameObject.AddComponent<SmoothShake>();
|
||||
}
|
||||
|
||||
if (shake.positionShake == null) shake.positionShake = new Shaker();
|
||||
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
|
||||
|
||||
shake.positionShake.noiseType = Shaker.NoiseType.SineWave;
|
||||
shake.positionShake.amplitude = new Vector3(amplitudeValue, amplitudeValue, 0f);
|
||||
shake.positionShake.frequency = new Vector3(18f, 18f, 0f);
|
||||
shake.rotationShake.amplitude = Vector3.zero;
|
||||
shake.rotationShake.frequency = Vector3.zero;
|
||||
|
||||
shake.timeSettings.constantShake = false;
|
||||
shake.timeSettings.fadeInDuration = 0.02f;
|
||||
shake.timeSettings.holdDuration = 0.04f;
|
||||
shake.timeSettings.fadeOutDuration = 0.05f;
|
||||
|
||||
if (shake.timeSettings.fadeInCurve == null || shake.timeSettings.fadeInCurve.length == 0)
|
||||
shake.timeSettings.fadeInCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
||||
if (shake.timeSettings.fadeOutCurve == null || shake.timeSettings.fadeOutCurve.length == 0)
|
||||
shake.timeSettings.fadeOutCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
|
||||
|
||||
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
|
||||
shake.sum = new Vector3[2];
|
||||
shake.StartShake();
|
||||
}
|
||||
|
||||
private void TriggerFlashBlink()
|
||||
{
|
||||
if (flashBlinkImage == null)
|
||||
return;
|
||||
|
||||
if (flashBlinkCoroutine != null)
|
||||
{
|
||||
StopCoroutine(flashBlinkCoroutine);
|
||||
}
|
||||
|
||||
flashBlinkCoroutine = StartCoroutine(FlashBlinkCoroutine());
|
||||
}
|
||||
|
||||
private IEnumerator FlashBlinkCoroutine()
|
||||
{
|
||||
SetFlashImageAlpha(1f);
|
||||
|
||||
float duration = Mathf.Max(0.01f, flashBlinkFadeDuration);
|
||||
float elapsed = 0f;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
SetFlashImageAlpha(1f - t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SetFlashImageAlpha(0f);
|
||||
flashBlinkCoroutine = null;
|
||||
}
|
||||
|
||||
private void TriggerCameraDash()
|
||||
{
|
||||
CacheCameraTransform();
|
||||
if (cachedCameraTransform == null)
|
||||
return;
|
||||
|
||||
if (cameraDashCoroutine != null)
|
||||
{
|
||||
StopCoroutine(cameraDashCoroutine);
|
||||
if (hasCameraBaseLocalZ)
|
||||
{
|
||||
Vector3 resetPosition = cachedCameraTransform.localPosition;
|
||||
resetPosition.z = cameraBaseLocalZ;
|
||||
cachedCameraTransform.localPosition = resetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
cameraDashCoroutine = StartCoroutine(CameraDashCoroutine());
|
||||
}
|
||||
|
||||
private IEnumerator CameraDashCoroutine()
|
||||
{
|
||||
if (!hasCameraBaseLocalZ)
|
||||
{
|
||||
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
|
||||
hasCameraBaseLocalZ = true;
|
||||
}
|
||||
|
||||
float baseLocalZ = cameraBaseLocalZ;
|
||||
float targetZ = targetCameraZPosition;
|
||||
if (Mathf.Approximately(targetZ, baseLocalZ))
|
||||
{
|
||||
targetZ = baseLocalZ + 1.5f;
|
||||
}
|
||||
float duration = Mathf.Max(0.01f, cameraDashDuration);
|
||||
AnimationCurve curve = cameraDashCurve == null || cameraDashCurve.length == 0
|
||||
? AnimationCurve.EaseInOut(0f, 0f, 1f, 1f)
|
||||
: cameraDashCurve;
|
||||
|
||||
float elapsed = 0f;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
float curvedT = curve.Evaluate(t);
|
||||
Vector3 position = cachedCameraTransform.localPosition;
|
||||
position.z = Mathf.LerpUnclamped(baseLocalZ, targetZ, curvedT);
|
||||
cachedCameraTransform.localPosition = position;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
elapsed = 0f;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
float curvedT = curve.Evaluate(t);
|
||||
Vector3 position = cachedCameraTransform.localPosition;
|
||||
position.z = Mathf.LerpUnclamped(targetZ, baseLocalZ, curvedT);
|
||||
cachedCameraTransform.localPosition = position;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Vector3 finalPosition = cachedCameraTransform.localPosition;
|
||||
finalPosition.z = baseLocalZ;
|
||||
cachedCameraTransform.localPosition = finalPosition;
|
||||
cameraDashCoroutine = null;
|
||||
}
|
||||
|
||||
private void TriggerCameraWaveFx()
|
||||
{
|
||||
GlobalDistortionRuntimeController.TriggerWaveEffect(
|
||||
Mathf.Max(0.0001f, cameraWaveEnterDuration),
|
||||
Mathf.Max(0.0001f, cameraWaveRecoverDuration)
|
||||
);
|
||||
}
|
||||
|
||||
private void TriggerCameraGlitchFx()
|
||||
{
|
||||
GlobalGlitchRuntimeController.TriggerWaveEffect(
|
||||
Mathf.Max(0.0001f, cameraGlitchEnterDuration),
|
||||
Mathf.Max(0.0001f, cameraGlitchRecoverDuration)
|
||||
);
|
||||
}
|
||||
|
||||
private void TriggerCameraMonochromeFx()
|
||||
{
|
||||
GlobalMonochromeRuntimeController.Trigger(
|
||||
Mathf.Max(0.0001f, cameraMonochromeEnterDuration),
|
||||
Mathf.Max(0.0001f, cameraMonochromeRecoverDuration)
|
||||
);
|
||||
}
|
||||
|
||||
private void TriggerScreenshotScaleFx()
|
||||
{
|
||||
GlobalAfterimageRuntimeController.Trigger(
|
||||
Mathf.Clamp01(screenshotScaleStartOpacity),
|
||||
Mathf.Max(0.0001f, screenshotScaleFadeDuration),
|
||||
Mathf.Max(1f, screenshotScaleEndScale)
|
||||
);
|
||||
}
|
||||
|
||||
private void SetFlashImageAlpha(float alpha)
|
||||
{
|
||||
if (flashBlinkImage == null)
|
||||
return;
|
||||
|
||||
Color color = flashBlinkImage.color;
|
||||
color.a = Mathf.Clamp01(alpha);
|
||||
flashBlinkImage.color = color;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7aad6dbb8ac9a574b832837614506af8
|
||||
+73
-8
@@ -28,11 +28,19 @@ public class iNumberPrefabController : MonoBehaviour
|
||||
|
||||
private bool _warnedMissingPrefab;
|
||||
private bool _warnedMissingParents;
|
||||
private Transform pooledRoot;
|
||||
private readonly System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<playerInstantNumbersPrefab>> pools
|
||||
= new System.Collections.Generic.Dictionary<GameObject, System.Collections.Generic.Stack<playerInstantNumbersPrefab>>();
|
||||
private readonly System.Collections.Generic.Dictionary<playerInstantNumbersPrefab, GameObject> sourcePrefabs
|
||||
= new System.Collections.Generic.Dictionary<playerInstantNumbersPrefab, GameObject>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null) Instance = this;
|
||||
else if (Instance != this) { Destroy(gameObject); return; }
|
||||
|
||||
pooledRoot = new GameObject("__instant_number_pool").transform;
|
||||
pooledRoot.SetParent(transform, false);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@@ -150,19 +158,76 @@ public class iNumberPrefabController : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
var go = Instantiate(prefab, parent, false);
|
||||
if (go == null) return;
|
||||
var view = GetPooledInstance(prefab, parent);
|
||||
if (view != null) view.Play(type, signedValue);
|
||||
}
|
||||
|
||||
if (prefab.scene.IsValid())
|
||||
private playerInstantNumbersPrefab GetPooledInstance(GameObject prefab, Transform parent)
|
||||
{
|
||||
if (prefab == null || parent == null)
|
||||
return null;
|
||||
|
||||
if (!pools.TryGetValue(prefab, out var pool))
|
||||
{
|
||||
if (prefab.activeSelf) prefab.SetActive(false);
|
||||
pool = new System.Collections.Generic.Stack<playerInstantNumbersPrefab>();
|
||||
pools[prefab] = pool;
|
||||
}
|
||||
|
||||
// Ensure the newly created object is active before playing animation
|
||||
if (!go.activeInHierarchy) go.SetActive(true);
|
||||
playerInstantNumbersPrefab view = null;
|
||||
while (pool.Count > 0 && view == null)
|
||||
{
|
||||
view = pool.Pop();
|
||||
}
|
||||
|
||||
var view = go.GetComponent<playerInstantNumbersPrefab>();
|
||||
if (view != null) view.Play(type, signedValue);
|
||||
if (view == null)
|
||||
{
|
||||
var go = Instantiate(prefab, parent, false);
|
||||
if (go == null)
|
||||
return null;
|
||||
|
||||
view = go.GetComponent<playerInstantNumbersPrefab>();
|
||||
if (view == null)
|
||||
return null;
|
||||
|
||||
sourcePrefabs[view] = prefab;
|
||||
}
|
||||
else
|
||||
{
|
||||
view.transform.SetParent(parent, false);
|
||||
view.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
view.ResetForReuse();
|
||||
return view;
|
||||
}
|
||||
|
||||
public static bool ReturnInstance(playerInstantNumbersPrefab view)
|
||||
{
|
||||
if (Instance == null || view == null)
|
||||
return false;
|
||||
|
||||
return Instance.ReturnInstanceInternal(view);
|
||||
}
|
||||
|
||||
private bool ReturnInstanceInternal(playerInstantNumbersPrefab view)
|
||||
{
|
||||
if (view == null)
|
||||
return false;
|
||||
|
||||
if (!sourcePrefabs.TryGetValue(view, out var prefab) || prefab == null)
|
||||
return false;
|
||||
|
||||
if (!pools.TryGetValue(prefab, out var pool))
|
||||
{
|
||||
pool = new System.Collections.Generic.Stack<playerInstantNumbersPrefab>();
|
||||
pools[prefab] = pool;
|
||||
}
|
||||
|
||||
view.transform.SetParent(pooledRoot, false);
|
||||
view.ResetForReuse();
|
||||
view.gameObject.SetActive(false);
|
||||
pool.Push(view);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void WarnMissingPrefabOnce()
|
||||
|
||||
+24
-1
@@ -51,14 +51,33 @@ public class playerInstantNumbersPrefab : MonoBehaviour
|
||||
_canvasGroup.alpha = 1f;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_animationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_animationCoroutine);
|
||||
_animationCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Play(iNumberPrefabController.InstantNumberType type, int signedValue)
|
||||
{
|
||||
ResetForReuse();
|
||||
ApplyVisual(type, signedValue);
|
||||
|
||||
if (_animationCoroutine != null) StopCoroutine(_animationCoroutine);
|
||||
_animationCoroutine = StartCoroutine(Animate());
|
||||
}
|
||||
|
||||
public void ResetForReuse()
|
||||
{
|
||||
if (_canvasGroup != null) _canvasGroup.alpha = 1f;
|
||||
transform.localRotation = Quaternion.identity;
|
||||
transform.localScale = Vector3.one;
|
||||
if (_rectTransform != null) _rectTransform.anchoredPosition = Vector2.zero;
|
||||
else transform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
private void ApplyVisual(iNumberPrefabController.InstantNumberType type, int signedValue)
|
||||
{
|
||||
if (numberText != null)
|
||||
@@ -178,6 +197,10 @@ public class playerInstantNumbersPrefab : MonoBehaviour
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
_animationCoroutine = null;
|
||||
if (!iNumberPrefabController.ReturnInstance(this))
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,6 +524,8 @@ public class settlementController : MonoBehaviour
|
||||
targetTotalScore = targetPmScore + targetIdolScore;
|
||||
targetTotalPercent = (float)targetTotalScore / Mathf.Max(1, _1000000) * 100f;
|
||||
|
||||
PlayerSkillService.NotifySettlementCompleted(targetIdolScore);
|
||||
|
||||
finalScore_Text.text = targetTotalScore.ToString();
|
||||
pmScoreSum_Text.text = targetPmScore.ToString();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user