252 lines
8.2 KiB
C#
252 lines
8.2 KiB
C#
using UnityEngine;
|
|
|
|
public class Note : BaseNote
|
|
{
|
|
private KeyCode keyToPress;
|
|
private string noteColor;
|
|
private AnimationController anim;
|
|
private NoteController controller;
|
|
private bool isJudged = false;
|
|
|
|
private NoteData noteData;
|
|
|
|
[Header("���������")]
|
|
public NoteJudgeConfig judgeConfig; // �ж��������ã�����Ԥ���������ʱ��ֵ
|
|
|
|
// Cache allies per track to avoid GameObject.Find on every judge.
|
|
private static AllyCombatant[] allyCache;
|
|
|
|
private static AllyCombatant GetAllyForTrackCached(int trackIndex)
|
|
{
|
|
if (trackIndex < 0) return null;
|
|
if (allyCache == null || allyCache.Length < 10) allyCache = new AllyCombatant[10];
|
|
if (allyCache[trackIndex] != null) return allyCache[trackIndex];
|
|
|
|
var allyGo = GameObject.Find($"ally_0{trackIndex + 1}");
|
|
if (allyGo != null)
|
|
{
|
|
allyCache[trackIndex] = allyGo.GetComponent<AllyCombatant>();
|
|
}
|
|
return allyCache[trackIndex];
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
anim = GetComponent<AnimationController>();
|
|
controller = GetComponent<NoteController>();
|
|
}
|
|
|
|
public void Setup(KeyCode key, int trackIndex, float speed, float hitTime, string color, NoteJudgeConfig judgeConfig, NoteData data)
|
|
{
|
|
keyToPress = key;
|
|
noteColor = color;
|
|
TrackIndex = trackIndex;
|
|
Speed = speed;
|
|
this.hitTime = hitTime;
|
|
isJudged = false;
|
|
this.judgeConfig = judgeConfig;
|
|
this.noteData = data;
|
|
|
|
if (controller != null)
|
|
{
|
|
controller.SetSpeed(speed);
|
|
}
|
|
|
|
InputManager.OnKeyPressed += HandlePress;
|
|
|
|
// �ж��������ü��
|
|
if (judgeConfig == null)
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.LogError($"NoteJudgeConfig is null! �ж���������δ���룡track={trackIndex}");
|
|
}
|
|
else
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"NoteJudgeConfig: perfect={judgeConfig.perfectRange}, great={judgeConfig.greatRange}, good={judgeConfig.goodRange}, miss={judgeConfig.missRange}");
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
InputManager.OnKeyPressed -= HandlePress;
|
|
}
|
|
|
|
private void HandlePress(KeyCode key)
|
|
{
|
|
// ֻ�ж���ȷ��������ж���
|
|
if (isJudged || key != keyToPress || (controller != null && !controller.IsInJudgeZone()))
|
|
return;
|
|
|
|
float timeDifference = Mathf.Abs(Time.time - hitTime);
|
|
// ��������ƫ���ֵ��ǰ����ֵ���
|
|
float rawOffsetMs = (hitTime - Time.time) * 1000f;
|
|
string judgeResult = null;
|
|
|
|
if (judgeConfig != null)
|
|
{
|
|
if (timeDifference <= judgeConfig.perfectRange)
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Perfect");
|
|
judgeResult = "Perfect";
|
|
ScoreManager.Instance.countPerfect += 1;
|
|
if (noteData != null) noteData.judgeOffsetMs = rawOffsetMs;
|
|
}
|
|
else if (timeDifference <= judgeConfig.greatRange)
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Great");
|
|
judgeResult = "Great";
|
|
ScoreManager.Instance.countGreat += 1;
|
|
if (noteData != null) noteData.judgeOffsetMs = rawOffsetMs;
|
|
}
|
|
else if (timeDifference <= judgeConfig.goodRange)
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Good");
|
|
judgeResult = "Good";
|
|
ScoreManager.Instance.countGood += 1;
|
|
if (noteData != null) noteData.judgeOffsetMs = rawOffsetMs;
|
|
}
|
|
else
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Miss");
|
|
judgeResult = "Miss";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// fallback timing
|
|
if (timeDifference <= 0.08f)
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Perfect");
|
|
judgeResult = "Perfect";
|
|
}
|
|
else if (timeDifference <= 0.15f)
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Great");
|
|
judgeResult = "Great";
|
|
}
|
|
else
|
|
{
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress}: Miss");
|
|
judgeResult = "Miss";
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(judgeResult))
|
|
{
|
|
InputManager.Instance?.ShowJudgeResult(TrackIndex, judgeResult);
|
|
JudgeSoundManager.Instance?.PlayJudgeSound(judgeResult);
|
|
teamUIController.Instance?.OnJudgeResult(judgeResult);
|
|
Animation_GenerateJudgementSituationPrefab.Instance?.SpawnJudgePrefab(noteColor, judgeResult);
|
|
|
|
try
|
|
{
|
|
var ally = GetAllyForTrackCached(TrackIndex);
|
|
if (ally != null)
|
|
{
|
|
int added = ally.AddScoreForJudge(judgeResult);
|
|
float efficiency = ally.scoreEfficiency;
|
|
ScoreManager.Instance?.AddPmScoreForTrack(TrackIndex, added, efficiency);
|
|
}
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning($"[Note] Failed to add per-track score: {ex}");
|
|
}
|
|
|
|
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { }
|
|
}
|
|
|
|
Judge();
|
|
}
|
|
|
|
public bool IsJudged()
|
|
{
|
|
return isJudged;
|
|
}
|
|
|
|
public void Judge()
|
|
{
|
|
if (isJudged)
|
|
return;
|
|
isJudged = true;
|
|
|
|
if (controller != null)
|
|
{
|
|
controller.StopMovement();
|
|
controller.PlayHitEffect();
|
|
}
|
|
ReturnToPool();
|
|
if (anim != null)
|
|
{
|
|
anim.PlayDestroyAnimation(noteColor);
|
|
}
|
|
|
|
}
|
|
|
|
public void JudgeMiss()
|
|
{
|
|
// idempotent: this can be called from multiple paths
|
|
if (isJudged) return;
|
|
|
|
isJudged = true;
|
|
ScoreManager.Instance.countMiss += 1;
|
|
if (GameConfig.verboseLogs) Debug.Log($"{keyToPress} Miss");
|
|
|
|
InputManager.Instance?.ShowJudgeResult(TrackIndex, "Miss");
|
|
JudgeSoundManager.Instance?.PlayJudgeSound("Miss");
|
|
teamUIController.Instance?.OnJudgeResult("Miss");
|
|
Animation_GenerateJudgementSituationPrefab.Instance?.SpawnJudgePrefab(noteColor, "Miss");
|
|
|
|
try
|
|
{
|
|
var ally = GetAllyForTrackCached(TrackIndex);
|
|
if (ally != null)
|
|
{
|
|
int added = ally.AddScoreForJudge("Miss");
|
|
float efficiency = ally.scoreEfficiency;
|
|
ScoreManager.Instance?.AddPmScoreForTrack(TrackIndex, added, efficiency);
|
|
}
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning($"[Note] Failed to add per-track score for Miss: {ex}");
|
|
}
|
|
|
|
try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, "Miss", SkillDefinition.NoteTypeTrigger.Tap); } catch { }
|
|
|
|
ReturnToPool();
|
|
}
|
|
|
|
private void ReturnToPool()
|
|
{
|
|
InputManager.OnKeyPressed -= HandlePress;
|
|
if (controller != null)
|
|
{
|
|
controller.ResetState();
|
|
}
|
|
gameObject.SetActive(false);
|
|
NotePool.Instance.ReturnNote(gameObject, noteColor);
|
|
}
|
|
|
|
public int GetTrackIndex()
|
|
{
|
|
return TrackIndex;
|
|
}
|
|
|
|
public KeyCode GetKey()
|
|
{
|
|
return keyToPress;
|
|
}
|
|
|
|
/// <summary>
|
|
/// �� Controller ֪ͨ Note �Ƿ�����ж���
|
|
/// </summary>
|
|
public void SetJudgeZone(bool inZone)
|
|
{
|
|
// leaving judge zone without being judged -> Miss
|
|
if (!inZone)
|
|
{
|
|
// JudgeMiss already handles UI/sound and prevents double execution.
|
|
JudgeMiss();
|
|
}
|
|
}
|
|
} |