TRACKER 1!!1

Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
2025-12-21 15:00:58 +08:00
parent 826f300f29
commit 7f4e339032
19 changed files with 790 additions and 4855 deletions

View File

@@ -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>())

View File

@@ -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)
{

View File

@@ -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
{

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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",

View File

@@ -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) })
));
}
}