大活:Tracker和Interferometer

等待改进
Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
2025-11-02 03:08:40 +08:00
parent eab38e36fe
commit 1280e32612
53 changed files with 3446 additions and 35373 deletions

View File

@@ -19,22 +19,36 @@ namespace Ichni.Editor
var displacementButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Displacement", () =>
{
Displacement.GenerateElement("New Displacement", Guid.NewGuid(), new List<string>(), true, gameElement,
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat());
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
}); //位移
var swirlButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Swirl", () =>
{
Swirl.GenerateElement("New Swirl", Guid.NewGuid(), new List<string>(), true, gameElement,
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat());
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
}); //旋转
var scaleButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Scale", () =>
{
Scale.GenerateElement("New Scale", Guid.NewGuid(), new List<string>(), true, gameElement,
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat());
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
}); //缩放
var LookAtButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Look At",
() => LookAt.GenerateElement("New Look At", Guid.NewGuid(),
new List<string>(), true, gameElement, null, new FlexibleBool()));
var displacementTrackerButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Displacement Tracker", () =>
{
DisplacementTracker.GenerateElement("New Displacement Tracker", Guid.NewGuid(), new List<string>(), true, gameElement,
null, 0f);
});
var swirlTrackerButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Swirl Tracker", () =>
{
SwirlTracker.GenerateElement("New Swirl Tracker", Guid.NewGuid(), new List<string>(), true, gameElement,
null, 0f);
}); var ScaleTrackerButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Scale Tracker", () =>
{
ScaleTracker.GenerateElement("New Scale Tracker", Guid.NewGuid(), new List<string>(), true, gameElement,
null, 0f);
});
}
public static void GenerateForLoading()
{

View File

@@ -12,7 +12,6 @@ namespace Ichni.RhythmGame
public FlexibleReturnType animationReturnType;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
@@ -47,6 +46,10 @@ namespace Ichni.RhythmGame
{
return Vector3.zero;
}
public virtual FlexibleReturnType getReturnType(float time)
{
return animationReturnType;
}
/// <summary>
/// 施加时间偏移即移动所有Flexible参数的时间
/// </summary>

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c59ac55bda5746b429dea11680098277
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 43c59b01d1d25b9448e5a5fecbc7e989
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public enum InterferomType
{
Additive,
Multiplicative,
Override
}
public abstract class InterferometerBase : GameElement, IHaveTimeDurationSubmodule, IBeChangeInExport
{
public AnimationBase parentAnimationElement;
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public BaseElement_BM MatchingExportElement { get; set; }
public virtual void SaveExportBM()
{
MatchingExportElement = null;
}
public InterferomType InterferomType;
}
public interface IBeChangeInExport
{
public BaseElement_BM MatchingExportElement { get; set; }
void SaveExportBM();
}
public interface IHaveInterferometer
{
public List<InterferometerBase> Interferometers { get; set; }
}
public interface IHaveVector3Interferometer : IHaveInterferometer
{
public void ApplyVector3Interferometers(ref Vector3 value)
{
foreach (Vector3Interferometer interferometer in Interferometers.OfType<Vector3Interferometer>())
{
interferometer.InterferomValue(ref value);
}
}
public void ApplyVector3InterferometersBM(FlexibleFloat_BM X, FlexibleFloat_BM Y, FlexibleFloat_BM Z)
{
foreach (Vector3Interferometer interferometer in Interferometers.OfType<Vector3Interferometer>())
{
interferometer.InterferomValueBM(X, Y, Z);
}
}
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 40784921009324241a68ffc3b2ed7fcf
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,147 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Beatmap;
using Ichni.Editor;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class Vector3Interferometer : InterferometerBase
{
public static Vector3Interferometer GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, AnimationBase parentAnimationElement,
InterferomType interferomType, Vector3 interferomValue)
{
Vector3Interferometer vector3Interferometer = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<Vector3Interferometer>();
vector3Interferometer.Initialize(elementName, id, tags, isFirstGenerated, parentAnimationElement);
vector3Interferometer.parentAnimationElement = parentAnimationElement;
vector3Interferometer.InterferomType = interferomType;
vector3Interferometer.InterferomValueVector3 = interferomValue;
if (isFirstGenerated) vector3Interferometer.timeDurationSubmodule = new TimeDurationSubmodule(vector3Interferometer, false, parentAnimationElement.timeDurationSubmodule.startTime, parentAnimationElement.timeDurationSubmodule.endTime);
if (parentAnimationElement is IHaveVector3Interferometer haveVector3Interferometer)
{
haveVector3Interferometer.Interferometers.Add(vector3Interferometer);
}
else
{
Debug.LogError("Trying to add Vector3Interferometer to an AnimationBase that does not implement IHaveVector3Interferometer.");
Destroy(vector3Interferometer.gameObject);
return null;
}
return vector3Interferometer;
}
public Vector3 InterferomValueVector3;
public virtual void InterferomValue(ref Vector3 value)
{
switch (InterferomType)
{
case InterferomType.Additive:
// Additive: add interferometer effect to the current value (placeholder)
value += InterferomValueVector3;
break;
case InterferomType.Multiplicative:
// Multiplicative: multiply current value by interferometer effect (placeholder)
value = Vector3.Scale(value, InterferomValueVector3);
break;
case InterferomType.Override:
// Override: replace current value with interferometer effect (placeholder)
value = InterferomValueVector3;
break;
default:
break;
}
}
public void InterferomValueBM(FlexibleFloat_BM X, FlexibleFloat_BM Y, FlexibleFloat_BM Z)
{
void tmpoffset(FlexibleFloat_BM a, int point)
{
foreach (var anim in a.animatedFloatList)
{
switch (InterferomType)
{
case InterferomType.Additive:
anim.endValue += InterferomValueVector3[point];
anim.startValue += InterferomValueVector3[point];
break;
case InterferomType.Multiplicative:
anim.endValue *= InterferomValueVector3[point];
anim.startValue *= InterferomValueVector3[point];
break;
case InterferomType.Override:
anim.endValue = InterferomValueVector3[point];
anim.startValue = InterferomValueVector3[point];
break;
default:
break;
}
}
}
tmpoffset(X, 0);
tmpoffset(Y, 1);
tmpoffset(Z, 2);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Vector3 Interferometer");
var subcontainer = container.GenerateSubcontainer(1);
inspector.GenerateVector3InputField(this, subcontainer, "Interferom Value", nameof(InterferomValueVector3));
inspector.GenerateDropdown(this, subcontainer, "Interferom Type", typeof(InterferomType), nameof(InterferomType));
}
public override void SaveBM()
{
matchedBM = new Vector3Interferometer_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
InterferomType, InterferomValueVector3);
}
private void OnDestroy()
{
((IHaveVector3Interferometer)parentElement)?.Interferometers.Remove(this);
}
}
}
namespace Beatmap
{
public class Vector3Interferometer_BM : AnimationBase_BM, ICanNotInExport
{
public Vector3 InterferomValueVector3;
public InterferomType InterferomType;
public Vector3Interferometer_BM() { }
public Vector3Interferometer_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, InterferomType interferomType, Vector3 interferomValue)
: base(elementName, elementGuid, tags, attachedElement)
{
this.InterferomType = interferomType;
this.InterferomValueVector3 = interferomValue;
}
public override void ExecuteBM()
{
matchedElement = Vector3Interferometer.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as AnimationBase, InterferomType, InterferomValueVector3);
}
public override GameElement DuplicateBM(GameElement parent)
{
return Vector3Interferometer.GenerateElement(elementName, Guid.NewGuid(), tags, false,
parent as AnimationBase, InterferomType, InterferomValueVector3);
}
}
public interface ICanNotInExport { }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef1be148d7f177a419f2de084f657248
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,212 @@
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;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class DisplacementTracker : AnimationBase, IBeChangeInExport, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedDisplacement
{
private TransformSubmodule targetTransformSubmodule;
public ICanBeTrackedDisplacement targetDisplacement;
public Vector3 PreviewValue = Vector3.zero;
public float TimeOffset;
public BaseElement_BM MatchingExportElement { get; set; } = null;
public List<InterferometerBase> Interferometers { get; set; } = new();
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.TimeOffset = timeOffset;
tracker.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
return tracker;
}
protected override void UpdateAnimation(float songTime)
{
if (targetDisplacement == 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)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
ApplyValue(songTime);
}
else if (x.Item2 || y.Item2 || z.Item2)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
ApplyValue(songTime);
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
{
ApplyValue(songTime);
}
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
private void ApplyValue(float time)
{
Vector3 currentPosition = targetDisplacement.getValue(time + TimeOffset);
// 用接口强制调用默认实现
((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);
((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");
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Displacement", () =>
{
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;
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));
}
public override void SaveBM()
{
matchedBM = new DisplacementTracker_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
((GameElement)targetDisplacement).elementGuid, TimeOffset);
}
public bool MaybeDeadLoop = true;
public void SaveExportBM()
{
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);
List<ICanBeTrackedDisplacement> ICanBeTrackedDisplacements = new List<ICanBeTrackedDisplacement> { this as ICanBeTrackedDisplacement };
while (MaybeDeadLoop && ICanBeTrackedDisplacements[0] is not Displacement)
{
ICanBeTrackedDisplacement ao = (ICanBeTrackedDisplacements[0] as DisplacementTracker).targetDisplacement;
ICanBeTrackedDisplacements.Insert(0, ao);
}
ICanBeTrackedDisplacements.ForEach(o =>
{
((IHaveVector3Interferometer)o).ApplyVector3InterferometersBM(x, y, z);
});
parentElement.SaveBM();
Displacement_BM a = new Displacement_BM("Displacement", elementGuid, new List<string>(), parentElement.matchedBM as GameElement_BM,
x, y, z);
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.");
}
}
}
public interface ICanBeTracked
{
Vector3 getValue(float time);
(FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time);
}
public interface ICanBeTrackedDisplacement : ICanBeTracked
{
Displacement GetOriginDisplacementWithOffset(ref float timeOffset);
}
}
namespace Beatmap
{
public class DisplacementTracker_BM : AnimationBase_BM, ICanNotInExport
{
public Guid targetDisplacementGuid;
public float timeOffset;
public DisplacementTracker_BM() { }
public DisplacementTracker_BM(string elementName, System.Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, Guid targetDisplacementGuid, float timeOffset)
: base(elementName, elementGuid, tags, attachedElement)
{
this.targetDisplacementGuid = targetDisplacementGuid;
this.timeOffset = timeOffset;
}
public override void ExecuteBM()
{
matchedElement = DisplacementTracker.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(targetDisplacementGuid) as Displacement, timeOffset);
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return DisplacementTracker.GenerateElement(elementName, System.Guid.NewGuid(), tags, false, parent,
GetElement(targetDisplacementGuid) as Displacement, timeOffset);
}
public override void AfterExecute()
{
(matchedElement as DisplacementTracker).targetDisplacement = GetElement(targetDisplacementGuid) as ICanBeTrackedDisplacement;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d87960788a4be94e87ff13bb81625cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Beatmap;
using Ichni;
using Ichni.Editor;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class ScaleTracker : AnimationBase, IBeChangeInExport, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedScale
{
private TransformSubmodule targetTransformSubmodule;
public ICanBeTrackedScale targetScale;
public Vector3 PreviewValue = Vector3.zero;
public float TimeOffset;
public BaseElement_BM MatchingExportElement { get; set; } = null;
public List<InterferometerBase> Interferometers { get; set; } = new();
public static ScaleTracker GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject, ICanBeTrackedScale targetScale, float timeOffset)
{
ScaleTracker tracker = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<ScaleTracker>();
tracker.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
tracker.animatedObject = animatedObject;
tracker.targetScale = targetScale;
tracker.TimeOffset = timeOffset;
tracker.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
return tracker;
}
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)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
ApplyValue(songTime);
}
else if (x.Item2 || y.Item2 || z.Item2)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
ApplyValue(songTime);
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
{
ApplyValue(songTime);
}
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
private void ApplyValue(float time)
{
Vector3 currentScale = targetScale.getValue(time + TimeOffset);
((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);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentScale);
return currentScale;
}
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 Scale");
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Scale", () =>
{
ICanBeTrackedScale targetElement = EditorManager.instance.beatmapContainer.gameElementList.OfType<ICanBeTrackedScale>()
.First(e => ((GameElement)e).elementName == connectedGameElementInputField.GetValue<string>());
if (targetElement == null)
{
LogWindow.Log("Game Element not found.", Color.yellow);
}
targetScale = targetElement;
inspectorMain.SetInspector(this);
});
string ShowConnection() => targetScale == null ? "No Scale Connected" : "Connected With: " + ((GameElement)targetScale).elementName;
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
var InputField = inspector.GenerateInputField(this, effectSettings, "Offset", nameof(TimeOffset));
}
public override void SaveBM()
{
matchedBM = new ScaleTracker_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
((GameElement)targetScale).elementGuid, TimeOffset);
}
public bool MaybeDeadLoop = true;
public void SaveExportBM()
{
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);
MatchingExportElement = a;
}
public Scale GetOriginScaleWithOffset(ref float timeOffset)
{
timeOffset += TimeOffset;
if (targetScale is Scale scale)
{
return scale;
}
else if (targetScale is ScaleTracker scaleTracker)
{
return scaleTracker.GetOriginScaleWithOffset(ref timeOffset);
}
else
{
throw new Exception("WTF type of tracked scale.");
}
}
}
public interface ICanBeTrackedScale : ICanBeTracked
{
Scale GetOriginScaleWithOffset(ref float timeOffset);
}
}
namespace Beatmap
{
public class ScaleTracker_BM : AnimationBase_BM, ICanNotInExport
{
public Guid targetScaleGuid;
public float timeOffset;
public ScaleTracker_BM() { }
public ScaleTracker_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, Guid targetScaleGuid, float timeOffset)
: base(elementName, elementGuid, tags, attachedElement)
{
this.targetScaleGuid = targetScaleGuid;
this.timeOffset = timeOffset;
}
public override void ExecuteBM()
{
matchedElement = ScaleTracker.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(targetScaleGuid) as ICanBeTrackedScale, timeOffset);
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return ScaleTracker.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(targetScaleGuid) as ICanBeTrackedScale, timeOffset);
}
public override void AfterExecute()
{
(matchedElement as ScaleTracker).targetScale = GetElement(targetScaleGuid) as ICanBeTrackedScale;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 771a58a2b0d89ca4d9440f8463a03ff2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Beatmap;
using Ichni;
using Ichni.Editor;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class SwirlTracker : AnimationBase, IBeChangeInExport, IHaveVector3Interferometer, IHaveTimeDurationSubmodule, ICanBeTrackedSwirl
{
private TransformSubmodule targetTransformSubmodule;
public ICanBeTrackedSwirl targetSwirl;
public Vector3 PreviewValue = Vector3.zero;
public float TimeOffset;
public BaseElement_BM MatchingExportElement { get; set; } = null;
public List<InterferometerBase> Interferometers { get; set; } = new();
public static SwirlTracker GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject, Swirl targetSwirl, float timeOffset)
{
SwirlTracker tracker = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<SwirlTracker>();
tracker.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
tracker.animatedObject = animatedObject;
tracker.targetSwirl = targetSwirl;
tracker.TimeOffset = timeOffset;
tracker.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
return tracker;
}
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)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
ApplyValue(songTime);
}
else if (x.Item2 || y.Item2 || z.Item2)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
ApplyValue(songTime);
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
{
ApplyValue(songTime);
}
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
private void ApplyValue(float time)
{
Vector3 currentEulerAngles = targetSwirl.getValue(time + TimeOffset);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentEulerAngles);
targetTransformSubmodule.eulerAnglesOffset += currentEulerAngles;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
PreviewValue = currentEulerAngles;
}
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
return targetSwirl.GetCurrentReturnTypes(time + TimeOffset);
}
public override Vector3 getValue(float time)
{
Vector3 currentEulerAngles = targetSwirl.getValue(time + TimeOffset);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentEulerAngles);
return currentEulerAngles;
}
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 Swirl");
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Swirl", () =>
{
ICanBeTrackedSwirl targetElement = EditorManager.instance.beatmapContainer.gameElementList.OfType<ICanBeTrackedSwirl>()
.First(e => ((GameElement)e).elementName == connectedGameElementInputField.GetValue<string>());
if (targetElement == null)
{
LogWindow.Log("Game Element not found.", Color.yellow);
}
targetSwirl = targetElement;
inspectorMain.SetInspector(this);
});
string ShowConnection() => targetSwirl == null ? "No Swirl Connected" : "Connected With: " + ((GameElement)targetSwirl).elementName;
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
var InputField = inspector.GenerateInputField(this, effectSettings, "Offset", nameof(TimeOffset));
}
public override void SaveBM()
{
matchedBM = new SwirlTracker_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
((GameElement)targetSwirl).elementGuid, TimeOffset);
}
public bool MaybeDeadLoop = true;
public void SaveExportBM()
{
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);
MatchingExportElement = a;
}
public Swirl GetOriginSwirlWithOffset(ref float timeOffset)
{
timeOffset += TimeOffset;
if (targetSwirl is Swirl swirl)
{
return swirl;
}
else if (targetSwirl is SwirlTracker swirlTracker)
{
return swirlTracker.GetOriginSwirlWithOffset(ref timeOffset);
}
else
{
throw new Exception("WTF type of tracked swirl.");
}
}
}
public interface ICanBeTrackedSwirl : ICanBeTracked
{
Swirl GetOriginSwirlWithOffset(ref float timeOffset);
}
}
namespace Beatmap
{
public class SwirlTracker_BM : AnimationBase_BM, ICanNotInExport
{
public Guid targetSwirlGuid;
public float timeOffset;
public SwirlTracker_BM() { }
public SwirlTracker_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, Guid targetSwirlGuid, float timeOffset)
: base(elementName, elementGuid, tags, attachedElement)
{
this.targetSwirlGuid = targetSwirlGuid;
this.timeOffset = timeOffset;
}
public override void ExecuteBM()
{
matchedElement = SwirlTracker.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(targetSwirlGuid) as Swirl, timeOffset);
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return SwirlTracker.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(targetSwirlGuid) as Swirl, timeOffset);
}
public override void AfterExecute()
{
(matchedElement as SwirlTracker).targetSwirl = GetElement(targetSwirlGuid) as ICanBeTrackedSwirl;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fa441a41a13cc794cb909abea76cd7a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -12,11 +12,13 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Displacement : AnimationBase
public partial class Displacement : AnimationBase, IHaveVector3Interferometer, ICanBeTrackedDisplacement
{
private TransformSubmodule targetTransformSubmodule;
public FlexibleFloat positionX, positionY, positionZ;
public List<InterferometerBase> Interferometers { get; set; } = new List<InterferometerBase>();
public Vector3 PreviewValue = Vector3.zero;
public static Displacement GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
FlexibleFloat positionX, FlexibleFloat positionY, FlexibleFloat positionZ)
@@ -33,7 +35,6 @@ namespace Ichni.RhythmGame
displacement.animationReturnType = FlexibleReturnType.Before;
displacement.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule).transformSubmodule;
//displacement.timeDurationSubmodule.SetDuration(positionX, positionY, positionZ);
return displacement;
@@ -50,36 +51,43 @@ namespace Ichni.RhythmGame
positionZ.returnType is FlexibleReturnType.MiddleExecuting)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
Vector3 currentPosition = new Vector3(positionX.value, positionY.value, positionZ.value);
targetTransformSubmodule.positionOffset += currentPosition;
targetTransformSubmodule.positionDirtyMark = true;
ApplyValue();
}
else if (positionX.isSwitchingReturnType || positionY.isSwitchingReturnType || positionZ.isSwitchingReturnType)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
Vector3 currentPosition = new Vector3(positionX.value, positionY.value, positionZ.value);
targetTransformSubmodule.positionOffset += currentPosition;
targetTransformSubmodule.positionDirtyMark = true;
ApplyValue();
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
{
Vector3 currentPosition = new Vector3(positionX.value, positionY.value, positionZ.value);
targetTransformSubmodule.positionOffset += currentPosition;
targetTransformSubmodule.positionDirtyMark = true;
ApplyValue();
}
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
private void ApplyValue()
{
Vector3 currentPosition = new Vector3(positionX.value, positionY.value, positionZ.value);
// 用接口强制调用默认实现
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentPosition);
targetTransformSubmodule.positionOffset += currentPosition;
targetTransformSubmodule.positionDirtyMark = true;
PreviewValue = currentPosition;
}
public override Vector3 getValue(float time)
{
float x = positionX.GetValue(time);
float y = positionY.GetValue(time);
float z = positionZ.GetValue(time);
return new Vector3(x, y, z);
Vector3 currentPosition = new Vector3(x, y, z);
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentPosition);
return currentPosition;
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
@@ -87,6 +95,21 @@ namespace Ichni.RhythmGame
positionY.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
positionZ.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
(FlexibleReturnType, bool) x = positionX.getReturnType(time);
(FlexibleReturnType, bool) y = positionY.getReturnType(time);
(FlexibleReturnType, bool) z = positionZ.getReturnType(time);
return new (FlexibleReturnType, bool)[] { x, y, z };
}
public Displacement GetOriginDisplacementWithOffset(ref float timeOffset)
{
return this;
}
public BaseElement_BM MatchingExportElement { get; set; }
}
public partial class Displacement
@@ -120,6 +143,24 @@ namespace Ichni.RhythmGame
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Displacement",
new FlexibleFloat[] { positionX, positionY, positionZ }, new string[] { "PosX", "PosY", "PosZ" });
});
var subcontainer2 = container.GenerateSubcontainer(1);
var valuetext = inspector.GenerateParameterText(this, subcontainer2, "value:", nameof(PreviewValue), true);
var interferometerButton = inspector.GenerateButton(this, subcontainer2, "Interferometer", () =>
{
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
this, InterferomType.Additive, Vector3.zero);
});
}
public void SaveExportBM()
{
SaveBM();
MatchingExportElement = matchedBM;
((IHaveVector3Interferometer)this).ApplyVector3InterferometersBM(
(MatchingExportElement as Beatmap.Displacement_BM).positionX,
(MatchingExportElement as Beatmap.Displacement_BM).positionY,
(MatchingExportElement as Beatmap.Displacement_BM).positionZ);
}
}

