Signed-off-by: TRAfoer <lhf190@outlook.com>

This commit is contained in:
2025-08-09 19:13:11 +08:00
parent 8da603c702
commit 0ac0c6228d
15 changed files with 35121 additions and 2349 deletions

View File

@@ -1,11 +1,12 @@
using UnityEngine;
using System;
using System.Collections.Generic;
namespace Ichni
{
public enum AnimationCurveType //预设动画曲线类型
// 保持枚举定义不变
public enum AnimationCurveType
{
Linear = 0,
InQuad = 1,
OutQuad = 2,
@@ -37,361 +38,206 @@ namespace Ichni
InBack = 28,
OutBack = 29,
InOutBack = 30
}
public static class AnimationCurveEvaluator
{
// 预计算常量
private const float HALF_PI = Mathf.PI / 2f;
private const float DOUBLE_PI = Mathf.PI * 2f;
private const float BOUNCE_THRESHOLD1 = 1f / 2.75f;
private const float BOUNCE_THRESHOLD2 = 2f / 2.75f;
private const float BOUNCE_THRESHOLD3 = 2.5f / 2.75f;
private const float BOUNCE_DIVISOR = 2.75f;
public static float Evaluate(AnimationCurveType animationCurveType, float t)
{
t = Mathf.Clamp(t, 0, 1);
t = Mathf.Clamp01(t); // 使用Unity内置的Clamp01
switch (animationCurveType)
{
case AnimationCurveType.Linear:
return Linear(0, 1, t);
case AnimationCurveType.InQuad:
return InQuad(0, 1, t);
case AnimationCurveType.OutQuad:
return OutQuad(0, 1, t);
case AnimationCurveType.InOutQuad:
return InOutQuad(0, 1, t);
case AnimationCurveType.InCubic:
return InCubic(0, 1, t);
case AnimationCurveType.OutCubic:
return OutCubic(0, 1, t);
case AnimationCurveType.InOutCubic:
return InOutCubic(0, 1, t);
case AnimationCurveType.InQuart:
return InQuart(0, 1, t);
case AnimationCurveType.OutQuart:
return OutQuart(0, 1, t);
case AnimationCurveType.InOutQuart:
return InOutQuart(0, 1, t);
case AnimationCurveType.InQuint:
return InQuint(0, 1, t);
case AnimationCurveType.OutQuint:
return OutQuint(0, 1, t);
case AnimationCurveType.InOutQuint:
return InOutQuint(0, 1, t);
case AnimationCurveType.InSine:
return InSine(0, 1, t);
case AnimationCurveType.OutSine:
return OutSine(0, 1, t);
case AnimationCurveType.InOutSine:
return InOutSine(0, 1, t);
case AnimationCurveType.InExpo:
return InExpo(0, 1, t);
case AnimationCurveType.OutExpo:
return OutExpo(0, 1, t);
case AnimationCurveType.InOutExpo:
return InOutExpo(0, 1, t);
case AnimationCurveType.InCirc:
return InCirc(0, 1, t);
case AnimationCurveType.OutCirc:
return OutCirc(0, 1, t);
case AnimationCurveType.InOutCirc:
return InOutCirc(0, 1, t);
case AnimationCurveType.InBounce:
return InBounce(0, 1, t);
case AnimationCurveType.OutBounce:
return OutBounce(0, 1, t);
case AnimationCurveType.InOutBounce:
return InOutBounce(0, 1, t);
case AnimationCurveType.InElastic:
return InElastic(0, 1, t);
case AnimationCurveType.OutElastic:
return OutElastic(0, 1, t);
case AnimationCurveType.InOutElastic:
return InOutElastic(0, 1, t);
case AnimationCurveType.InBack:
return InBack(0, 1, t);
case AnimationCurveType.OutBack:
return OutBack(0, 1, t);
case AnimationCurveType.InOutBack:
return InOutBack(0, 1, t);
}
throw new NotImplementedException($"Animation curve type {animationCurveType} is not implemented.");
}
#region 线
private static float Linear(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return c * t / 1f + from;
}
private static float InQuad(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return c * t * t + from;
}
private static float OutQuad(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return -c * t * (t - 2f) + from;
}
private static float InOutQuad(float from, float to, float t)
{
float c = to - from;
t /= 0.5f;
if (t < 1) return c / 2f * t * t + from;
t--;
return -c / 2f * (t * (t - 2) - 1) + from;
}
private static float InCubic(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return c * t * t * t + from;
}
private static float OutCubic(float from, float to, float t)
{
float c = to - from;
t /= 1f;
t--;
return c * (t * t * t + 1) + from;
}
private static float InOutCubic(float from, float to, float t)
{
float c = to - from;
t /= 0.5f;
if (t < 1) return c / 2f * t * t * t + from;
t -= 2;
return c / 2f * (t * t * t + 2) + from;
}
private static float InQuart(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return c * t * t * t * t + from;
}
private static float OutQuart(float from, float to, float t)
{
float c = to - from;
t /= 1f;
t--;
return -c * (t * t * t * t - 1) + from;
}
private static float InOutQuart(float from, float to, float t)
{
float c = to - from;
t /= 0.5f;
if (t < 1) return c / 2f * t * t * t * t + from;
t -= 2;
return -c / 2f * (t * t * t * t - 2) + from;
}
private static float InQuint(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return c * t * t * t * t * t + from;
}
private static float OutQuint(float from, float to, float t)
{
float c = to - from;
t /= 1f;
t--;
return c * (t * t * t * t * t + 1) + from;
}
private static float InOutQuint(float from, float to, float t)
{
float c = to - from;
t /= 0.5f;
if (t < 1) return c / 2f * t * t * t * t * t + from;
t -= 2;
return c / 2f * (t * t * t * t * t + 2) + from;
}
private static float InSine(float from, float to, float t)
{
float c = to - from;
return -c * Mathf.Cos(t / 1f * (Mathf.PI / 2f)) + c + from;
}
private static float OutSine(float from, float to, float t)
{
float c = to - from;
return c * Mathf.Sin(t / 1f * (Mathf.PI / 2f)) + from;
}
private static float InOutSine(float from, float to, float t)
{
float c = to - from;
return -c / 2f * (Mathf.Cos(Mathf.PI * t / 1f) - 1) + from;
}
private static float InExpo(float from, float to, float t)
{
float c = to - from;
return c * Mathf.Pow(2, 10 * (t / 1f - 1)) + from;
}
private static float OutExpo(float from, float to, float t)
{
float c = to - from;
return c * (-Mathf.Pow(2, -10 * t / 1f) + 1) + from;
}
private static float InOutExpo(float from, float to, float t)
{
float c = to - from;
t /= 0.5f;
if (t < 1f) return c / 2f * Mathf.Pow(2, 10 * (t - 1)) + from;
t--;
return c / 2f * (-Mathf.Pow(2, -10 * t) + 2) + from;
}
private static float InCirc(float from, float to, float t)
{
float c = to - from;
t /= 1f;
return -c * (Mathf.Sqrt(1 - t * t) - 1) + from;
}
private static float OutCirc(float from, float to, float t)
{
float c = to - from;
t /= 1f;
t--;
return c * Mathf.Sqrt(1 - t * t) + from;
}
private static float InOutCirc(float from, float to, float t)
{
float c = to - from;
t /= 0.5f;
if (t < 1) return -c / 2f * (Mathf.Sqrt(1 - t * t) - 1) + from;
t -= 2;
return c / 2f * (Mathf.Sqrt(1 - t * t) + 1) + from;
}
private static float InBounce(float from, float to, float t)
{
float c = to - from;
return c - OutBounce(0f, c, 1f - t) + from; //does this work?
}
private static float OutBounce(float from, float to, float t)
{
float c = to - from;
if ((t /= 1f) < (1 / 2.75f))
{
return c * (7.5625f * t * t) + from;
}
else if (t < (2 / 2.75f))
{
return c * (7.5625f * (t -= (1.5f / 2.75f)) * t + .75f) + from;
}
else if (t < (2.5 / 2.75))
{
return c * (7.5625f * (t -= (2.25f / 2.75f)) * t + .9375f) + from;
}
else
{
return c * (7.5625f * (t -= (2.625f / 2.75f)) * t + .984375f) + from;
// 使用简化的函数调用
case AnimationCurveType.Linear: return Linear(t);
case AnimationCurveType.InQuad: return InQuad(t);
case AnimationCurveType.OutQuad: return OutQuad(t);
case AnimationCurveType.InOutQuad: return InOutQuad(t);
case AnimationCurveType.InCubic: return InCubic(t);
case AnimationCurveType.OutCubic: return OutCubic(t);
case AnimationCurveType.InOutCubic: return InOutCubic(t);
case AnimationCurveType.InQuart: return InQuart(t);
case AnimationCurveType.OutQuart: return OutQuart(t);
case AnimationCurveType.InOutQuart: return InOutQuart(t);
case AnimationCurveType.InQuint: return InQuint(t);
case AnimationCurveType.OutQuint: return OutQuint(t);
case AnimationCurveType.InOutQuint: return InOutQuint(t);
case AnimationCurveType.InSine: return InSine(t);
case AnimationCurveType.OutSine: return OutSine(t);
case AnimationCurveType.InOutSine: return InOutSine(t);
case AnimationCurveType.InExpo: return InExpo(t);
case AnimationCurveType.OutExpo: return OutExpo(t);
case AnimationCurveType.InOutExpo: return InOutExpo(t);
case AnimationCurveType.InCirc: return InCirc(t);
case AnimationCurveType.OutCirc: return OutCirc(t);
case AnimationCurveType.InOutCirc: return InOutCirc(t);
case AnimationCurveType.InBounce: return InBounce(t);
case AnimationCurveType.OutBounce: return OutBounce(t);
case AnimationCurveType.InOutBounce: return InOutBounce(t);
case AnimationCurveType.InElastic: return InElastic(t);
case AnimationCurveType.OutElastic: return OutElastic(t);
case AnimationCurveType.InOutElastic: return InOutElastic(t);
case AnimationCurveType.InBack: return InBack(t);
case AnimationCurveType.OutBack: return OutBack(t);
case AnimationCurveType.InOutBack: return InOutBack(t);
default:
throw new NotImplementedException($"Animation curve type {animationCurveType} is not implemented.");
}
}
private static float InOutBounce(float from, float to, float t)
{
float c = to - from;
if (t < 0.5f) return InBounce(0, c, t * 2f) * 0.5f + from;
return OutBounce(0, c, t * 2 - 1) * 0.5f + c * 0.5f + from;
#region
private static float Linear(float t) => t;
private static float InQuad(float t) => t * t;
private static float OutQuad(float t) => t * (2f - t);
private static float InOutQuad(float t) =>
t < 0.5f ? 2f * t * t : -1f + (4f - 2f * t) * t;
private static float InCubic(float t) => t * t * t;
private static float OutCubic(float t) =>
(--t) * t * t + 1f;
private static float InOutCubic(float t) =>
t < 0.5f ? 4f * t * t * t : (t - 1f) * (2f * t - 2f) * (2f * t - 2f) + 1f;
private static float InQuart(float t) => t * t * t * t;
private static float OutQuart(float t) =>
1f - (--t) * t * t * t;
private static float InOutQuart(float t) =>
t < 0.5f ? 8f * t * t * t * t : 1f - 8f * (--t) * t * t * t;
private static float InQuint(float t) => t * t * t * t * t;
private static float OutQuint(float t) =>
1f + (--t) * t * t * t * t;
private static float InOutQuint(float t) =>
t < 0.5f ? 16f * t * t * t * t * t : 1f + 16f * (--t) * t * t * t * t;
private static float InSine(float t) =>
1f - Mathf.Cos(t * HALF_PI);
private static float OutSine(float t) =>
Mathf.Sin(t * HALF_PI);
private static float InOutSine(float t) =>
0.5f * (1f - Mathf.Cos(Mathf.PI * t));
private static float InExpo(float t) =>
Mathf.Approximately(t, 0) ? 0 : Mathf.Pow(2, 10 * (t - 1));
private static float OutExpo(float t) =>
Mathf.Approximately(t, 1) ? 1 : 1 - Mathf.Pow(2, -10 * t);
private static float InOutExpo(float t)
{
if (Mathf.Approximately(t, 0)) return 0;
if (Mathf.Approximately(t, 1)) return 1;
return t < 0.5f
? 0.5f * Mathf.Pow(2, 20 * t - 10)
: 0.5f * (2 - Mathf.Pow(2, -20 * t + 10));
}
private static float InElastic(float from, float to, float t)
private static float InCirc(float t) =>
1f - Mathf.Sqrt(1f - t * t);
private static float OutCirc(float t) =>
Mathf.Sqrt(1f - (t - 1f) * (t - 1f));
private static float InOutCirc(float t) =>
t < 0.5f
? 0.5f * (1 - Mathf.Sqrt(1 - 4 * t * t))
: 0.5f * (Mathf.Sqrt(1 - 4 * (t - 1) * (t - 1)) + 1);
private static float InBounce(float t) =>
1f - OutBounce(1f - t);
private static float OutBounce(float t)
{
float c = to - from;
if (t == 0) return from;
if ((t /= 1f) == 1) return from + c;
float p = 0.3f;
float s = p / 4f;
return -(c * Mathf.Pow(2, 10 * (t -= 1)) * Mathf.Sin((t - s) * (2 * Mathf.PI) / p)) + from;
if (t < BOUNCE_THRESHOLD1)
return 7.5625f * t * t;
if (t < BOUNCE_THRESHOLD2)
return 7.5625f * (t -= 1.5f / BOUNCE_DIVISOR) * t + 0.75f;
if (t < BOUNCE_THRESHOLD3)
return 7.5625f * (t -= 2.25f / BOUNCE_DIVISOR) * t + 0.9375f;
return 7.5625f * (t -= 2.625f / BOUNCE_DIVISOR) * t + 0.984375f;
}
private static float OutElastic(float from, float to, float t)
private static float InOutBounce(float t) =>
t < 0.5f
? 0.5f * InBounce(2f * t)
: 0.5f * OutBounce(2f * t - 1f) + 0.5f;
private static float InElastic(float t)
{
float c = to - from;
if (t == 0) return from;
if ((t /= 1f) == 1) return from + c;
float p = 0.3f;
float s = p / 4f;
return (c * Mathf.Pow(2, -10 * t) * Mathf.Sin((t - s) * (2 * Mathf.PI) / p) + c + from);
if (Mathf.Approximately(t, 0)) return 0;
if (Mathf.Approximately(t, 1)) return 1;
const float p = 0.3f;
const float s = p / 4f;
return -Mathf.Pow(2, 10 * (t -= 1)) * Mathf.Sin((t - s) * DOUBLE_PI / p);
}
private static float InOutElastic(float from, float to, float t)
private static float OutElastic(float t)
{
float c = to - from;
if (t == 0) return from;
if ((t /= 0.5f) == 2) return from + c;
float p = 0.3f * 1.5f;
float s = p / 4f;
if (t < 1)
return -0.5f * (c * Mathf.Pow(2, 10 * (t -= 1f)) * Mathf.Sin((t - 2) * (2 * Mathf.PI) / p)) + from;
return c * Mathf.Pow(2, -10 * (t -= 1)) * Mathf.Sin((t - s) * (2f * Mathf.PI) / p) * 0.5f + c + from;
if (Mathf.Approximately(t, 0)) return 0;
if (Mathf.Approximately(t, 1)) return 1;
const float p = 0.3f;
const float s = p / 4f;
return Mathf.Pow(2, -10 * t) * Mathf.Sin((t - s) * DOUBLE_PI / p) + 1;
}
private static float InBack(float from, float to, float t)
private static float InOutElastic(float t)
{
float c = to - from;
float s = 1.70158f;
t /= 0.5f;
return c * t * t * ((s + 1) * t - s) + from;
if (Mathf.Approximately(t, 0)) return 0;
if (Mathf.Approximately(t, 1)) return 1;
const float p = 0.45f;
if (t < 0.5f)
return -0.5f * Mathf.Pow(2, 20 * t - 10) * Mathf.Sin((20 * t - 1.125f) * DOUBLE_PI / p);
return 0.5f * Mathf.Pow(2, -20 * t + 10) * Mathf.Sin((20 * t - 1.125f) * DOUBLE_PI / p) + 1;
}
private static float OutBack(float from, float to, float t)
private static float InBack(float t)
{
float c = to - from;
float s = 1.70158f;
t = t / 1f - 1f;
return c * (t * t * ((s + 1) * t + s) + 1) + from;
const float s = 1.70158f;
return t * t * ((s + 1) * t - s);
}
private static float InOutBack(float from, float to, float t)
private static float OutBack(float t)
{
float c = to - from;
float s = 1.70158f;
t /= 0.5f;
if (t < 1) return c / 2f * (t * t * (((s *= (1.525f)) + 1) * t - s)) + from;
t -= 2;
return c / 2f * (t * t * (((s *= (1.525f)) + 1) * t + s) + 2) + from;
const float s = 1.70158f;
return (t -= 1) * t * ((s + 1) * t + s) + 1;
}
private static float InOutBack(float t)
{
float s = 1.70158f * 1.525f;
return t < 0.5f
? 0.5f * (4 * t * t * ((s + 1) * 2 * t - s))
: 0.5f * ((2 * t - 2) * (2 * t - 2) * ((s + 1) * (2 * t - 2) + s) + 2);
}
#endregion
}
// [System.Serializable]
// public class PresetAnimationCurve
// {
// public AnimationCurveType animationCurveType; //动画曲线类型
//
// public PresetAnimationCurve(AnimationCurveType animationCurveType)
// {
// this.animationCurveType = animationCurveType;
// }
//
// /// <summary>
// /// 根据Type选择曲线并计算t点(0,1)时曲线的值若t越界则直接返回0或1
// /// </summary>
// public float Evaluate(float t)
// {
// return AnimationCurveEvaluator.Evaluate(this.animationCurveType, t);
// }
// }
}

View File

@@ -231,13 +231,15 @@ namespace Ichni.RhythmGame
var timeField = qcWindow.GenerateInputField(qcSubcontainer, "Time offset", "0");
var iterationField = qcWindow.GenerateInputField(qcSubcontainer, "Iteration", "0");
var includeAnimationToggle = qcWindow.GenerateToggle(null, qcSubcontainer, "Include Animation", string.Empty);
var MovingTrackToggle = qcWindow.GenerateToggle(null, qcSubcontainer, "Moving Track or PathNode", string.Empty);
qcWindow.GenerateButton(this, qcSubcontainer, "Copy", () =>
{
Vector3 positionOffset = new Vector3(xField.GetValue<float>(), yField.GetValue<float>(), zField.GetValue<float>());
float timeOffset = timeField.GetValue<float>();
int iteration = iterationField.GetValue<int>();
bool includeAnimation = includeAnimationToggle.toggle.isOn;
QuickCopy(positionOffset, timeOffset, includeAnimation, iteration);
bool MovingTrack = MovingTrackToggle.toggle.isOn;
QuickCopy(positionOffset, timeOffset, includeAnimation, iteration, MovingTrack);
});
}); //快速复制

