1.新增了SplineAnchor的旋转跟随2.修复了IInteraction交互物体的乱序错误
This commit is contained in:
@@ -19,46 +19,96 @@ namespace Demo.Game
|
||||
item.SetupDuration(new(VisibleDuration.x, VisibleDuration.y), GetTimelineItemColor());
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public enum DurationStats
|
||||
{
|
||||
BeforeBegin = 0,
|
||||
BeforeEnd,
|
||||
After,
|
||||
Judgement
|
||||
}
|
||||
|
||||
public const float IdentifiableJudgementTerminal = 0.16f;
|
||||
|
||||
[Content, SerializeField, Header("Cache")]
|
||||
public float MyCacheUpdateTick = 0;
|
||||
|
||||
[Header(nameof(VisibleDuration))]
|
||||
[Content, SerializeField] private Vector2 VisibleDuration;
|
||||
public static float DefaultVisibleLength = IdentifiableJudgementTerminal * 15;
|
||||
[Content, SerializeField] public UnityEvent VisibleDurationBeforeEvent = new(),
|
||||
VisibleDurationBeginEvent = new(), VisibleDurationEndEvent = new();
|
||||
[Content, SerializeField] private DurationStats VisibleDurationStats = default;
|
||||
|
||||
[Header(nameof(InteractiveDuration))]
|
||||
[Content, SerializeField] private Vector2 InteractiveDuration;
|
||||
public static float DefaultInteractiveLength = IdentifiableJudgementTerminal * 9;
|
||||
[Content, SerializeField] public UnityEvent InteractiveDurationBeforeEvent = new(),
|
||||
InteractiveDurationBeginEvent = new(), InteractiveDurationEndEvent = new();
|
||||
[Content, SerializeField] private DurationStats InteractiveDurationStats = default;
|
||||
|
||||
[Header(nameof(InteractableScoreInterval))]
|
||||
[Content, SerializeField] private Vector2 InteractableScoreInterval;
|
||||
public static float DefaultInteractableScoreIntervalLength = IdentifiableJudgementTerminal * 6;
|
||||
[Content, SerializeField] public UnityEvent InteractableScoreIntervalBeforeEvent = new(),
|
||||
InteractableScoreIntervalBeginEvent = new(), InteractableScoreIntervalEndEvent = new();
|
||||
[Content, SerializeField] private DurationStats InteractableScoreIntervalStats = default;
|
||||
|
||||
[Header(nameof(InteractableIntervalThatCanScoreBest))]
|
||||
[Content, SerializeField] private Vector2 InteractableIntervalThatCanScoreBest;
|
||||
public static float DefaultInteractableIntervalLengthThatCanScoreBest = IdentifiableJudgementTerminal * 3;
|
||||
[Content, SerializeField] public UnityEvent InteractableIntervalThatCanScoreBestBeforeEvent = new(),
|
||||
InteractableIntervalThatCanScoreBestBeginEvent = new(), InteractableIntervalThatCanScoreBestEndEvent = new();
|
||||
[Content, SerializeField] private DurationStats InteractableIntervalThatCanScoreBestStats = default;
|
||||
|
||||
[Flags,Serializable]
|
||||
public enum UpdatePhaseComponent
|
||||
{
|
||||
OutsideVisibleDuration = 0b00000000,
|
||||
//
|
||||
InsideVisibleDuration = 0b00000001,
|
||||
InsideInteractiveDuration = 0b00000010,
|
||||
InsideInteractableScoreInterval = 0b00000100,
|
||||
InsideInteractableIntervalThatCanScoreBest = 0b00001000,
|
||||
//
|
||||
EnterVisibleDuration = 0b00010000,
|
||||
EnterInteractiveDuration = 0b00100000,
|
||||
EnterInteractableScoreInterval = 0b01000000,
|
||||
EnterInteractableIntervalThatCanScoreBest = 0b10000000,
|
||||
}
|
||||
|
||||
[Flags, Serializable]
|
||||
public enum UpdatePhase
|
||||
{
|
||||
// 进入可视区间之前
|
||||
BeforeVisibleDuration
|
||||
= UpdatePhaseComponent.OutsideVisibleDuration,
|
||||
// 进入不可判定但可视的3级判定区间
|
||||
EnterVisibleDuration
|
||||
= UpdatePhaseComponent.InsideVisibleDuration | UpdatePhaseComponent.EnterVisibleDuration,
|
||||
// 进入可判定为失误的2级判定区间
|
||||
EnterInteractiveDuration
|
||||
= UpdatePhaseComponent.InsideInteractiveDuration | UpdatePhaseComponent.EnterInteractiveDuration | UpdatePhase.EnterVisibleDuration,
|
||||
// 进入可得分的1级判定区间
|
||||
EnterInteractableScoreInterval
|
||||
= UpdatePhaseComponent.InsideInteractableScoreInterval | UpdatePhaseComponent.EnterInteractableScoreInterval | UpdatePhase.EnterInteractiveDuration,
|
||||
// 进入可得满分的0级判定区间
|
||||
EnterInteractableIntervalThatCanScoreBest
|
||||
= UpdatePhaseComponent.InsideInteractableIntervalThatCanScoreBest| UpdatePhaseComponent.EnterInteractableIntervalThatCanScoreBest
|
||||
| UpdatePhase.EnterInteractableScoreInterval,
|
||||
// 退出0级判定区间
|
||||
AfterInteractableIntervalThatCanScoreBest
|
||||
= UpdatePhase.EnterInteractableIntervalThatCanScoreBest&(~UpdatePhaseComponent.InsideInteractableIntervalThatCanScoreBest),
|
||||
// 退出1级判定区间
|
||||
AfterInteractableScoreInterval
|
||||
= UpdatePhase.AfterInteractableIntervalThatCanScoreBest & (~UpdatePhaseComponent.InsideInteractableScoreInterval),
|
||||
// 退出2级判断区间
|
||||
AfterInteractiveDuration
|
||||
= UpdatePhase.AfterInteractableScoreInterval & (~UpdatePhaseComponent.InsideInteractiveDuration),
|
||||
// 退出3级判断区间, 已不可视
|
||||
AfterVisibleDuration
|
||||
= UpdatePhase.AfterInteractiveDuration & (~UpdatePhaseComponent.InsideVisibleDuration)
|
||||
}
|
||||
|
||||
public enum JudgementLevel
|
||||
{
|
||||
None = -2,//No Judge
|
||||
Default = -1,
|
||||
BestLevel = 0,//Level0
|
||||
ScoreLevel = 1,//Level1
|
||||
Bad = 128,
|
||||
}
|
||||
|
||||
[Header("Judgement")]
|
||||
[Content, SerializeField] private JudgementLevel MyJudgementLevel = JudgementLevel.None;
|
||||
[Content, SerializeField] private UpdatePhase MyUpdatePhase = default;
|
||||
[Content, SerializeField] private float BestJudgementTimePoint = -1;
|
||||
[Content, SerializeField] public UnityEvent<JudgementLevel> JudgementEvent = new();
|
||||
|
||||
@@ -67,14 +117,14 @@ namespace Demo.Game
|
||||
return BestJudgementTimePoint;
|
||||
}
|
||||
|
||||
public bool IsInInteractiveDuration()
|
||||
{
|
||||
return InteractiveDurationStats == DurationStats.BeforeEnd;
|
||||
}
|
||||
public bool IsInInteractiveDuration(float time)
|
||||
{
|
||||
return time > InteractiveDuration.x && time < InteractiveDuration.y;
|
||||
}
|
||||
public bool IsInInteractiveDuration()
|
||||
{
|
||||
return IsInInteractiveDuration(MyCacheUpdateTick);
|
||||
}
|
||||
|
||||
public const int JudgementLevelCount = 3;
|
||||
|
||||
@@ -105,92 +155,126 @@ namespace Demo.Game
|
||||
{
|
||||
if (level == JudgementLevel.None)
|
||||
return;
|
||||
// 进入已判定状态
|
||||
MyJudgementLevel = level;
|
||||
JudgementEvent.Invoke(level);
|
||||
VisibleDurationStats = DurationStats.Judgement;
|
||||
VisibleDurationEndEvent.Invoke();
|
||||
InteractiveDurationStats = DurationStats.Judgement;
|
||||
InteractableScoreIntervalStats = DurationStats.Judgement;
|
||||
InteractableIntervalThatCanScoreBestStats = DurationStats.Judgement;
|
||||
InteractiveDurationEndEvent.Invoke();
|
||||
InteractableScoreIntervalEndEvent.Invoke();
|
||||
InteractableIntervalThatCanScoreBestEndEvent.Invoke();
|
||||
}
|
||||
|
||||
private static DurationStats UpdateDurationStats(float begin, UnityEvent beforeEvent, UnityEvent beginEvent, float end, UnityEvent endEvent,
|
||||
float current, DurationStats currentStats)
|
||||
{
|
||||
if (currentStats == DurationStats.After)
|
||||
return DurationStats.After;
|
||||
else if (current < begin)
|
||||
// 触发还未触发的退出事件
|
||||
{
|
||||
if (currentStats != DurationStats.BeforeBegin)
|
||||
beforeEvent.Invoke();
|
||||
return DurationStats.BeforeBegin;
|
||||
if (((int)MyUpdatePhase & (int)UpdatePhaseComponent.EnterInteractableIntervalThatCanScoreBest) != 0)
|
||||
{
|
||||
InteractableIntervalThatCanScoreBestEndEvent.Invoke();
|
||||
}
|
||||
if (((int)MyUpdatePhase & (int)UpdatePhaseComponent.EnterInteractableScoreInterval) != 0)
|
||||
{
|
||||
InteractableScoreIntervalEndEvent.Invoke();
|
||||
}
|
||||
if (((int)MyUpdatePhase & (int)UpdatePhaseComponent.EnterInteractiveDuration) != 0)
|
||||
{
|
||||
InteractiveDurationEndEvent.Invoke();
|
||||
}
|
||||
if (((int)MyUpdatePhase & (int)UpdatePhaseComponent.EnterVisibleDuration) != 0)
|
||||
{
|
||||
VisibleDurationEndEvent.Invoke();
|
||||
}
|
||||
}
|
||||
else if (current < end)
|
||||
{
|
||||
if (currentStats == DurationStats.BeforeBegin)
|
||||
beginEvent.Invoke();
|
||||
return DurationStats.BeforeEnd;
|
||||
}
|
||||
else if (currentStats == DurationStats.BeforeEnd)
|
||||
{
|
||||
endEvent.Invoke();
|
||||
}
|
||||
return DurationStats.After;
|
||||
}
|
||||
|
||||
public enum JudgementLevel
|
||||
{
|
||||
None = -2,//No Judge
|
||||
Default = -1,
|
||||
BestLevel = 0,//Level0
|
||||
ScoreLevel = 1,//Level1
|
||||
Bad = 128,
|
||||
}
|
||||
|
||||
public abstract JudgementLevel JudgementBehaviour(float timePoint);
|
||||
|
||||
#region Update Judgement Stats
|
||||
|
||||
private void DoUpdateJudgementStats(float currentTime)
|
||||
{
|
||||
// 可见区间
|
||||
VisibleDurationStats = UpdateDurationStats(VisibleDuration.x, VisibleDurationBeforeEvent,
|
||||
VisibleDurationBeginEvent, VisibleDuration.y, VisibleDurationEndEvent,
|
||||
currentTime, VisibleDurationStats);
|
||||
if (VisibleDurationStats != DurationStats.BeforeEnd)
|
||||
return;
|
||||
// 可判定区间
|
||||
InteractiveDurationStats = UpdateDurationStats(InteractiveDuration.x, InteractiveDurationBeforeEvent,
|
||||
InteractiveDurationBeginEvent, InteractiveDuration.y, InteractiveDurationEndEvent,
|
||||
currentTime, InteractiveDurationStats);
|
||||
if (InteractiveDurationStats != DurationStats.BeforeEnd)
|
||||
return;
|
||||
// 1级判定区间
|
||||
InteractableScoreIntervalStats = UpdateDurationStats(InteractableScoreInterval.x, InteractableScoreIntervalBeforeEvent,
|
||||
InteractableScoreIntervalBeginEvent, InteractableScoreInterval.y, InteractableScoreIntervalEndEvent,
|
||||
currentTime, InteractableScoreIntervalStats);
|
||||
if (InteractableScoreIntervalStats != DurationStats.BeforeEnd)
|
||||
return;
|
||||
// 0级判定区间
|
||||
InteractableIntervalThatCanScoreBestStats = UpdateDurationStats(InteractableIntervalThatCanScoreBest.x, InteractableIntervalThatCanScoreBestBeforeEvent,
|
||||
InteractableIntervalThatCanScoreBestBeginEvent, InteractableIntervalThatCanScoreBest.y, InteractableIntervalThatCanScoreBestEndEvent,
|
||||
currentTime, InteractableIntervalThatCanScoreBestStats);
|
||||
// 重置
|
||||
if (MyCacheUpdateTick > currentTime)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.BeforeVisibleDuration;
|
||||
VisibleDurationBeforeEvent.Invoke();
|
||||
InteractiveDurationBeforeEvent.Invoke();
|
||||
InteractableScoreIntervalBeforeEvent.Invoke();
|
||||
InteractableIntervalThatCanScoreBestBeforeEvent.Invoke();
|
||||
MyJudgementLevel = JudgementLevel.None;
|
||||
}
|
||||
// 状态更新
|
||||
{
|
||||
// 在当前区间进行判断, 当前时间落入下一个区间时, 就进入下一个区间
|
||||
switch (MyUpdatePhase)
|
||||
{
|
||||
case UpdatePhase.BeforeVisibleDuration:
|
||||
if (currentTime > VisibleDuration.x)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.EnterVisibleDuration;
|
||||
VisibleDurationBeginEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
case UpdatePhase.EnterVisibleDuration:
|
||||
if (currentTime > InteractiveDuration.x)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.EnterInteractiveDuration;
|
||||
InteractiveDurationBeginEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
case UpdatePhase.EnterInteractiveDuration:
|
||||
if (currentTime > InteractableScoreInterval.x)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.EnterInteractableScoreInterval;
|
||||
InteractableScoreIntervalBeginEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
case UpdatePhase.EnterInteractableScoreInterval:
|
||||
if (currentTime > InteractableIntervalThatCanScoreBest.x)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.EnterInteractableIntervalThatCanScoreBest;
|
||||
InteractableIntervalThatCanScoreBestBeginEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
// ---------------------------------------------------------
|
||||
case UpdatePhase.EnterInteractableIntervalThatCanScoreBest:
|
||||
if (currentTime > InteractableIntervalThatCanScoreBest.y)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.AfterInteractableIntervalThatCanScoreBest;
|
||||
InteractableIntervalThatCanScoreBestEndEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
case UpdatePhase.AfterInteractableIntervalThatCanScoreBest:
|
||||
if (currentTime > InteractableScoreInterval.y)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.AfterInteractableScoreInterval;
|
||||
InteractableScoreIntervalEndEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
case UpdatePhase.AfterInteractableScoreInterval:
|
||||
if (currentTime > InteractiveDuration.y)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.AfterInteractiveDuration;
|
||||
InteractiveDurationEndEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
case UpdatePhase.AfterInteractiveDuration:
|
||||
if (currentTime > VisibleDuration.y)
|
||||
{
|
||||
MyUpdatePhase = UpdatePhase.AfterVisibleDuration;
|
||||
VisibleDurationEndEvent.Invoke();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 记录
|
||||
MyCacheUpdateTick = currentTime;
|
||||
}
|
||||
|
||||
public override void ResetEnterGameStatus()
|
||||
{
|
||||
base.ResetEnterGameStatus();
|
||||
DoUpdateJudgementStats(Mathf.NegativeInfinity);
|
||||
}
|
||||
#endregion
|
||||
|
||||
protected override void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
|
||||
{
|
||||
base.UpdateTicks(currentTime, deltaTime, tickType);
|
||||
// 预判断
|
||||
if (VisibleDurationStats == DurationStats.Judgement)
|
||||
return;
|
||||
// 检定
|
||||
InvokeJudgement(JudgementBehaviour(currentTime));
|
||||
if (MyJudgementLevel == JudgementLevel.None)
|
||||
{
|
||||
InvokeJudgement(JudgementBehaviour(currentTime));
|
||||
}
|
||||
// 更新状态
|
||||
DoUpdateJudgementStats(currentTime);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user