View File

@@ -7,11 +7,18 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Scale : AnimationBase
public partial class Scale : AnimationBase, IHaveVector3Interferometer, IBeChangeInExport, ICanBeTrackedScale
{
public TransformSubmodule targetTransformSubmodule;
public FlexibleFloat scaleX, scaleY, scaleZ;
public List<InterferometerBase> Interferometers { get; set; } = new List<InterferometerBase>();
public BaseElement_BM MatchingExportElement { get; set; }
public Vector3 PreviewValue = Vector3.zero;
public static Scale GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
FlexibleFloat scaleX, FlexibleFloat scaleY, FlexibleFloat scaleZ)
@@ -50,29 +57,33 @@ namespace Ichni.RhythmGame
scaleZ.returnType is FlexibleReturnType.MiddleExecuting)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value);
targetTransformSubmodule.scaleOffset += currentScale;
targetTransformSubmodule.scaleDirtyMark = true;
ApplyValue();
}
else if (scaleX.isSwitchingReturnType || scaleY.isSwitchingReturnType || scaleZ.isSwitchingReturnType)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value);
targetTransformSubmodule.scaleOffset += currentScale;
targetTransformSubmodule.scaleDirtyMark = true;
ApplyValue();
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
{
Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value);
targetTransformSubmodule.scaleOffset += currentScale;
targetTransformSubmodule.scaleDirtyMark = true;
ApplyValue();
}
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
private void ApplyValue()
{
Vector3 currentScale = new Vector3(scaleX.value, scaleY.value, scaleZ.value);
// 用接口强制调用默认实现
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentScale);
targetTransformSubmodule.scaleOffset += currentScale;
targetTransformSubmodule.scaleDirtyMark = true;
PreviewValue = currentScale;
}
public override Vector3 getValue(float time)
{
float x = scaleX.GetValue(time);
@@ -80,6 +91,26 @@ namespace Ichni.RhythmGame
float z = scaleZ.GetValue(time);
return new Vector3(x, y, z);
}
public override FlexibleReturnType getReturnType(float time)
{
(FlexibleReturnType, bool) x = scaleX.getReturnType(time);
(FlexibleReturnType, bool) y = scaleY.getReturnType(time);
(FlexibleReturnType, bool) z = scaleZ.getReturnType(time);
if (x.Item1 is FlexibleReturnType.MiddleExecuting ||
y.Item1 is FlexibleReturnType.MiddleExecuting ||
z.Item1 is FlexibleReturnType.MiddleExecuting)
{
return FlexibleReturnType.MiddleExecuting;
}
else if (x.Item2 || x.Item2 || x.Item2)
{
return FlexibleReturnType.MiddleExecuting;
}
else
{
return FlexibleReturnType.MiddleInterval;
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
@@ -87,6 +118,18 @@ namespace Ichni.RhythmGame
scaleY.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
scaleZ.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
(FlexibleReturnType, bool) x = scaleX.getReturnType(time);
(FlexibleReturnType, bool) y = scaleY.getReturnType(time);
(FlexibleReturnType, bool) z = scaleZ.getReturnType(time);
return new (FlexibleReturnType, bool)[] { x, y, z };
}
public Scale GetOriginScaleWithOffset(ref float timeOffset)
{
return this;
}
}
public partial class Scale
@@ -96,6 +139,15 @@ namespace Ichni.RhythmGame
matchedBM = new Scale_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
scaleX.ConvertToBM(), scaleY.ConvertToBM(), scaleZ.ConvertToBM());
}
public void SaveExportBM()
{
SaveBM();
MatchingExportElement = matchedBM;
((IHaveVector3Interferometer)this).ApplyVector3InterferometersBM(
(MatchingExportElement as Scale_BM).scaleX,
(MatchingExportElement as Scale_BM).scaleY,
(MatchingExportElement as Scale_BM).scaleZ);
}
public override void SetUpInspector()
{
@@ -121,6 +173,14 @@ namespace Ichni.RhythmGame
new FlexibleFloat[] { scaleX, scaleY, scaleZ },
new string[] { "ScaleX", "ScaleY", "ScaleZ" });
});
var subcontainer2 = container.GenerateSubcontainer(1);
var valuetext = inspector.GenerateParameterText(this, subcontainer2, "value:", nameof(PreviewValue), true);
var interferometerButton = inspector.GenerateButton(this, subcontainer2, "Interferometer", () =>
{
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
this, InterferomType.Additive, Vector3.zero);
});
}
}

