353 lines
15 KiB
C#
353 lines
15 KiB
C#
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using Convention;
|
|||
|
|
using Demo.Editor.UI;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.Events;
|
|||
|
|
|
|||
|
|
namespace Demo.Game
|
|||
|
|
{
|
|||
|
|
public interface IHookInteraction
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public abstract class IInteraction : TimelineScriptObject
|
|||
|
|
{
|
|||
|
|
protected override void SetupTimelineItem(TimelineItem item)
|
|||
|
|
{
|
|||
|
|
item.SetupDuration(new(VisibleDuration.x, VisibleDuration.y), GetTimelineItemColor());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public enum DurationStats
|
|||
|
|
{
|
|||
|
|
BeforeBegin = 0,
|
|||
|
|
BeforeEnd,
|
|||
|
|
After,
|
|||
|
|
Judgement
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Header(nameof(VisibleDuration))]
|
|||
|
|
[Content, SerializeField] private Vector2 VisibleDuration;
|
|||
|
|
[Content, SerializeField] public UnityEvent VisibleDurationBeginEvent = new(), VisibleDurationEndEvent = new();
|
|||
|
|
[Content, SerializeField] private DurationStats VisibleDurationStats = default;
|
|||
|
|
|
|||
|
|
[Header(nameof(InteractiveDuration))]
|
|||
|
|
[Content, SerializeField] private Vector2 InteractiveDuration;
|
|||
|
|
[Content, SerializeField] public UnityEvent InteractiveDurationBeginEvent = new(), InteractiveDurationEndEvent = new();
|
|||
|
|
[Content, SerializeField] private DurationStats InteractiveDurationStats = default;
|
|||
|
|
|
|||
|
|
[Header(nameof(InteractableScoreInterval))]
|
|||
|
|
[Content, SerializeField] private Vector2 InteractableScoreInterval;
|
|||
|
|
[Content, SerializeField] public UnityEvent InteractableScoreIntervalBeginEvent = new(), InteractableScoreIntervalEndEvent = new();
|
|||
|
|
[Content, SerializeField] private DurationStats InteractableScoreIntervalStats = default;
|
|||
|
|
|
|||
|
|
[Header(nameof(InteractableIntervalThatCanScoreBest))]
|
|||
|
|
[Content, SerializeField] private Vector2 InteractableIntervalThatCanScoreBest;
|
|||
|
|
[Content, SerializeField] public UnityEvent InteractableIntervalThatCanScoreBestBeginEvent = new(), InteractableIntervalThatCanScoreBestEndEvent = new();
|
|||
|
|
[Content, SerializeField] private DurationStats InteractableIntervalThatCanScoreBestStats = default;
|
|||
|
|
|
|||
|
|
[Header("Judgement")]
|
|||
|
|
[Content, SerializeField] private float BestJudgementTimePoint = -1;
|
|||
|
|
[Content, SerializeField] public UnityEvent<int> JudgementEvent = new();
|
|||
|
|
|
|||
|
|
public float GetBestJudgementTimePoint()
|
|||
|
|
{
|
|||
|
|
return BestJudgementTimePoint;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public bool IsInInteractiveDuration()
|
|||
|
|
{
|
|||
|
|
return InteractiveDurationStats == DurationStats.BeforeEnd;
|
|||
|
|
}
|
|||
|
|
public bool IsInInteractiveDuration(float time)
|
|||
|
|
{
|
|||
|
|
return time > InteractiveDuration.x && time < InteractiveDuration.y;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public const int JudgementLevelCount = 3;
|
|||
|
|
|
|||
|
|
public override IEnumerator LoadScript(string script)
|
|||
|
|
{
|
|||
|
|
yield return base.LoadScript(script);
|
|||
|
|
if (BestJudgementTimePoint < 0)
|
|||
|
|
{
|
|||
|
|
BestJudgementTimePoint = Mathf.Lerp(InteractableIntervalThatCanScoreBest.x, InteractableIntervalThatCanScoreBest.y, 0.5f);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override IEnumerator UnloadScript()
|
|||
|
|
{
|
|||
|
|
yield return base.UnloadScript();
|
|||
|
|
VisibleDurationBeginEvent = new();
|
|||
|
|
VisibleDurationEndEvent = new();
|
|||
|
|
InteractiveDurationBeginEvent = new();
|
|||
|
|
InteractiveDurationEndEvent = new();
|
|||
|
|
InteractableScoreIntervalBeginEvent = new();
|
|||
|
|
InteractableScoreIntervalEndEvent = new();
|
|||
|
|
InteractableIntervalThatCanScoreBestBeginEvent = new();
|
|||
|
|
InteractableIntervalThatCanScoreBestEndEvent = new();
|
|||
|
|
BestJudgementTimePoint = -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void InvokeJudgement()
|
|||
|
|
{
|
|||
|
|
int judgeStats = JudgementLevelCount;
|
|||
|
|
if (InteractiveDurationStats == DurationStats.BeforeEnd)
|
|||
|
|
{
|
|||
|
|
judgeStats--;
|
|||
|
|
if (InteractableScoreIntervalStats == DurationStats.BeforeEnd)
|
|||
|
|
{
|
|||
|
|
judgeStats--;
|
|||
|
|
if (InteractableIntervalThatCanScoreBestStats == DurationStats.BeforeEnd)
|
|||
|
|
{
|
|||
|
|
judgeStats--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (judgeStats == JudgementLevelCount)
|
|||
|
|
return;
|
|||
|
|
JudgementEvent.Invoke(judgeStats);
|
|||
|
|
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 beginEvent, float end, UnityEvent endEvent,
|
|||
|
|
float current, DurationStats currentStats)
|
|||
|
|
{
|
|||
|
|
if (currentStats == DurationStats.After)
|
|||
|
|
return DurationStats.After;
|
|||
|
|
else if (current < begin)
|
|||
|
|
return DurationStats.BeforeBegin;
|
|||
|
|
else if (current < end)
|
|||
|
|
{
|
|||
|
|
if (currentStats == DurationStats.BeforeBegin)
|
|||
|
|
beginEvent.Invoke();
|
|||
|
|
return DurationStats.BeforeEnd;
|
|||
|
|
}
|
|||
|
|
else if (currentStats == DurationStats.BeforeEnd)
|
|||
|
|
{
|
|||
|
|
endEvent.Invoke();
|
|||
|
|
}
|
|||
|
|
return DurationStats.After;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public abstract bool JudgementBehaviour(float timePoint);
|
|||
|
|
|
|||
|
|
protected override void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
|
|||
|
|
{
|
|||
|
|
if (tickType == TickType.Start || tickType == TickType.Reset)
|
|||
|
|
{
|
|||
|
|
VisibleDurationStats = DurationStats.BeforeBegin;
|
|||
|
|
InteractiveDurationStats = DurationStats.BeforeBegin;
|
|||
|
|
InteractableScoreIntervalStats = DurationStats.BeforeBegin;
|
|||
|
|
InteractableIntervalThatCanScoreBestStats = DurationStats.BeforeBegin;
|
|||
|
|
}
|
|||
|
|
//预判断
|
|||
|
|
if (VisibleDurationStats == DurationStats.Judgement)
|
|||
|
|
return;
|
|||
|
|
//检定
|
|||
|
|
if (JudgementBehaviour(currentTime))
|
|||
|
|
InvokeJudgement();
|
|||
|
|
if (tickType == TickType.Update)
|
|||
|
|
{
|
|||
|
|
// 可见区间
|
|||
|
|
VisibleDurationStats = UpdateDurationStats(VisibleDuration.x, VisibleDurationBeginEvent, VisibleDuration.y, VisibleDurationEndEvent,
|
|||
|
|
currentTime, VisibleDurationStats);
|
|||
|
|
if (VisibleDurationStats != DurationStats.BeforeEnd)
|
|||
|
|
return;
|
|||
|
|
// 可判定区间
|
|||
|
|
InteractiveDurationStats = UpdateDurationStats(InteractiveDuration.x, InteractiveDurationBeginEvent, InteractiveDuration.y, InteractiveDurationEndEvent,
|
|||
|
|
currentTime, InteractiveDurationStats);
|
|||
|
|
if (InteractiveDurationStats != DurationStats.BeforeEnd)
|
|||
|
|
return;
|
|||
|
|
// 1级判定区间
|
|||
|
|
InteractableScoreIntervalStats = UpdateDurationStats(InteractableScoreInterval.x, InteractableScoreIntervalBeginEvent, InteractableScoreInterval.y, InteractableScoreIntervalEndEvent,
|
|||
|
|
currentTime, InteractableScoreIntervalStats);
|
|||
|
|
if (InteractableScoreIntervalStats != DurationStats.BeforeEnd)
|
|||
|
|
return;
|
|||
|
|
// 0级判定区间
|
|||
|
|
InteractableIntervalThatCanScoreBestStats = UpdateDurationStats(InteractableIntervalThatCanScoreBest.x, InteractableIntervalThatCanScoreBestBeginEvent, InteractableIntervalThatCanScoreBest.y, InteractableIntervalThatCanScoreBestEndEvent,
|
|||
|
|
currentTime, InteractableIntervalThatCanScoreBestStats);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通过传递对称区间进行初始化
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="bestJudgementTimePoint">最佳判定点</param>
|
|||
|
|
/// <param name="interactableIntervalThatCanScoreBest">区间时长,最终结果为
|
|||
|
|
/// (bestJudgementTimePoint-interactableIntervalThatCanScoreBest/2,bestJudgementTimePoint+interactableIntervalThatCanScoreBest/2)</param>
|
|||
|
|
/// <param name="interactableScoreInterval">区间时长,最终结果为
|
|||
|
|
/// (bestJudgementTimePoint-interactableScoreInterval/2,bestJudgementTimePoint+interactableScoreInterval/2)</param>
|
|||
|
|
/// <param name="interactiveDuration">区间时长,最终结果为
|
|||
|
|
/// (bestJudgementTimePoint-interactiveDuration/2,bestJudgementTimePoint+interactiveDuration/2)</param>
|
|||
|
|
/// <param name="visibleDuration">区间时长,最终结果为
|
|||
|
|
/// (bestJudgementTimePoint-visibleDuration/2,bestJudgementTimePoint+visibleDuration/2)</param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
通过传递对称区间进行初始化
|
|||
|
|
</summary>
|
|||
|
|
<param name=""bestJudgementTimePoint"">最佳判定点</param>
|
|||
|
|
<param name=""interactableIntervalThatCanScoreBest"">区间时长,最终结果为
|
|||
|
|
(bestJudgementTimePoint-interactableIntervalThatCanScoreBest/2,bestJudgementTimePoint+interactableIntervalThatCanScoreBest/2)</param>
|
|||
|
|
<param name=""interactableScoreInterval"">区间时长,最终结果为
|
|||
|
|
(bestJudgementTimePoint-interactableScoreInterval/2,bestJudgementTimePoint+interactableScoreInterval/2)</param>
|
|||
|
|
<param name=""interactiveDuration"">区间时长,最终结果为
|
|||
|
|
(bestJudgementTimePoint-interactiveDuration/2,bestJudgementTimePoint+interactiveDuration/2)</param>
|
|||
|
|
<param name=""visibleDuration"">区间时长,最终结果为
|
|||
|
|
(bestJudgementTimePoint-visibleDuration/2,bestJudgementTimePoint+visibleDuration/2)</param>
|
|||
|
|
")]
|
|||
|
|
public void SetupJudgementLevels(
|
|||
|
|
string bestJudgementTimePoint,
|
|||
|
|
string interactableIntervalThatCanScoreBest,
|
|||
|
|
string interactableScoreInterval,
|
|||
|
|
string interactiveDuration,
|
|||
|
|
string visibleDuration)
|
|||
|
|
{
|
|||
|
|
var bestJudgementTimePointValue = Parse(bestJudgementTimePoint);
|
|||
|
|
// InteractableIntervalThatCanScoreBest
|
|||
|
|
var interactableIntervalThatCanScoreBestValue = Parse(interactableIntervalThatCanScoreBest) * 0.5f;
|
|||
|
|
InteractableIntervalThatCanScoreBest = new(bestJudgementTimePointValue - interactableIntervalThatCanScoreBestValue,
|
|||
|
|
bestJudgementTimePointValue + interactableIntervalThatCanScoreBestValue);
|
|||
|
|
|
|||
|
|
// InteractableScoreInterval
|
|||
|
|
var interactableScoreIntervalValue = Parse(interactableScoreInterval) * 0.5f;
|
|||
|
|
InteractableScoreInterval = new(bestJudgementTimePointValue - interactableScoreIntervalValue,
|
|||
|
|
bestJudgementTimePointValue + interactableScoreIntervalValue);
|
|||
|
|
|
|||
|
|
// InteractiveDuration
|
|||
|
|
var interactiveDurationValue = Parse(interactiveDuration) * 0.5f;
|
|||
|
|
InteractiveDuration = new(bestJudgementTimePointValue - interactiveDurationValue,
|
|||
|
|
bestJudgementTimePointValue + interactiveDurationValue);
|
|||
|
|
|
|||
|
|
// InteractableScoreInterval
|
|||
|
|
var visibleDurationValue = Parse(visibleDuration) * 0.5f;
|
|||
|
|
VisibleDuration = new(bestJudgementTimePointValue - visibleDurationValue,
|
|||
|
|
bestJudgementTimePointValue + visibleDurationValue);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置可见区间(显现但不可判定,3级判定区间)开始时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置可见区间(显现但不可判定,3级判定区间)开始时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetVisibleDurationBegin(string value)
|
|||
|
|
{
|
|||
|
|
VisibleDuration.x = Parse(value);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置可见区间(显现但不可判定,3级判定区间)结束时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置可见区间(显现但不可判定,3级判定区间)结束时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetVisibleDurationEnd(string value)
|
|||
|
|
{
|
|||
|
|
VisibleDuration.y = Parse(value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置2级判定区间(可判定但错误的)开始时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置2级判定区间(可判定但错误的)开始时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetInteractiveDurationBegin(string value)
|
|||
|
|
{
|
|||
|
|
InteractiveDuration.x = Parse(value);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置2级判定区间(可判定但错误的)结束时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置2级判定区间(可判定但错误的)结束时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetInteractiveDurationEnd(string value)
|
|||
|
|
{
|
|||
|
|
InteractiveDuration.y = Parse(value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置1级判定区间(可判定的)开始时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置1级判定区间(可判定的)开始时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetInteractableScoreIntervalBegin(string value)
|
|||
|
|
{
|
|||
|
|
InteractableScoreInterval.x = Parse(value);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置1级判定区间(可判定的)结束时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置1级判定区间(可判定的)结束时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetInteractableScoreIntervalEnd(string value)
|
|||
|
|
{
|
|||
|
|
InteractableScoreInterval.y = Parse(value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置0级判定区间(最佳判定)开始时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置0级判定区间(最佳判定)开始时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetInteractableIntervalThatCanScoreBestBegin(string value)
|
|||
|
|
{
|
|||
|
|
InteractableIntervalThatCanScoreBest.x = Parse(value);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置0级判定区间(最佳判定)结束时间
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="value"></param>
|
|||
|
|
[ScriptableCall(@"
|
|||
|
|
<summary>
|
|||
|
|
设置0级判定区间(最佳判定)结束时间
|
|||
|
|
</summary>
|
|||
|
|
<param name=""value""></param>
|
|||
|
|
")]
|
|||
|
|
public void SetInteractableIntervalThatCanScoreBestEnd(string value)
|
|||
|
|
{
|
|||
|
|
InteractableIntervalThatCanScoreBest.y = Parse(value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|