View File

@@ -32,7 +32,7 @@ namespace Ichni.RhythmGame
head.trackPositioner = head.gameObject.AddComponent<SplinePositioner>();
head.trackPositioner.spline = track.trackPathSubmodule.path;
head.trackTimeSubmoduleMovable = track.trackTimeSubmodule as TrackTimeSubmoduleMovable;
head.motionApplyRotation = motionApplyRotation;
head.trackPositioner.motion.applyRotation = motionApplyRotation;
@@ -69,7 +69,7 @@ namespace Ichni.RhythmGame
var container = inspector.GenerateContainer("Track Percent Point");
var MotionAngles = container.GenerateSubcontainer(3);
var MotionAnglesT = inspector.GenerateToggle(this, MotionAngles, "Motion With Angles", nameof(motionApplyRotation));
var generation = container.GenerateSubcontainer(3);
var generateTrailButton = inspector.GenerateButton(this, generation, "Generate Trail", () =>
{
@@ -85,7 +85,7 @@ namespace Ichni.RhythmGame
{
base.Refresh();
trackPositioner.motion.applyRotation = motionApplyRotation;
this.transform.eulerAngles = Vector3.zero;
this.transform.localEulerAngles = Vector3.zero;
}
}

View File

@@ -58,6 +58,7 @@ namespace Ichni.RhythmGame
meshRenderer.material = renderMaterial;
}
public override void Refresh()
{
SetEnableZWrite();

View File

@@ -15,7 +15,7 @@ namespace Ichni.RhythmGame
/// <param name="unitPositionOffset">单位位置整体偏移</param>
/// <param name="unitTimeOffset">单位时间偏移</param>
/// <param name="iteration">迭代次数即产生几个粘贴的Track</param>
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1)
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1, bool MovingTrack = false)
{
if (iteration <= 0) return;
@@ -29,14 +29,20 @@ namespace Ichni.RhythmGame
float timeOffset = unitTimeOffset * i;
//以下对Track的所有有效的Submodule和子GameElement进行偏移 TODO: 需要思考是否有统一时间偏移的方法?
//PathNode位置偏移
newTrack.trackPathSubmodule.pathNodeList.ForEach(pn =>
if (MovingTrack)
{
pn.transformSubmodule.originalPosition += positionOffset;
pn.transformSubmodule.Refresh();
});
newTrack.transformSubmodule.originalPosition += positionOffset;
newTrack.transformSubmodule.Refresh();
}
else
{
//PathNode位置偏移
newTrack.trackPathSubmodule.pathNodeList.ForEach(pn =>
{
pn.transformSubmodule.originalPosition += positionOffset;
pn.transformSubmodule.Refresh();
});
}
//TrackTimeSubmoduleMovable时间偏移
if (newTrack.trackTimeSubmodule is TrackTimeSubmoduleMovable movable)
{