View File

@@ -8,10 +8,15 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class Swirl : AnimationBase
public partial class Swirl : AnimationBase, IHaveVector3Interferometer, IBeChangeInExport, ICanBeTrackedSwirl
{
private TransformSubmodule targetTransformSubmodule;
public FlexibleFloat eulerAngleX, eulerAngleY, eulerAngleZ;
public List<InterferometerBase> Interferometers { get; set; } = new List<InterferometerBase>();
public Vector3 PreviewValue = Vector3.zero;
public BaseElement_BM MatchingExportElement { get; set; }
public static Swirl GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
@@ -49,29 +54,33 @@ namespace Ichni.RhythmGame
eulerAngleZ.returnType is FlexibleReturnType.MiddleExecuting)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
Vector3 currentEulerAngles = new Vector3(eulerAngleX.value, eulerAngleY.value, eulerAngleZ.value);
targetTransformSubmodule.eulerAnglesOffset += currentEulerAngles;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
ApplyValue();
}
else if (eulerAngleX.isSwitchingReturnType || eulerAngleY.isSwitchingReturnType || eulerAngleZ.isSwitchingReturnType)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
Vector3 currentEulerAngles = new Vector3(eulerAngleX.value, eulerAngleY.value, eulerAngleZ.value);
targetTransformSubmodule.eulerAnglesOffset += currentEulerAngles;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
ApplyValue();
}
else
{
if (!EditorManager.instance.musicPlayer.isPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
{
Vector3 currentRotation = new Vector3(eulerAngleX.value, eulerAngleY.value, eulerAngleZ.value);
targetTransformSubmodule.eulerAnglesOffset += currentRotation;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
ApplyValue();
}
animationReturnType = FlexibleReturnType.MiddleInterval;
}
}
private void ApplyValue()
{
Vector3 currentEulerAngles = new Vector3(eulerAngleX.value, eulerAngleY.value, eulerAngleZ.value);
// 用接口强制调用默认实现
((IHaveVector3Interferometer)this).ApplyVector3Interferometers(ref currentEulerAngles);
targetTransformSubmodule.eulerAnglesOffset += currentEulerAngles;
targetTransformSubmodule.eulerAnglesDirtyMark = true;
PreviewValue = currentEulerAngles;
}
public override Vector3 getValue(float time)
{
float x = eulerAngleX.GetValue(time);
@@ -79,6 +88,26 @@ namespace Ichni.RhythmGame
float z = eulerAngleZ.GetValue(time);
return new Vector3(x, y, z);
}
public override FlexibleReturnType getReturnType(float time)
{
(FlexibleReturnType, bool) x = eulerAngleX.getReturnType(time);
(FlexibleReturnType, bool) y = eulerAngleY.getReturnType(time);
(FlexibleReturnType, bool) z = eulerAngleZ.getReturnType(time);
if (x.Item1 is FlexibleReturnType.MiddleExecuting ||
y.Item1 is FlexibleReturnType.MiddleExecuting ||
z.Item1 is FlexibleReturnType.MiddleExecuting)
{
return FlexibleReturnType.MiddleExecuting;
}
else if (x.Item2 || x.Item2 || x.Item2)
{
return FlexibleReturnType.MiddleExecuting;
}
else
{
return FlexibleReturnType.MiddleInterval;
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
@@ -86,6 +115,19 @@ namespace Ichni.RhythmGame
eulerAngleY.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
eulerAngleZ.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
public (FlexibleReturnType, bool)[] GetCurrentReturnTypes(float time)
{
(FlexibleReturnType, bool) x = eulerAngleX.getReturnType(time);
(FlexibleReturnType, bool) y = eulerAngleY.getReturnType(time);
(FlexibleReturnType, bool) z = eulerAngleZ.getReturnType(time);
return new (FlexibleReturnType, bool)[] { x, y, z };
}
public Swirl GetOriginSwirlWithOffset(ref float timeOffset)
{
return this;
}
}
public partial class Swirl
@@ -96,6 +138,16 @@ namespace Ichni.RhythmGame
eulerAngleX.ConvertToBM(), eulerAngleY.ConvertToBM(), eulerAngleZ.ConvertToBM());
}
public void SaveExportBM()
{
SaveBM();
MatchingExportElement = matchedBM;
((IHaveVector3Interferometer)this).ApplyVector3InterferometersBM(
(MatchingExportElement as Swirl_BM).eulerAngleX,
(MatchingExportElement as Swirl_BM).eulerAngleY,
(MatchingExportElement as Swirl_BM).eulerAngleZ);
}
public override void SetUpInspector()
{
base.SetUpInspector();
@@ -121,6 +173,14 @@ namespace Ichni.RhythmGame
new FlexibleFloat[] { eulerAngleX, eulerAngleY, eulerAngleZ },
new string[] { "EulerX", "EulerY", "EulerZ" });
});
var subcontainer2 = container.GenerateSubcontainer(1);
var valuetext = inspector.GenerateParameterText(this, subcontainer2, "value:", nameof(PreviewValue), true);
var interferometerButton = inspector.GenerateButton(this, subcontainer2, "Interferometer", () =>
{
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
this, InterferomType.Additive, Vector3.zero);
});
}
}

