159 lines
6.3 KiB
C#
159 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Dreamteck.Splines;
|
|
using Ichni.RhythmGame.Beatmap;
|
|
using Lean.Pool;
|
|
using Unity.VisualScripting;
|
|
using UnityEngine;
|
|
|
|
namespace Ichni.RhythmGame
|
|
{
|
|
public class Flick : NoteBase
|
|
{
|
|
#region [特有属性字段] Special Fields
|
|
public NoteJudgeType preJudgeType;
|
|
public List<Vector2> availableFlickDirections;
|
|
public float flickBuffer = 0.5f;
|
|
#endregion
|
|
|
|
#region [生成与初始化] Generation & Initialization
|
|
public static Flick GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
|
|
GameElement parentElement, float exactJudgeTime, List<Vector2> directions)
|
|
{
|
|
Flick flick = LeanPool.Spawn(GameManager.Instance.basePrefabs.flickNote, parentElement.transform).GetComponent<Flick>();
|
|
|
|
flick.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
|
|
flick.exactJudgeTime = exactJudgeTime;
|
|
flick.judgeIntervals = NoteJudgeIntervals.FlickDefault;
|
|
|
|
// 注意这里暂未赋值传入的 directions, 请根据情况补充。
|
|
if (parentElement.TryGetComponent(out Track track) && track.trackTimeSubmodule != null)
|
|
{
|
|
flick.track = track;
|
|
flick.trackPositioner.enabled = true;
|
|
flick.trackPositioner.spline = track.trackPathSubmodule.path;
|
|
flick.isOnTrack = true;
|
|
flick.UpdateNoteInTrack(CoreServices.TimeProvider.SongTime);
|
|
}
|
|
else
|
|
{
|
|
flick.track = null;
|
|
flick.isOnTrack = false;
|
|
}
|
|
return flick;
|
|
}
|
|
|
|
public override void SetDefaultSubmodules()
|
|
{
|
|
base.SetDefaultSubmodules();
|
|
NoteAudioSubmodule = new NoteAudioSubmodule(this, "DefaultStay");
|
|
}
|
|
#endregion
|
|
|
|
#region [主循环阶段] Main Update
|
|
public override bool ManualUpdate(float currentSongTime)
|
|
{
|
|
if (!isFirstJudged && !isDuringJudging &&
|
|
currentSongTime >= exactJudgeTime + judgeIntervals.beforeMiss.intervalStart &&
|
|
!GameManager.Instance.noteJudgeManager.checkingFlickList.Contains(this))
|
|
{
|
|
isDuringJudging = true;
|
|
GameManager.Instance.noteJudgeManager.checkingFlickList.Add(this);
|
|
}
|
|
|
|
ExecuteFinalJudge(currentSongTime);
|
|
return base.ManualUpdate(currentSongTime);
|
|
}
|
|
|
|
protected override void RemoveFromCheckingList()
|
|
{
|
|
if (GameManager.Instance.noteJudgeManager.checkingFlickList.Contains(this))
|
|
GameManager.Instance.noteJudgeManager.checkingFlickList.Remove(this);
|
|
}
|
|
#endregion
|
|
|
|
#region [核心判定逻辑] Judgement Logic
|
|
public bool CheckJudgeAvailability(InputUnitSwipe inputUnitSwipe)
|
|
{
|
|
foreach (var judgeUnit in NoteJudgeSubmodule.judgeUnitList)
|
|
{
|
|
if (!judgeUnit.CheckJudgeAvailability(inputUnitSwipe)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool CheckSwipeDirection(InputUnitSwipe inputUnitSwipe)
|
|
{
|
|
if (inputUnitSwipe.isGeneric) return true;
|
|
|
|
Camera gameCamera = GameManager.Instance.cameraManager.gameCamera.cam;
|
|
foreach (Vector2 localDir in availableFlickDirections)
|
|
{
|
|
Vector3 worldDirection = noteVisual.transform.TransformDirection(localDir.normalized);
|
|
Vector3 noteOriginWorld = noteVisual.transform.position;
|
|
Vector3 noteTargetWorld = noteOriginWorld + worldDirection;
|
|
|
|
Vector3 screenOrigin = gameCamera.WorldToScreenPoint(noteOriginWorld);
|
|
Vector3 screenTarget = gameCamera.WorldToScreenPoint(noteTargetWorld);
|
|
Vector2 noteScreenDirection = new Vector2(screenTarget.x - screenOrigin.x, screenTarget.y - screenOrigin.y).normalized;
|
|
|
|
if (noteScreenDirection.sqrMagnitude < 0.01f) continue;
|
|
|
|
float dotProduct = Vector2.Dot(inputUnitSwipe.swipeDirection, noteScreenDirection);
|
|
if (dotProduct >= flickBuffer) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override void ExecuteStartJudge(float triggerTime)
|
|
{
|
|
float timeDifference = triggerTime - exactJudgeTime;
|
|
|
|
RemoveFromCheckingList();
|
|
preJudgeType = GetStartJudgeType(timeDifference);
|
|
isFirstJudged = true;
|
|
}
|
|
|
|
public void ExecuteTapJudge(float triggerTime)
|
|
{
|
|
RemoveFromCheckingList();
|
|
NoteJudgeType startJudgeType = GetStartJudgeType(triggerTime - exactJudgeTime);
|
|
|
|
switch (startJudgeType)
|
|
{
|
|
case NoteJudgeType.Perfect: Perfect(triggerTime); GameManager.Instance.playingRecorder.resultData.Add(0); break;
|
|
case NoteJudgeType.Good: Good(triggerTime); break;
|
|
case NoteJudgeType.Bad: Bad(triggerTime); break;
|
|
case NoteJudgeType.Miss: Miss(triggerTime); break;
|
|
}
|
|
|
|
if (startJudgeType != NoteJudgeType.Miss) NoteAudioSubmodule.PlayGeneralJudgeAudios();
|
|
|
|
isFirstJudged = true;
|
|
isFinalJudged = true;
|
|
}
|
|
|
|
public void ExecuteFinalJudge(float triggerTime)
|
|
{
|
|
if (isFirstJudged && !isFinalJudged && preJudgeType != NoteJudgeType.NotJudged && triggerTime >= exactJudgeTime)
|
|
{
|
|
switch (preJudgeType)
|
|
{
|
|
case NoteJudgeType.Perfect: Perfect(triggerTime); GameManager.Instance.playingRecorder.resultData.Add(0); break;
|
|
case NoteJudgeType.Good: Good(triggerTime); break;
|
|
case NoteJudgeType.Bad: Bad(triggerTime); break;
|
|
case NoteJudgeType.Miss: Miss(triggerTime); break;
|
|
}
|
|
|
|
if (preJudgeType != NoteJudgeType.Miss) NoteAudioSubmodule.PlayGeneralJudgeAudios();
|
|
isFinalJudged = true;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region [谱面功能] Beatmap Method
|
|
#endregion
|
|
}
|
|
|
|
}
|