展前冒死重构
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
{
|
||||
@@ -23,51 +25,82 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
public GameObject good_judge_prefab;
|
||||
public GameObject miss_judge_prefab;
|
||||
|
||||
[Header("Inspector")]
|
||||
public GameObject trackSkill_prefab;
|
||||
|
||||
[Header("Inspector")]
|
||||
public float baseScale = 1.0f;
|
||||
public bool useRandomScale = true;
|
||||
public float minScaleMultiplier = 0.8f;
|
||||
public float maxScaleMultiplier = 1.2f;
|
||||
|
||||
[Header("Inspector")]
|
||||
public float jumpForce = 5.0f; // Documentation text normalized.
|
||||
public float gravity = -16f; // Documentation text normalized.
|
||||
[Tooltip("Horizontal drift distance range for judge popup text. Adds a real arc instead of a straight pop.")]
|
||||
public Vector2 horizontalDriftRange = new Vector2(0.25f, 0.65f);
|
||||
[Tooltip("Random Z rotation range applied over the popup lifetime.")]
|
||||
public float rotationRange = 8f;
|
||||
[Tooltip("Temporary scale punch at the beginning of the popup.")]
|
||||
public float scalePunch = 0.18f;
|
||||
[Tooltip("How long the initial scale punch takes before settling back.")]
|
||||
public float scalePunchDuration = 0.18f;
|
||||
[System.Serializable]
|
||||
public class PopupMotionSettings
|
||||
{
|
||||
public float jumpForce = 5.0f;
|
||||
public float gravity = -16f;
|
||||
[Tooltip("Horizontal drift distance range for popup text. Adds a real arc instead of a straight pop.")]
|
||||
public Vector2 horizontalDriftRange = new Vector2(0.25f, 0.65f);
|
||||
[Tooltip("Random Z rotation range applied over the popup lifetime.")]
|
||||
public float rotationRange = 8f;
|
||||
[Tooltip("Temporary scale punch at the beginning of the popup.")]
|
||||
public float scalePunch = 0.18f;
|
||||
[Tooltip("How long the initial scale punch takes before settling back.")]
|
||||
public float scalePunchDuration = 0.18f;
|
||||
public float fadeInTime = 0.1f;
|
||||
public float fadeOutStartTime = 0.6f;
|
||||
public float fadeOutDuration = 0.35f;
|
||||
}
|
||||
|
||||
[Header("Inspector")]
|
||||
public float fadeInTime = 0.1f; // Documentation text normalized.
|
||||
public float fadeOutStartTime = 0.6f; // Documentation text normalized.
|
||||
public float fadeOutDuration = 0.35f; // Documentation text normalized.
|
||||
[Header("Judge Popup")]
|
||||
public PopupMotionSettings judgePopup = new PopupMotionSettings()
|
||||
{
|
||||
jumpForce = 7.2f,
|
||||
gravity = -16f,
|
||||
horizontalDriftRange = new Vector2(0.25f, 0.65f),
|
||||
rotationRange = 8f,
|
||||
scalePunch = 0.18f,
|
||||
scalePunchDuration = 0.18f,
|
||||
fadeInTime = 0.1f,
|
||||
fadeOutStartTime = 0.3f,
|
||||
fadeOutDuration = 0.1f
|
||||
};
|
||||
|
||||
[Header("Track Skill Popup")]
|
||||
public PopupMotionSettings trackSkillPopup = new PopupMotionSettings()
|
||||
{
|
||||
jumpForce = 6.8f,
|
||||
gravity = -12.5f,
|
||||
horizontalDriftRange = new Vector2(0.18f, 0.48f),
|
||||
rotationRange = 6f,
|
||||
scalePunch = 0.14f,
|
||||
scalePunchDuration = 0.16f,
|
||||
fadeInTime = 0.08f,
|
||||
fadeOutStartTime = 0.36f,
|
||||
fadeOutDuration = 0.1f
|
||||
};
|
||||
|
||||
[Header("Track Skill UI")]
|
||||
[Tooltip("UI prefab spawned under world-space Effect nodes needs a small world scale. Judge SpriteRenderer prefabs still use baseScale directly.")]
|
||||
public float trackSkillUiScaleMultiplier = 0.01f;
|
||||
public int trackSkillSortingOrder = 9000;
|
||||
|
||||
// Cache spawn transforms to avoid accessing destroyed GameObject references.
|
||||
private Transform redSpawn;
|
||||
private Transform greenSpawn;
|
||||
private Transform yellowSpawn;
|
||||
private Transform purpleSpawn;
|
||||
private Transform blueSpawn;
|
||||
|
||||
// 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 readonly System.Collections.Generic.HashSet<GameObject> rentedJudges
|
||||
= new System.Collections.Generic.HashSet<GameObject>();
|
||||
private readonly Dictionary<GameObject, Stack<GameObject>> judgePools = new Dictionary<GameObject, Stack<GameObject>>();
|
||||
private readonly HashSet<GameObject> rentedJudges = new HashSet<GameObject>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
// Documentation text normalized.
|
||||
// Documentation text normalized.
|
||||
}
|
||||
else if (Instance != this)
|
||||
{
|
||||
@@ -81,13 +114,11 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Ensure spawn points are cached after all scene objects are initialized
|
||||
CacheSpawnPointsIfNeeded();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// Detect scene reload and refresh cache
|
||||
int currentSceneIndex = UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex;
|
||||
if (currentSceneIndex != lastSceneIndex)
|
||||
{
|
||||
@@ -103,10 +134,8 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
private void CacheSpawnPointsIfNeeded()
|
||||
{
|
||||
// Only recache if any of the references appear to be invalid (destroyed)
|
||||
if (redSpawn == null || greenSpawn == null || yellowSpawn == null || purpleSpawn == null || blueSpawn == null)
|
||||
{
|
||||
// Check if the effect GameObjects are still valid
|
||||
bool anyInvalid = (redEffect == null || redEffect.transform == null) ||
|
||||
(greenEffect == null || greenEffect.transform == null) ||
|
||||
(yellowEffect == null || yellowEffect.transform == null) ||
|
||||
@@ -122,16 +151,15 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
private void CacheSpawnPoints()
|
||||
{
|
||||
// Important: check Unity "fake null" before accessing .transform
|
||||
redSpawn = redEffect != null ? redEffect.transform : null;
|
||||
greenSpawn = greenEffect != null ? greenEffect.transform : null;
|
||||
yellowSpawn = yellowEffect != null ? yellowEffect.transform : null;
|
||||
purpleSpawn = purpleEffect != null ? purpleEffect.transform : null;
|
||||
blueSpawn = blueEffect != null ? blueEffect.transform : null;
|
||||
|
||||
|
||||
if (JudgeManager.IsDebugEnabled)
|
||||
{
|
||||
Debug.Log($"[Animation_Generate] Cached spawn points: red={redSpawn!=null}, green={greenSpawn!=null}, yellow={yellowSpawn!=null}, purple={purpleSpawn!=null}, blue={blueSpawn!=null}");
|
||||
Debug.Log($"[Animation_Generate] Cached spawn points: red={redSpawn != null}, green={greenSpawn != null}, yellow={yellowSpawn != null}, purple={purpleSpawn != null}, blue={blueSpawn != null}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,13 +200,37 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
instance.transform.localPosition = Vector3.zero;
|
||||
instance.transform.localRotation = Quaternion.identity;
|
||||
|
||||
// Documentation text normalized.
|
||||
float finalScale = baseScale;
|
||||
if (useRandomScale) finalScale *= Random.Range(minScaleMultiplier, maxScaleMultiplier);
|
||||
instance.transform.localScale = new Vector3(finalScale, finalScale, 1f);
|
||||
|
||||
// Documentation text normalized.
|
||||
StartCoroutine(AnimateSprite(instance));
|
||||
StartCoroutine(AnimatePopup(instance, judgePopup, false));
|
||||
}
|
||||
|
||||
public void SpawnTrackSkillPrefab(string color, Sprite skillIcon, string skillName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(color) || trackSkill_prefab == null)
|
||||
return;
|
||||
|
||||
Transform spawnPoint = GetSpawnPoint(color);
|
||||
if (spawnPoint == null)
|
||||
return;
|
||||
|
||||
GameObject instance = Instantiate(trackSkill_prefab, spawnPoint, false);
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
EnsureRenderableTrackSkillInstance(instance);
|
||||
BindTrackSkillContent(instance, skillIcon, skillName);
|
||||
|
||||
instance.transform.localPosition = Vector3.zero;
|
||||
instance.transform.localRotation = Quaternion.identity;
|
||||
float finalScale = baseScale;
|
||||
if (useRandomScale) finalScale *= Random.Range(minScaleMultiplier, maxScaleMultiplier);
|
||||
ApplyTrackSkillScale(instance, finalScale);
|
||||
instance.SetActive(true);
|
||||
|
||||
StartCoroutine(AnimatePopup(instance, trackSkillPopup, true));
|
||||
}
|
||||
|
||||
public void PrewarmJudgePrefabs(int perPrefab = 1)
|
||||
@@ -231,78 +283,98 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
prewarmJudgeCoroutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator AnimateSprite(GameObject obj)
|
||||
private IEnumerator AnimatePopup(GameObject obj, PopupMotionSettings settings, bool destroyAtEnd = false)
|
||||
{
|
||||
if (obj == null) yield break;
|
||||
if (settings == null) settings = judgePopup;
|
||||
|
||||
SpriteRenderer[] renderers = obj.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
Graphic[] graphics = obj.GetComponentsInChildren<Graphic>(true);
|
||||
CanvasGroup canvasGroup = obj.GetComponent<CanvasGroup>();
|
||||
|
||||
float elapsed = 0f;
|
||||
float vVelocity = jumpForce;
|
||||
float totalLifeTime = fadeOutStartTime + fadeOutDuration;
|
||||
float vVelocity = settings.jumpForce;
|
||||
float fadeDuration = Mathf.Max(0.001f, settings.fadeOutDuration);
|
||||
float estimatedApexTime = settings.gravity < -0.001f ? Mathf.Max(0f, settings.jumpForce / -settings.gravity) : settings.fadeOutStartTime;
|
||||
float totalLifeTime = Mathf.Max(settings.fadeInTime + fadeDuration, estimatedApexTime + fadeDuration);
|
||||
float driftSign = Random.value < 0.5f ? -1f : 1f;
|
||||
float driftDistance = Random.Range(horizontalDriftRange.x, horizontalDriftRange.y) * driftSign;
|
||||
float driftDistance = Random.Range(settings.horizontalDriftRange.x, settings.horizontalDriftRange.y) * driftSign;
|
||||
float horizontalVelocity = totalLifeTime > 0.001f ? driftDistance / totalLifeTime : 0f;
|
||||
float targetRotation = Random.Range(-rotationRange, rotationRange);
|
||||
float targetRotation = Random.Range(-settings.rotationRange, settings.rotationRange);
|
||||
Vector3 currentLocalPos = Vector3.zero;
|
||||
Vector3 baseScaleValue = obj.transform.localScale;
|
||||
bool fadeOutStarted = false;
|
||||
float fadeOutElapsed = 0f;
|
||||
float fadeOutStartAlpha = 1f;
|
||||
float currentAlpha = 0f;
|
||||
|
||||
SetRenderersAlpha(renderers, 0f);
|
||||
SetGraphicsAlpha(graphics, canvasGroup, 0f);
|
||||
|
||||
// Documentation text normalized.
|
||||
while (elapsed < totalLifeTime)
|
||||
while (!fadeOutStarted || fadeOutElapsed < fadeDuration)
|
||||
{
|
||||
if (obj == null) yield break;
|
||||
|
||||
float dt = Time.deltaTime;
|
||||
elapsed += dt;
|
||||
|
||||
// Documentation text normalized.
|
||||
vVelocity += gravity * dt;
|
||||
float previousVelocity = vVelocity;
|
||||
vVelocity += settings.gravity * dt;
|
||||
currentLocalPos.x += horizontalVelocity * dt;
|
||||
currentLocalPos.y += vVelocity * dt;
|
||||
obj.transform.localPosition = currentLocalPos;
|
||||
obj.transform.localRotation = Quaternion.Euler(0f, 0f, Mathf.Lerp(0f, targetRotation, Mathf.Clamp01(elapsed / totalLifeTime)));
|
||||
|
||||
float scaleT = scalePunchDuration > 0.001f ? Mathf.Clamp01(elapsed / scalePunchDuration) : 1f;
|
||||
float punch = Mathf.Sin(scaleT * Mathf.PI) * scalePunch;
|
||||
float scaleT = settings.scalePunchDuration > 0.001f ? Mathf.Clamp01(elapsed / settings.scalePunchDuration) : 1f;
|
||||
float punch = Mathf.Sin(scaleT * Mathf.PI) * settings.scalePunch;
|
||||
obj.transform.localScale = baseScaleValue * (1f + punch);
|
||||
|
||||
// Documentation text normalized.
|
||||
float alpha;
|
||||
bool reachedApex = previousVelocity > 0f && vVelocity <= 0f;
|
||||
if (!fadeOutStarted && (reachedApex || elapsed >= totalLifeTime - fadeDuration))
|
||||
{
|
||||
fadeOutStarted = true;
|
||||
fadeOutElapsed = 0f;
|
||||
fadeOutStartAlpha = currentAlpha;
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
if (elapsed < fadeInTime)
|
||||
float alpha;
|
||||
if (fadeOutStarted)
|
||||
{
|
||||
alpha = Mathf.InverseLerp(0f, fadeInTime, elapsed);
|
||||
fadeOutElapsed += dt;
|
||||
alpha = Mathf.Lerp(fadeOutStartAlpha, 0f, Mathf.Clamp01(fadeOutElapsed / fadeDuration));
|
||||
}
|
||||
// Documentation text normalized.
|
||||
else if (elapsed > fadeOutStartTime)
|
||||
else if (elapsed < settings.fadeInTime)
|
||||
{
|
||||
// Documentation text normalized.
|
||||
alpha = Mathf.InverseLerp(totalLifeTime, fadeOutStartTime, elapsed);
|
||||
alpha = Mathf.InverseLerp(0f, settings.fadeInTime, elapsed);
|
||||
}
|
||||
// Documentation text normalized.
|
||||
else
|
||||
{
|
||||
alpha = 1f;
|
||||
}
|
||||
|
||||
SetRenderersAlpha(renderers, Mathf.Clamp01(alpha));
|
||||
alpha = Mathf.Clamp01(alpha);
|
||||
currentAlpha = alpha;
|
||||
SetRenderersAlpha(renderers, alpha);
|
||||
SetGraphicsAlpha(graphics, canvasGroup, alpha);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
if (obj != null)
|
||||
{
|
||||
obj.transform.localScale = baseScaleValue;
|
||||
obj.transform.localRotation = Quaternion.identity;
|
||||
SetRenderersAlpha(renderers, 0f);
|
||||
SetGraphicsAlpha(graphics, canvasGroup, 0f);
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
|
||||
if (obj != null) ReturnJudgeToPool(obj);
|
||||
if (obj != null)
|
||||
{
|
||||
if (destroyAtEnd)
|
||||
Destroy(obj);
|
||||
else
|
||||
ReturnJudgeToPool(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetRenderersAlpha(SpriteRenderer[] renderers, float alpha)
|
||||
@@ -322,6 +394,104 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetGraphicsAlpha(Graphic[] graphics, CanvasGroup canvasGroup, float alpha)
|
||||
{
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = alpha;
|
||||
return;
|
||||
}
|
||||
|
||||
if (graphics == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < graphics.Length; i++)
|
||||
{
|
||||
Graphic graphic = graphics[i];
|
||||
if (graphic == null)
|
||||
continue;
|
||||
|
||||
Color c = graphic.color;
|
||||
c.a = alpha;
|
||||
graphic.color = c;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureRenderableTrackSkillInstance(GameObject instance)
|
||||
{
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
if (instance.GetComponentInChildren<Graphic>(true) == null)
|
||||
return;
|
||||
|
||||
Canvas canvas = instance.GetComponent<Canvas>();
|
||||
if (canvas == null)
|
||||
canvas = instance.AddComponent<Canvas>();
|
||||
|
||||
canvas.renderMode = RenderMode.WorldSpace;
|
||||
canvas.overrideSorting = true;
|
||||
canvas.sortingOrder = trackSkillSortingOrder;
|
||||
canvas.pixelPerfect = false;
|
||||
|
||||
CanvasGroup canvasGroup = instance.GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null)
|
||||
canvasGroup = instance.AddComponent<CanvasGroup>();
|
||||
canvasGroup.alpha = 1f;
|
||||
}
|
||||
|
||||
private void ApplyTrackSkillScale(GameObject instance, float finalScale)
|
||||
{
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
bool isUiPrefab = instance.GetComponentInChildren<Graphic>(true) != null;
|
||||
float appliedScale = isUiPrefab ? finalScale * trackSkillUiScaleMultiplier : finalScale;
|
||||
instance.transform.localScale = new Vector3(appliedScale, appliedScale, 1f);
|
||||
}
|
||||
|
||||
private void BindTrackSkillContent(GameObject instance, Sprite skillIcon, string skillName)
|
||||
{
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
Image targetImage = null;
|
||||
Text targetText = null;
|
||||
|
||||
TrackSkillPrefab modern = instance.GetComponent<TrackSkillPrefab>();
|
||||
if (modern != null)
|
||||
{
|
||||
modern.Bind(skillIcon, skillName);
|
||||
targetImage = modern.skillImage;
|
||||
targetText = modern.skillText;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackSkillPrefab legacy = instance.GetComponent<trackSkillPrefab>();
|
||||
if (legacy != null)
|
||||
{
|
||||
targetImage = legacy.track_skillIcon;
|
||||
targetText = legacy.track_skillName;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetImage == null)
|
||||
targetImage = instance.GetComponentInChildren<Image>(true);
|
||||
if (targetText == null)
|
||||
targetText = instance.GetComponentInChildren<Text>(true);
|
||||
|
||||
if (targetImage != null)
|
||||
{
|
||||
targetImage.sprite = skillIcon;
|
||||
targetImage.enabled = skillIcon != null;
|
||||
}
|
||||
|
||||
if (targetText != null)
|
||||
{
|
||||
targetText.text = string.IsNullOrWhiteSpace(skillName) ? string.Empty : skillName;
|
||||
}
|
||||
}
|
||||
|
||||
private GameObject GetPooledJudge(GameObject prefab, Transform parent)
|
||||
{
|
||||
if (prefab == null || parent == null)
|
||||
@@ -329,7 +499,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
if (!judgePools.TryGetValue(prefab, out var pool))
|
||||
{
|
||||
pool = new System.Collections.Generic.Stack<GameObject>();
|
||||
pool = new Stack<GameObject>();
|
||||
judgePools[prefab] = pool;
|
||||
}
|
||||
|
||||
@@ -384,7 +554,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
|
||||
if (!judgePools.TryGetValue(tag.prefabSource, out var pool))
|
||||
{
|
||||
pool = new System.Collections.Generic.Stack<GameObject>();
|
||||
pool = new Stack<GameObject>();
|
||||
judgePools[tag.prefabSource] = pool;
|
||||
}
|
||||
|
||||
@@ -399,8 +569,6 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
{
|
||||
if (string.IsNullOrEmpty(color)) return null;
|
||||
|
||||
// Documentation text normalized.
|
||||
|
||||
Transform point = null;
|
||||
switch (color.ToLower())
|
||||
{
|
||||
@@ -409,7 +577,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
case "yellow": point = yellowSpawn; break;
|
||||
case "purple": point = purpleSpawn; break;
|
||||
case "blue": point = blueSpawn; break;
|
||||
default:
|
||||
default:
|
||||
Debug.LogWarning($"[Animation_Generate] Unknown color: {color}");
|
||||
return null;
|
||||
}
|
||||
@@ -425,7 +593,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
private GameObject GetJudgePrefab(string result)
|
||||
{
|
||||
if (string.IsNullOrEmpty(result)) return null;
|
||||
|
||||
|
||||
GameObject prefab = null;
|
||||
switch (result.ToLower())
|
||||
{
|
||||
@@ -433,7 +601,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour
|
||||
case "great": prefab = great_judge_prefab; break;
|
||||
case "good": prefab = good_judge_prefab; break;
|
||||
case "miss": prefab = miss_judge_prefab; break;
|
||||
default:
|
||||
default:
|
||||
Debug.LogWarning($"[Animation_Generate] Unknown judge result: {result}");
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user