View File

@@ -53,11 +53,16 @@ namespace Ichni.RhythmGame
public FlexibleReturnType lastReturnType;
public FlexibleReturnType returnType;
public FlexibleFloat()
public FlexibleFloat(bool withFirstAnimation = false)
{
animations = new List<AnimatedFloat>();
if (withFirstAnimation)
{
animations.Add(new AnimatedFloat(0f, 1f, 0f, 0f, AnimationCurveType.Linear));
}
}
public FlexibleFloat(List<AnimatedFloat> anim)
{
animations = anim;
@@ -198,9 +203,18 @@ namespace Ichni.RhythmGame
{
UpdateFlexibleFloat(songtime);
float a = value;
UpdateFlexibleFloat(EditorManager.instance.songInformation.songTime);
return a;
}
public (FlexibleReturnType, bool) getReturnType(float Songtime)
{
UpdateFlexibleFloat(Songtime);
return (returnType, isSwitchingReturnType);
}
public (FlexibleReturnType, bool, float) GetReturnTypeAndValue(float songtime)
{
UpdateFlexibleFloat(songtime);
return (returnType, isSwitchingReturnType, value);
}
/// <summary>
/// 转换为Beatmap存档类型
/// </summary>
@@ -216,6 +230,14 @@ namespace Ichni.RhythmGame
return flexibleFloat_BM;
}
public void ApplyTimeOffset(float OffsetTime)
{
animations.ForEach(i =>
{
i.ApplyTimeOffset(OffsetTime);
});
}
}
namespace Beatmap
@@ -259,6 +281,26 @@ namespace Ichni.RhythmGame
return flexibleFloat;
}
public FlexibleFloat_BM DeepCopyBM()
{
FlexibleFloat_BM copy = new FlexibleFloat_BM();
foreach (AnimatedFloat animatedFloat in animatedFloatList)
{
copy.animatedFloatList.Add(new AnimatedFloat(
animatedFloat.startTime, animatedFloat.endTime,
animatedFloat.startValue, animatedFloat.endValue,
animatedFloat.animationCurveType));
}
return copy;
}
public void ApplyTimeOffset(float OffsetTime)
{
animatedFloatList.ForEach(i =>
{
i.ApplyTimeOffset(OffsetTime);
});
}
}
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Beatmap;
using Ichni.RhythmGame.Beatmap;
using UniRx;
using UnityEngine;
@@ -9,7 +10,7 @@ using UnityEngine.Events;
namespace Ichni.RhythmGame
{
public class BeatmapContainer : IBaseElement
public class BeatmapContainer : IBaseElement, IBeChangeInExport
{
public List<GameElement> gameElementList;
@@ -17,6 +18,7 @@ namespace Ichni.RhythmGame
public List<UnityAction> lowPriorityActions;
public BaseElement_BM matchedBM { get; set; }
public BaseElement_BM MatchingExportElement { get; set; }
public BeatmapContainer()
{
@@ -72,6 +74,15 @@ namespace Ichni.RhythmGame
}
public void SaveExportBM()
{
MatchingExportElement = new BeatmapContainer_BM(gameElementList, true);
if (((BeatmapContainer_BM)MatchingExportElement).elementList.Any(i => i is ICanNotInExport))
{
Debug.LogError("Export Error!");
}
}
}
namespace Beatmap
@@ -86,7 +97,7 @@ namespace Ichni.RhythmGame
}
public BeatmapContainer_BM(List<GameElement> gameElementList)
public BeatmapContainer_BM(List<GameElement> gameElementList, bool forExport = false)
{
elementList = new List<BaseElement_BM>();
@@ -95,18 +106,39 @@ namespace Ichni.RhythmGame
e.SaveBM();
e.submoduleList.RemoveAll(s => s == null);
e.submoduleList.ForEach(s => s.SaveBM());
if (forExport && e is IBeChangeInExport changeInExport)
{
changeInExport.SaveExportBM();
}
});
foreach (var gameElement in gameElementList)
{
if (gameElement.matchedBM != null)
{
elementList.Add(gameElement.matchedBM);
}
if (forExport && gameElement is IBeChangeInExport changeInExport)
{
if (changeInExport.MatchingExportElement != null)
{
elementList.Add(changeInExport.MatchingExportElement);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
submodules.ForEach(e => { e.attachedElementGuid = ((GameElement_BM)changeInExport.MatchingExportElement).elementGuid; });
elementList.AddRange(submodules);
}
}
else
{
elementList.Add(gameElement.matchedBM);
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
elementList.AddRange(submodules);
}
List<BaseElement_BM> submodules = gameElement.submoduleList.ConvertAll(s => s.matchedBM);
submodules.RemoveAll(s => s == null);
elementList.AddRange(submodules);
}
}
}

