@@ -715,7 +715,7 @@ namespace Ichni.Editor
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Animation Swaps (动画值交换)
|
||||
#region Animation (动画值)
|
||||
/// <summary>
|
||||
/// 交换 Displacement 动画值的正负号
|
||||
/// </summary>
|
||||
@@ -799,6 +799,32 @@ namespace Ichni.Editor
|
||||
anim.startValue = -anim.startValue;
|
||||
}
|
||||
}
|
||||
|
||||
// public static void randomAnimationValue(float range)
|
||||
// {
|
||||
// AnimationBase animationBase = inspector.connectedGameElement as AnimationBase;
|
||||
// if (animationBase == null)
|
||||
// {
|
||||
// LogWindow.Log("Please select a AnimationBase first!", Color.red);
|
||||
// return;
|
||||
// }
|
||||
// System.Random random = new System.Random();
|
||||
// foreach (var property in animationBase.GetType().GetProperties())
|
||||
// {
|
||||
// if (property.PropertyType == typeof(FlexibleFloat))
|
||||
// {
|
||||
// FlexibleFloat ff = property.GetValue(animationBase) as FlexibleFloat;
|
||||
// if (ff != null)
|
||||
// {
|
||||
// foreach (var anim in ff.animations)
|
||||
// {
|
||||
// float randomOffset = (float)(random.NextDouble() * 2 - 1) * range;
|
||||
// anim.endValue += randomOffset;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
#endregion
|
||||
|
||||
#region Global Utilities (全局工具)
|
||||
|
||||
@@ -53,6 +53,20 @@ namespace Ichni.RhythmGame
|
||||
interferometer.InterferomValue(ref value);
|
||||
}
|
||||
}
|
||||
public FlexibleFloat GetInterferomedValue(FlexibleFloat originalValue)
|
||||
{
|
||||
FlexibleFloat newone = new FlexibleFloat();
|
||||
foreach (var anim in originalValue.animations)
|
||||
{
|
||||
AnimatedFloat animatedFloat = new AnimatedFloat(anim.startTime, anim.endTime, anim.startValue, anim.endValue, anim.animationCurveType);
|
||||
foreach (var interferometer in Interferometers.OfType<Vector3Interferometer>())
|
||||
{
|
||||
animatedFloat = interferometer.InterferomValue(animatedFloat);
|
||||
}
|
||||
newone.Add(animatedFloat);
|
||||
}
|
||||
return newone;
|
||||
}
|
||||
public void ApplyVector3InterferometersBM(FlexibleFloat_BM X, FlexibleFloat_BM Y, FlexibleFloat_BM Z)
|
||||
{
|
||||
foreach (Vector3Interferometer interferometer in Interferometers.OfType<Vector3Interferometer>())
|
||||
|
||||
@@ -58,6 +58,32 @@ namespace Ichni.RhythmGame
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
public AnimatedFloat InterferomValue(AnimatedFloat animatedFloat)
|
||||
{
|
||||
AnimatedFloat newone = new AnimatedFloat(animatedFloat.startTime, animatedFloat.endTime, animatedFloat.startValue, animatedFloat.endValue, animatedFloat.animationCurveType);
|
||||
switch (InterferomType)
|
||||
{
|
||||
case InterferomType.Additive:
|
||||
// Additive: add interferometer effect to the current value (placeholder)
|
||||
newone.endValue += InterferomValueVector3.x;
|
||||
newone.startValue += InterferomValueVector3.x;
|
||||
break;
|
||||
case InterferomType.Multiplicative:
|
||||
// Multiplicative: multiply current value by interferometer effect (placeholder)
|
||||
newone.endValue *= InterferomValueVector3.x;
|
||||
newone.startValue *= InterferomValueVector3.x;
|
||||
break;
|
||||
case InterferomType.Override:
|
||||
// Override: replace current value with interferometer effect (placeholder)
|
||||
newone.endValue = InterferomValueVector3.x;
|
||||
newone.startValue = InterferomValueVector3.x;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return newone;
|
||||
|
||||
}
|
||||
public void InterferomValueBM(FlexibleFloat_BM X, FlexibleFloat_BM Y, FlexibleFloat_BM Z)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Beatmap;
|
||||
using Ichni;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
@@ -14,83 +12,168 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
private TransformSubmodule targetTransformSubmodule;
|
||||
public ICanBeTrackedDisplacement targetDisplacement;
|
||||
private FlexibleFloat positionX, positionY, positionZ;
|
||||
|
||||
public Vector3 PreviewValue = Vector3.zero;
|
||||
public float TimeOffset;
|
||||
public BaseElement_BM MatchingExportElement { get; set; } = null;
|
||||
public List<InterferometerBase> Interferometers { get; set; } = new();
|
||||
private bool isSwitchingReturnType = false;
|
||||
|
||||
public override void Initialize(string name, Guid elementGuid, List<string> tags, bool isFirstGenerated, GameElement parentElement)
|
||||
{
|
||||
base.Initialize(name, elementGuid, tags, isFirstGenerated, parentElement);
|
||||
positionX = new FlexibleFloat();
|
||||
positionY = new FlexibleFloat();
|
||||
positionZ = new FlexibleFloat();
|
||||
}
|
||||
public static DisplacementTracker GenerateElement(string elementName, System.Guid id,
|
||||
List<string> tags, bool isFirstGenerated, GameElement animatedObject, Displacement targetDisplacement, float timeOffset)
|
||||
{
|
||||
DisplacementTracker tracker = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<DisplacementTracker>();
|
||||
tracker.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
|
||||
tracker.animatedObject = animatedObject;
|
||||
tracker.targetDisplacement = targetDisplacement;
|
||||
tracker.SetTargetDisplacement(targetDisplacement);
|
||||
tracker.TimeOffset = timeOffset;
|
||||
tracker.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public void SetTargetDisplacement(ICanBeTrackedDisplacement newTarget)
|
||||
{
|
||||
// 解绑旧事件
|
||||
if (targetDisplacement is Displacement oldDisp)
|
||||
{
|
||||
oldDisp.positionX.OnDataChanged -= OnSourceChanged;
|
||||
}
|
||||
else if (targetDisplacement is DisplacementTracker oldTracker)
|
||||
{
|
||||
oldTracker.positionX.OnDataChanged -= OnSourceChanged;
|
||||
}
|
||||
targetDisplacement = newTarget;
|
||||
if (targetDisplacement is Displacement disp)
|
||||
{
|
||||
positionX = ManualCopyFlexibleFloat(disp.positionX);
|
||||
positionY = ManualCopyFlexibleFloat(disp.positionY);
|
||||
positionZ = ManualCopyFlexibleFloat(disp.positionZ);
|
||||
disp.positionX.OnDataChanged += OnSourceChanged;
|
||||
}
|
||||
else if (targetDisplacement is DisplacementTracker tracker)
|
||||
{
|
||||
positionX = ManualCopyFlexibleFloat(tracker.positionX);
|
||||
positionY = ManualCopyFlexibleFloat(tracker.positionY);
|
||||
positionZ = ManualCopyFlexibleFloat(tracker.positionZ);
|
||||
tracker.positionX.OnDataChanged += OnSourceChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSourceChanged()
|
||||
{
|
||||
if (targetDisplacement is Displacement disp)
|
||||
{
|
||||
CopyFlexibleFloat(positionX, disp.positionX);
|
||||
CopyFlexibleFloat(positionY, disp.positionY);
|
||||
CopyFlexibleFloat(positionZ, disp.positionZ);
|
||||
// 叠加 IHaveVector3Interferometer 偏移
|
||||
positionX = ((IHaveVector3Interferometer)disp).GetInterferomedValue(positionX);
|
||||
positionY = ((IHaveVector3Interferometer)disp).GetInterferomedValue(positionY);
|
||||
positionZ = ((IHaveVector3Interferometer)disp).GetInterferomedValue(positionZ);
|
||||
|
||||
}
|
||||
else if (targetDisplacement is DisplacementTracker tracker)
|
||||
{
|
||||
CopyFlexibleFloat(positionX, tracker.positionX);
|
||||
CopyFlexibleFloat(positionY, tracker.positionY);
|
||||
CopyFlexibleFloat(positionZ, tracker.positionZ);
|
||||
|
||||
positionX = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(positionX);
|
||||
positionY = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(positionY);
|
||||
positionZ = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(positionZ);
|
||||
|
||||
}
|
||||
}
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
OnSourceChanged();
|
||||
}
|
||||
|
||||
private FlexibleFloat ManualCopyFlexibleFloat(FlexibleFloat source)
|
||||
{
|
||||
var target = new FlexibleFloat();
|
||||
CopyFlexibleFloat(target, source);
|
||||
|
||||
return target;
|
||||
}
|
||||
private void CopyFlexibleFloat(FlexibleFloat target, FlexibleFloat source)
|
||||
{
|
||||
|
||||
target.animations = new List<AnimatedFloat>();
|
||||
foreach (var a in source.animations)
|
||||
{
|
||||
AnimatedFloat animatedFloat = new AnimatedFloat(a.startTime + TimeOffset, a.endTime + TimeOffset, a.startValue, a.endValue, a.animationCurveType);
|
||||
|
||||
target.animations.Add(animatedFloat);
|
||||
}
|
||||
// 如有其它字段请补充
|
||||
}
|
||||
|
||||
protected override void UpdateAnimation(float songTime)
|
||||
{
|
||||
if (targetDisplacement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var a = GetCurrentReturnTypes(songTime);
|
||||
var (x, y, z) = (a[0], a[1], a[2]);
|
||||
positionX.UpdateFlexibleFloat(songTime);
|
||||
positionY.UpdateFlexibleFloat(songTime);
|
||||
positionZ.UpdateFlexibleFloat(songTime);
|
||||
|
||||
if (x.Item1 is FlexibleReturnType.MiddleExecuting ||
|
||||
y.Item1 is FlexibleReturnType.MiddleExecuting ||
|
||||
z.Item1 is FlexibleReturnType.MiddleExecuting)
|
||||
if (positionX.returnType is FlexibleReturnType.MiddleExecuting ||
|
||||
positionY.returnType is FlexibleReturnType.MiddleExecuting ||
|
||||
positionZ.returnType is FlexibleReturnType.MiddleExecuting)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
ApplyValue(songTime);
|
||||
isSwitchingReturnType = true;
|
||||
ApplyValue();
|
||||
}
|
||||
else if (isSwitchingReturnType)
|
||||
else if (positionX.isSwitchingReturnType || positionY.isSwitchingReturnType || positionZ.isSwitchingReturnType)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
isSwitchingReturnType = false;
|
||||
ApplyValue(songTime);
|
||||
ApplyValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
|
||||
{
|
||||
ApplyValue(songTime);
|
||||
ApplyValue();
|
||||
}
|
||||
animationReturnType = FlexibleReturnType.MiddleInterval;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyValue(float time)
|
||||
private void ApplyValue()
|
||||
{
|
||||
Vector3 currentPosition = targetDisplacement.getValue(time + TimeOffset);
|
||||
Vector3 currentPosition = new Vector3(positionX.value, positionY.value, positionZ.value);
|
||||
// 用接口强制调用默认实现
|
||||
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentPosition);
|
||||
targetTransformSubmodule.positionOffset += currentPosition;
|
||||
targetTransformSubmodule.positionDirtyMark = true;
|
||||
PreviewValue = currentPosition;
|
||||
}
|
||||
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
|
||||
{
|
||||
return targetDisplacement.GetCurrentReturnTypes(time + TimeOffset);
|
||||
}
|
||||
|
||||
public override Vector3 getValue(float time)
|
||||
{
|
||||
Vector3 currentPosition = targetDisplacement.getValue(time + TimeOffset);
|
||||
Vector3 currentPosition = new Vector3(
|
||||
positionX.GetValue(time + TimeOffset),
|
||||
positionY.GetValue(time + TimeOffset),
|
||||
positionZ.GetValue(time + TimeOffset)
|
||||
);
|
||||
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentPosition);
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var container = inspector.GenerateContainer("Enable Control");
|
||||
var effectSettings = container.GenerateSubcontainer(2);
|
||||
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Try Get Displacement");
|
||||
@@ -98,26 +181,21 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
ICanBeTrackedDisplacement targetElement = EditorManager.instance.beatmapContainer.gameElementList.OfType<ICanBeTrackedDisplacement>()
|
||||
.First(e => ((GameElement)e).elementName == connectedGameElementInputField.GetValue<string>());
|
||||
|
||||
if (targetElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
}
|
||||
|
||||
targetDisplacement = targetElement;
|
||||
//targetTransformSubmodule = (targetElement as IHaveTransformSubmodule).transformSubmodule;
|
||||
|
||||
SetTargetDisplacement(targetElement);
|
||||
inspectorMain.SetInspector(this);
|
||||
});
|
||||
string ShowConnection() => targetDisplacement == null ? "No Displacement Connected" : "Connected With: " + ((GameElement)targetDisplacement).elementName;
|
||||
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
|
||||
var InputField = inspector.GenerateInputField(this, effectSettings, "Offset", nameof(TimeOffset));
|
||||
var interferometerButton = inspector.GenerateButton(this, effectSettings, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
}
|
||||
|
||||
public override void SaveBM()
|
||||
@@ -125,62 +203,28 @@ namespace Ichni.RhythmGame
|
||||
matchedBM = new DisplacementTracker_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
|
||||
((GameElement)targetDisplacement).elementGuid, TimeOffset);
|
||||
}
|
||||
public bool MaybeDeadLoop = true;
|
||||
public void SaveExportBM()
|
||||
{
|
||||
|
||||
Refresh();
|
||||
SaveBM();
|
||||
MatchingExportElement = matchedBM;
|
||||
float finalTimeOffset = 0;
|
||||
Displacement displacement = GetOriginDisplacementWithOffset(ref finalTimeOffset);
|
||||
displacement.SaveBM();
|
||||
var x = ((Displacement_BM)displacement.matchedBM).positionX.DeepCopyBM();
|
||||
var y = ((Displacement_BM)displacement.matchedBM).positionY.DeepCopyBM();
|
||||
var z = ((Displacement_BM)displacement.matchedBM).positionZ.DeepCopyBM();
|
||||
x.ApplyTimeOffset(finalTimeOffset); y.ApplyTimeOffset(finalTimeOffset); z.ApplyTimeOffset(finalTimeOffset);
|
||||
|
||||
// 构建链表,从底层 Displacement 到最上层 Tracker
|
||||
List<ICanBeTrackedDisplacement> chain = new List<ICanBeTrackedDisplacement>();
|
||||
ICanBeTrackedDisplacement cur = this;
|
||||
int safeGuard = 100; // 防止死循环
|
||||
while (cur != null && safeGuard-- > 0)
|
||||
{
|
||||
chain.Insert(0, cur);
|
||||
if (cur is DisplacementTracker tracker)
|
||||
cur = tracker.targetDisplacement;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// 依次叠加 Interferometer
|
||||
foreach (var o in chain)
|
||||
((IHaveVector3Interferometer)o).ApplyVector3InterferometersBM(x, y, z);
|
||||
|
||||
// 先保存 parentElement
|
||||
parentElement.SaveBM();
|
||||
|
||||
// 用当前 elementName/tags
|
||||
var a = new Displacement_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, x, y, z);
|
||||
var a = new Displacement_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
|
||||
positionX.ConvertToBM(), positionY.ConvertToBM(), positionZ.ConvertToBM());
|
||||
MatchingExportElement = a;
|
||||
}
|
||||
|
||||
public Displacement GetOriginDisplacementWithOffset(ref float timeOffset)
|
||||
{
|
||||
timeOffset += TimeOffset;
|
||||
if (targetDisplacement is Displacement disp)
|
||||
{
|
||||
return disp;
|
||||
}
|
||||
else if (targetDisplacement is DisplacementTracker dispt)
|
||||
{
|
||||
return dispt.GetOriginDisplacementWithOffset(ref timeOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("WTF type of tracked displacement.");
|
||||
}
|
||||
// 兼容旧接口,直接返回 null
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
public interface ICanBeTracked
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Ichni.RhythmGame
|
||||
public float TimeOffset;
|
||||
public BaseElement_BM MatchingExportElement { get; set; } = null;
|
||||
public List<InterferometerBase> Interferometers { get; set; } = new();
|
||||
private bool isSwitchingReturnType = false;
|
||||
private FlexibleFloat scaleX, scaleY, scaleZ;
|
||||
|
||||
public static ScaleTracker GenerateElement(string elementName, Guid id,
|
||||
List<string> tags, bool isFirstGenerated, GameElement animatedObject, ICanBeTrackedScale targetScale, float timeOffset)
|
||||
@@ -31,54 +31,133 @@ namespace Ichni.RhythmGame
|
||||
tracker.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public override void Initialize(string name, Guid elementGuid, List<string> tags, bool isFirstGenerated, GameElement parentElement)
|
||||
{
|
||||
base.Initialize(name, elementGuid, tags, isFirstGenerated, parentElement);
|
||||
scaleX = new FlexibleFloat();
|
||||
scaleY = new FlexibleFloat();
|
||||
scaleZ = new FlexibleFloat();
|
||||
}
|
||||
|
||||
public void SetTargetScale(ICanBeTrackedScale newTarget)
|
||||
{
|
||||
if (targetScale is Scale oldScale)
|
||||
{
|
||||
oldScale.scaleX.OnDataChanged -= OnSourceChanged;
|
||||
}
|
||||
else if (targetScale is ScaleTracker oldTracker)
|
||||
{
|
||||
oldTracker.scaleX.OnDataChanged -= OnSourceChanged;
|
||||
}
|
||||
targetScale = newTarget;
|
||||
if (targetScale is Scale scale)
|
||||
{
|
||||
scaleX = ManualCopyFlexibleFloat(scale.scaleX);
|
||||
scaleY = ManualCopyFlexibleFloat(scale.scaleY);
|
||||
scaleZ = ManualCopyFlexibleFloat(scale.scaleZ);
|
||||
scale.scaleX.OnDataChanged += OnSourceChanged;
|
||||
}
|
||||
else if (targetScale is ScaleTracker tracker)
|
||||
{
|
||||
scaleX = ManualCopyFlexibleFloat(tracker.scaleX);
|
||||
scaleY = ManualCopyFlexibleFloat(tracker.scaleY);
|
||||
scaleZ = ManualCopyFlexibleFloat(tracker.scaleZ);
|
||||
tracker.scaleX.OnDataChanged += OnSourceChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSourceChanged()
|
||||
{
|
||||
if (targetScale is Scale scale)
|
||||
{
|
||||
CopyFlexibleFloat(scaleX, scale.scaleX);
|
||||
CopyFlexibleFloat(scaleY, scale.scaleY);
|
||||
CopyFlexibleFloat(scaleZ, scale.scaleZ);
|
||||
scaleX = ((IHaveVector3Interferometer)scale).GetInterferomedValue(scaleX);
|
||||
scaleY = ((IHaveVector3Interferometer)scale).GetInterferomedValue(scaleY);
|
||||
scaleZ = ((IHaveVector3Interferometer)scale).GetInterferomedValue(scaleZ);
|
||||
}
|
||||
else if (targetScale is ScaleTracker tracker)
|
||||
{
|
||||
CopyFlexibleFloat(scaleX, tracker.scaleX);
|
||||
CopyFlexibleFloat(scaleY, tracker.scaleY);
|
||||
CopyFlexibleFloat(scaleZ, tracker.scaleZ);
|
||||
scaleX = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(scaleX);
|
||||
scaleY = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(scaleY);
|
||||
scaleZ = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(scaleZ);
|
||||
}
|
||||
}
|
||||
|
||||
private FlexibleFloat ManualCopyFlexibleFloat(FlexibleFloat source)
|
||||
{
|
||||
var target = new FlexibleFloat();
|
||||
CopyFlexibleFloat(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
private void CopyFlexibleFloat(FlexibleFloat target, FlexibleFloat source)
|
||||
{
|
||||
target.animations = new List<AnimatedFloat>();
|
||||
foreach (var a in source.animations)
|
||||
{
|
||||
AnimatedFloat animatedFloat = new AnimatedFloat(a.startTime + TimeOffset, a.endTime + TimeOffset, a.startValue, a.endValue, a.animationCurveType);
|
||||
target.animations.Add(animatedFloat);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateAnimation(float songTime)
|
||||
{
|
||||
if (targetScale == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var a = GetCurrentReturnTypes(songTime);
|
||||
var (x, y, z) = (a[0], a[1], a[2]);
|
||||
|
||||
if (x.Item1 is FlexibleReturnType.MiddleExecuting ||
|
||||
y.Item1 is FlexibleReturnType.MiddleExecuting ||
|
||||
z.Item1 is FlexibleReturnType.MiddleExecuting)
|
||||
scaleX.UpdateFlexibleFloat(songTime);
|
||||
scaleY.UpdateFlexibleFloat(songTime);
|
||||
scaleZ.UpdateFlexibleFloat(songTime);
|
||||
if (scaleX.returnType is FlexibleReturnType.MiddleExecuting ||
|
||||
scaleY.returnType is FlexibleReturnType.MiddleExecuting ||
|
||||
scaleZ.returnType is FlexibleReturnType.MiddleExecuting)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
ApplyValue(songTime);
|
||||
isSwitchingReturnType = true;
|
||||
ApplyValue();
|
||||
}
|
||||
else if (isSwitchingReturnType)
|
||||
else if (scaleX.isSwitchingReturnType || scaleY.isSwitchingReturnType || scaleZ.isSwitchingReturnType)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
isSwitchingReturnType = false;
|
||||
ApplyValue(songTime);
|
||||
ApplyValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
|
||||
{
|
||||
ApplyValue(songTime);
|
||||
ApplyValue();
|
||||
}
|
||||
animationReturnType = FlexibleReturnType.MiddleInterval;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyValue(float time)
|
||||
private void ApplyValue()
|
||||
{
|
||||
Vector3 currentScale = targetScale.getValue(time + TimeOffset);
|
||||
Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value);
|
||||
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentScale);
|
||||
targetTransformSubmodule.scaleOffset += currentScale;
|
||||
targetTransformSubmodule.scaleDirtyMark = true;
|
||||
PreviewValue = currentScale;
|
||||
}
|
||||
|
||||
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
|
||||
{
|
||||
return targetScale.GetCurrentReturnTypes(time + TimeOffset);
|
||||
}
|
||||
|
||||
public override Vector3 getValue(float time)
|
||||
{
|
||||
Vector3 currentScale = targetScale.getValue(time + TimeOffset);
|
||||
Vector3 currentScale = new Vector3(
|
||||
scaleX.GetValue(time + TimeOffset),
|
||||
scaleY.GetValue(time + TimeOffset),
|
||||
scaleZ.GetValue(time + TimeOffset)
|
||||
);
|
||||
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentScale);
|
||||
return currentScale;
|
||||
}
|
||||
@@ -121,32 +200,18 @@ namespace Ichni.RhythmGame
|
||||
matchedBM = new ScaleTracker_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
|
||||
((GameElement)targetScale).elementGuid, TimeOffset);
|
||||
}
|
||||
|
||||
public bool MaybeDeadLoop = true;
|
||||
|
||||
public void SaveExportBM()
|
||||
{
|
||||
|
||||
Refresh();
|
||||
SaveBM();
|
||||
MatchingExportElement = matchedBM;
|
||||
float finalTimeOffset = 0;
|
||||
Scale scale = GetOriginScaleWithOffset(ref finalTimeOffset);
|
||||
scale.SaveBM();
|
||||
var x = ((Scale_BM)scale.matchedBM).scaleX.DeepCopyBM();
|
||||
var y = ((Scale_BM)scale.matchedBM).scaleY.DeepCopyBM();
|
||||
var z = ((Scale_BM)scale.matchedBM).scaleZ.DeepCopyBM();
|
||||
x.ApplyTimeOffset(finalTimeOffset); y.ApplyTimeOffset(finalTimeOffset); z.ApplyTimeOffset(finalTimeOffset);
|
||||
|
||||
List<ICanBeTrackedScale> ICanBeTrackedScales = new List<ICanBeTrackedScale> { this as ICanBeTrackedScale };
|
||||
while (MaybeDeadLoop && ICanBeTrackedScales[0] is not Scale)
|
||||
{
|
||||
ICanBeTrackedScale ao = (ICanBeTrackedScales[0] as ScaleTracker).targetScale;
|
||||
ICanBeTrackedScales.Insert(0, ao);
|
||||
}
|
||||
ICanBeTrackedScales.ForEach(o =>
|
||||
{
|
||||
((IHaveVector3Interferometer)o).ApplyVector3InterferometersBM(x, y, z);
|
||||
});
|
||||
parentElement.SaveBM();
|
||||
Scale_BM a = new Scale_BM("Scale", elementGuid, new List<string>(), parentElement.matchedBM as GameElement_BM,
|
||||
x, y, z);
|
||||
var a = new Scale_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
|
||||
scaleX.ConvertToBM(), scaleY.ConvertToBM(), scaleZ.ConvertToBM());
|
||||
MatchingExportElement = a;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Ichni.RhythmGame
|
||||
public float TimeOffset;
|
||||
public BaseElement_BM MatchingExportElement { get; set; } = null;
|
||||
public List<InterferometerBase> Interferometers { get; set; } = new();
|
||||
private bool isSwitchingReturnType = false;
|
||||
private FlexibleFloat eulerAngleX, eulerAngleY, eulerAngleZ;
|
||||
|
||||
public static SwirlTracker GenerateElement(string elementName, Guid id,
|
||||
List<string> tags, bool isFirstGenerated, GameElement animatedObject, Swirl targetSwirl, float timeOffset)
|
||||
@@ -31,27 +31,94 @@ namespace Ichni.RhythmGame
|
||||
tracker.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
|
||||
return tracker;
|
||||
}
|
||||
public override void Initialize(string name, Guid elementGuid, List<string> tags, bool isFirstGenerated, GameElement parentElement)
|
||||
{
|
||||
base.Initialize(name, elementGuid, tags, isFirstGenerated, parentElement);
|
||||
eulerAngleX = new FlexibleFloat();
|
||||
eulerAngleY = new FlexibleFloat();
|
||||
eulerAngleZ = new FlexibleFloat();
|
||||
}
|
||||
public void SetTargetSwirl(ICanBeTrackedSwirl newTarget)
|
||||
{
|
||||
if (targetSwirl is Swirl oldSwirl)
|
||||
{
|
||||
oldSwirl.eulerAngleX.OnDataChanged -= OnSourceChanged;
|
||||
}
|
||||
else if (targetSwirl is SwirlTracker oldTracker)
|
||||
{
|
||||
oldTracker.eulerAngleX.OnDataChanged -= OnSourceChanged;
|
||||
}
|
||||
targetSwirl = newTarget;
|
||||
if (targetSwirl is Swirl swirl)
|
||||
{
|
||||
eulerAngleX = ManualCopyFlexibleFloat(swirl.eulerAngleX);
|
||||
eulerAngleY = ManualCopyFlexibleFloat(swirl.eulerAngleY);
|
||||
eulerAngleZ = ManualCopyFlexibleFloat(swirl.eulerAngleZ);
|
||||
swirl.eulerAngleX.OnDataChanged += OnSourceChanged;
|
||||
}
|
||||
else if (targetSwirl is SwirlTracker tracker)
|
||||
{
|
||||
eulerAngleX = ManualCopyFlexibleFloat(tracker.eulerAngleX);
|
||||
eulerAngleY = ManualCopyFlexibleFloat(tracker.eulerAngleY);
|
||||
eulerAngleZ = ManualCopyFlexibleFloat(tracker.eulerAngleZ);
|
||||
tracker.eulerAngleX.OnDataChanged += OnSourceChanged;
|
||||
}
|
||||
}
|
||||
private void OnSourceChanged()
|
||||
{
|
||||
if (targetSwirl is Swirl swirl)
|
||||
{
|
||||
CopyFlexibleFloat(eulerAngleX, swirl.eulerAngleX);
|
||||
CopyFlexibleFloat(eulerAngleY, swirl.eulerAngleY);
|
||||
CopyFlexibleFloat(eulerAngleZ, swirl.eulerAngleZ);
|
||||
eulerAngleX = ((IHaveVector3Interferometer)swirl).GetInterferomedValue(eulerAngleX);
|
||||
eulerAngleY = ((IHaveVector3Interferometer)swirl).GetInterferomedValue(eulerAngleY);
|
||||
eulerAngleZ = ((IHaveVector3Interferometer)swirl).GetInterferomedValue(eulerAngleZ);
|
||||
}
|
||||
else if (targetSwirl is SwirlTracker tracker)
|
||||
{
|
||||
CopyFlexibleFloat(eulerAngleX, tracker.eulerAngleX);
|
||||
CopyFlexibleFloat(eulerAngleY, tracker.eulerAngleY);
|
||||
CopyFlexibleFloat(eulerAngleZ, tracker.eulerAngleZ);
|
||||
eulerAngleX = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(eulerAngleX);
|
||||
eulerAngleY = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(eulerAngleY);
|
||||
eulerAngleZ = ((IHaveVector3Interferometer)tracker).GetInterferomedValue(eulerAngleZ);
|
||||
}
|
||||
}
|
||||
private FlexibleFloat ManualCopyFlexibleFloat(FlexibleFloat source)
|
||||
{
|
||||
var target = new FlexibleFloat();
|
||||
CopyFlexibleFloat(target, source);
|
||||
return target;
|
||||
}
|
||||
private void CopyFlexibleFloat(FlexibleFloat target, FlexibleFloat source)
|
||||
{
|
||||
target.animations = new List<AnimatedFloat>();
|
||||
foreach (var a in source.animations)
|
||||
{
|
||||
AnimatedFloat animatedFloat = new AnimatedFloat(a.startTime + TimeOffset, a.endTime + TimeOffset, a.startValue, a.endValue, a.animationCurveType);
|
||||
target.animations.Add(animatedFloat);
|
||||
}
|
||||
}
|
||||
protected override void UpdateAnimation(float songTime)
|
||||
{
|
||||
if (targetSwirl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var a = GetCurrentReturnTypes(songTime);
|
||||
var (x, y, z) = (a[0], a[1], a[2]);
|
||||
|
||||
if (x.Item1 is FlexibleReturnType.MiddleExecuting ||
|
||||
y.Item1 is FlexibleReturnType.MiddleExecuting ||
|
||||
z.Item1 is FlexibleReturnType.MiddleExecuting)
|
||||
eulerAngleX.UpdateFlexibleFloat(songTime);
|
||||
eulerAngleY.UpdateFlexibleFloat(songTime);
|
||||
eulerAngleZ.UpdateFlexibleFloat(songTime);
|
||||
if (eulerAngleX.returnType is FlexibleReturnType.MiddleExecuting ||
|
||||
eulerAngleY.returnType is FlexibleReturnType.MiddleExecuting ||
|
||||
eulerAngleZ.returnType is FlexibleReturnType.MiddleExecuting)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
ApplyValue(songTime);
|
||||
isSwitchingReturnType = true;
|
||||
}
|
||||
else if (isSwitchingReturnType)
|
||||
else if (eulerAngleX.isSwitchingReturnType || eulerAngleY.isSwitchingReturnType || eulerAngleZ.isSwitchingReturnType)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
isSwitchingReturnType = false;
|
||||
ApplyValue(songTime);
|
||||
}
|
||||
else
|
||||
@@ -63,10 +130,9 @@ namespace Ichni.RhythmGame
|
||||
animationReturnType = FlexibleReturnType.MiddleInterval;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyValue(float time)
|
||||
{
|
||||
Vector3 currentEulerAngles = targetSwirl.getValue(time + TimeOffset);
|
||||
Vector3 currentEulerAngles = new Vector3(eulerAngleX.value, eulerAngleY.value, eulerAngleZ.value);
|
||||
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentEulerAngles);
|
||||
targetTransformSubmodule.eulerAnglesOffset += currentEulerAngles;
|
||||
targetTransformSubmodule.eulerAnglesDirtyMark = true;
|
||||
@@ -78,7 +144,11 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
public override Vector3 getValue(float time)
|
||||
{
|
||||
Vector3 currentEulerAngles = targetSwirl.getValue(time + TimeOffset);
|
||||
Vector3 currentEulerAngles = new Vector3(
|
||||
eulerAngleX.GetValue(time + TimeOffset),
|
||||
eulerAngleY.GetValue(time + TimeOffset),
|
||||
eulerAngleZ.GetValue(time + TimeOffset)
|
||||
);
|
||||
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentEulerAngles);
|
||||
return currentEulerAngles;
|
||||
}
|
||||
@@ -123,29 +193,12 @@ namespace Ichni.RhythmGame
|
||||
public bool MaybeDeadLoop = true;
|
||||
public void SaveExportBM()
|
||||
{
|
||||
Refresh();
|
||||
SaveBM();
|
||||
MatchingExportElement = matchedBM;
|
||||
float finalTimeOffset = 0;
|
||||
Swirl swirl = GetOriginSwirlWithOffset(ref finalTimeOffset);
|
||||
swirl.SaveBM();
|
||||
var x = ((Swirl_BM)swirl.matchedBM).eulerAngleX.DeepCopyBM();
|
||||
var y = ((Swirl_BM)swirl.matchedBM).eulerAngleY.DeepCopyBM();
|
||||
var z = ((Swirl_BM)swirl.matchedBM).eulerAngleZ.DeepCopyBM();
|
||||
x.ApplyTimeOffset(finalTimeOffset); y.ApplyTimeOffset(finalTimeOffset); z.ApplyTimeOffset(finalTimeOffset);
|
||||
|
||||
List<ICanBeTrackedSwirl> ICanBeTrackedSwirls = new List<ICanBeTrackedSwirl> { this as ICanBeTrackedSwirl };
|
||||
while (MaybeDeadLoop && ICanBeTrackedSwirls[0] is not Swirl)
|
||||
{
|
||||
ICanBeTrackedSwirl ao = (ICanBeTrackedSwirls[0] as SwirlTracker).targetSwirl;
|
||||
ICanBeTrackedSwirls.Insert(0, ao);
|
||||
}
|
||||
ICanBeTrackedSwirls.ForEach(o =>
|
||||
{
|
||||
((IHaveVector3Interferometer)o).ApplyVector3InterferometersBM(x, y, z);
|
||||
});
|
||||
parentElement.SaveBM();
|
||||
Swirl_BM a = new Swirl_BM("Swirl", elementGuid, new List<string>(), parentElement.matchedBM as GameElement_BM,
|
||||
x, y, z);
|
||||
var a = new Swirl_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
|
||||
eulerAngleX.ConvertToBM(), eulerAngleY.ConvertToBM(), eulerAngleZ.ConvertToBM());
|
||||
MatchingExportElement = a;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace Ichni.RhythmGame
|
||||
public bool isSwitchingReturnType;
|
||||
public FlexibleReturnType lastReturnType;
|
||||
public FlexibleReturnType returnType;
|
||||
public event Action OnDataChanged;
|
||||
|
||||
public FlexibleFloat(bool withFirstAnimation = false)
|
||||
{
|
||||
@@ -71,11 +72,14 @@ namespace Ichni.RhythmGame
|
||||
public void Add(AnimatedFloat animatedFloat)
|
||||
{
|
||||
animations.Add(animatedFloat);
|
||||
OnDataChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void Sort()
|
||||
{
|
||||
animations.Sort();
|
||||
OnDataChanged?.Invoke();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Ichni.RhythmGame
|
||||
public partial class EnvironmentObject : SubstantialObject
|
||||
{
|
||||
public bool isStatic;
|
||||
|
||||
|
||||
public static EnvironmentObject GenerateElement(string elementName, Guid id, List<string> tags,
|
||||
bool isFirstGenerated, string themeBundleName, string objectName, GameElement parentElement, bool isStatic)
|
||||
{
|
||||
@@ -52,7 +52,12 @@ namespace Ichni.RhythmGame
|
||||
var generateAnimation = container.GenerateSubcontainer(3);
|
||||
var generateBaseColorChangeButton = inspector.GenerateButton(this, generateAnimation, "Base Color Change",
|
||||
() => BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this, new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
|
||||
this,
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
|
||||
));
|
||||
if (haveEmissionColor)
|
||||
{
|
||||
var generateEmissionColorChangeButton = inspector.GenerateButton(this, generateAnimation, "Emission Color Change",
|
||||
|
||||
@@ -130,7 +130,12 @@ namespace Ichni.RhythmGame
|
||||
StandardInspectionElement.GenerateForTransform(this, container);
|
||||
var generateBaseColorChangeButton = inspector.GenerateButton(this, generateAnimation, "Base Color Change",
|
||||
() => BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this, new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)));
|
||||
this,
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace Ichni.RhythmGame
|
||||
public class NoteManager : MonoBehaviour
|
||||
{
|
||||
public List<(NoteBase note, float activationTime, float finishTime)> pendingNotes = new List<(NoteBase, float, float)>();
|
||||
private int nextNoteIndex = 0;
|
||||
private List<(NoteBase note1, bool isActive, float activationTime)> ProcessingNotes = new List<(NoteBase, bool, float)>();
|
||||
public void RegisterNote(NoteBase note, float activationTime, float finishTime)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user