View File

@@ -74,7 +74,10 @@ namespace Ichni.RhythmGame
var generateAnimation = container.GenerateSubcontainer(3);
var fovAnimationButton = inspector.GenerateButton(this, generateAnimation, "Field of View",
() => CameraFieldOfView.GenerateElement("New Field of View", Guid.NewGuid(),
new List<string>(), true, this, new FlexibleFloat()));
new List<string>(), true, this, new FlexibleFloat(new List<AnimatedFloat>
{
new AnimatedFloat(0f, 1f, 60f, 60f, AnimationCurveType.Linear)
})));
var extensionButton = inspector.GenerateButton(this, generateAnimation, "Extension",
() => GameCameraExtension.GenerateElement("New Extension", Guid.NewGuid(),
new List<string>(), true, this, 1000f));

View File

@@ -130,7 +130,7 @@ 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(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
this, new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)));
}
}

View File

@@ -189,7 +189,7 @@ namespace Ichni.RhythmGame
StandardInspectionElement.GenerateForTransform(this, generateContainer); //关于有Transform的元素
inspector.GenerateButton(this, particleSubcontainer, "Track Global Color Change",
() => { TrackGlobalColorChange.GenerateElement("New Track Global Color Change", Guid.NewGuid(), new List<string>(), true, this, new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()); }); //变量容器
() => { TrackGlobalColorChange.GenerateElement("New Track Global Color Change", Guid.NewGuid(), new List<string>(), true, this, new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true)); }); //变量容器
// var animationSubcontainer = generateContainer.GenerateSubcontainer(3);
// var displacementButton = inspector.GenerateButton(this, animationSubcontainer, "Displacement", () =>

View File

@@ -94,8 +94,8 @@ namespace Ichni
private void ExportBeatMap(string exportPath)
{
EditorManager.instance.beatmapContainer.SaveBM();
ES3.Save("Beatmap", EditorManager.instance.beatmapContainer.matchedBM as BeatmapContainer_BM,
EditorManager.instance.beatmapContainer.SaveExportBM();
ES3.Save("Beatmap", EditorManager.instance.beatmapContainer.MatchingExportElement as BeatmapContainer_BM,
exportPath, ProjectManager.ExportSettings);
}

View File

@@ -56,10 +56,15 @@ namespace Ichni
{
AssetBundle.UnloadAllAssetBundles(true);
loadedThemeBundleList.Clear();
LogWindow = StartMenuManager.instance.startPage.logText;
if (InformationTransistor.instance.isRecovery)
{
LogWindow.text += "Recovery Mode.\n";
LogWindow.color = Color.red;
}
LogWindow.text += "Loading ThemeBundles, Please wait...\n";
waitingBundleAmount = new IntReactiveProperty(list.Count);
Debug.Log("Waiting for " + list.Count + " AssetBundles to load.");
LogWindow.text += "Waiting for " + list.Count + " AssetBundles to load.\n";
@@ -120,7 +125,7 @@ namespace Ichni
AssetBundle bundle = AssetBundle.LoadFromFile(uri);
Object[] ob = bundle.LoadAllAssets<Object>();
loadedThemeBundleList.Add(new ThemeBundle(themeBundleName));
for (int i = 0; i < ob.Length; i++)
{
if (ob[i].GetType() == typeof(GameObject))

View File

@@ -4,6 +4,7 @@ using Ichni.RhythmGame.Beatmap;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
@@ -33,6 +34,10 @@ namespace Ichni.StartMenu
InformationTransistor.instance.isLoadedProject = true;
InformationTransistor.instance.loadedProjectName = projectName;
InformationTransistor.instance.isRecovery = isRecovery;
if (Keyboard.current.sKey.isPressed && Keyboard.current.lKey.isPressed)
{
InformationTransistor.instance.isRecovery = true;
}
string projectPath = Application.streamingAssetsPath + "/Projects/" + projectName;
InformationTransistor.instance.projectInfo_BM = ES3.Load<ProjectInformation_BM>("ProjectInformation", projectPath + "/ProjectInfo.json");