Substantial Object生成调整

可以正确的生成NoteVisual
This commit is contained in:
SoulliesOfficial
2025-02-22 01:56:33 -05:00
parent f941ca7dbc
commit 935cbbb029
37 changed files with 11095 additions and 154 deletions

View File

@@ -211,7 +211,7 @@ namespace Ichni.Editor
float x = xs + (xe - xs) / loop * i;
float y = ys + (ye - ys) / loop * i;
float z = zs + (ze - zs) / loop * i;
PathNode j = PathNode.GenerateElement("PathNode" + i.ToString(), Guid.NewGuid(), new List<string>(), true, track);
PathNode j = PathNode.GenerateElement("PathNode" + i.ToString(), Guid.NewGuid(), new List<string>(), true, track, true);
j.transformSubmodule.originalPosition = new Vector3(x, y, z);
}

View File

@@ -45,7 +45,6 @@ namespace Ichni.RhythmGame
List<EffectBase> effectList = new List<EffectBase>();
foreach (var effectBM in effect.Value)
{
Debug.Log(attachedGameElement.GetType().ToString());
effectList.Add(effectBM.ConvertToGameType(attachedGameElement));
}
effectCollection.Add(effect.Key, effectList);

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using Dreamteck.Splines;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using Unity.VisualScripting;
@@ -52,6 +53,18 @@ namespace Ichni.RhythmGame
{
matchedBM = new Tap_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, exactJudgeTime);
}
public override void SetUpInspector()
{
base.SetUpInspector();
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Generate");
var generateNoteVisualButton = inspector.GenerateButton(this, container, "Generate Note Visual", () =>
{
TemporaryObject.GenerateElement("New Note Visual", Guid.NewGuid(), new List<string>(), true, this);
});
}
}
namespace Beatmap

View File

@@ -21,10 +21,22 @@ namespace Ichni.RhythmGame
GameObject themeBundleObject = ThemeBundleManager.instance.GetObject<GameObject>(themeBundleName, objectName);
SubstantialObject substantialObject = Instantiate(themeBundleObject, parentElement.transform).GetComponent<SubstantialObject>();
substantialObject.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
substantialObject.themeBundleName = themeBundleName;
substantialObject.objectName = objectName;
substantialObject.FirstSetUpObject(isFirstGenerated);
return substantialObject;
}
/// <summary>
/// 初次生成继承自SubstantialObject的对象时生成方法必然使用SubstantialObject中的GenerateElement方法。
/// 因此对于需要进行特殊处理的子类需要重写FirstSetUpObject方法。
/// 在读取Beatmap时生成物体则使用子类本身的GenerateElement方法。
/// </summary>
public virtual void FirstSetUpObject(bool isFirstGenerated)
{
}
protected override void SetDefaultSubmodules()
{
transformSubmodule = new TransformSubmodule(this);

View File

@@ -54,7 +54,7 @@ namespace Ichni.RhythmGame
{
Delete();
inspectorMain.ClearInspector();
SubstantialObject.GenerateElement(elementName, elementGuid, tags, false, themeBundleName, objectName, parentElement);
SubstantialObject.GenerateElement(elementName, elementGuid, tags, true, themeBundleName, objectName, parentElement);
});
if (themeBundleName == String.Empty || objectName == String.Empty)

View File

@@ -14,18 +14,20 @@ namespace Ichni.RhythmGame
public partial class PathNode : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule, IHaveColorSubmodule
{
public Track track;
public int index => track.trackPathSubmodule.pathNodeList.IndexOf(this);
public SplinePoint node;
public int index => track.trackPathSubmodule.pathNodeList.IndexOf(this);
public TransformSubmodule transformSubmodule { get; set; }
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
public ColorSubmodule colorSubmodule { get; set; }
public bool haveEmission => false;
[Title("Editor独有参数")]
[SerializeField] [HideInPlayMode]
private GameObject pathNodeSphere;
public bool isShowingSphere;
public static PathNode GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
Track track)
Track track, bool isShowingSphere)
{
PathNode pathNode = Instantiate(EditorManager.instance.basePrefabs.pathNode, track.transform)
.GetComponent<PathNode>();
@@ -33,6 +35,8 @@ namespace Ichni.RhythmGame
pathNode.Initialize(elementName, id, tags, isFirstGenerated, track);
pathNode.track = track;
pathNode.isShowingSphere = isShowingSphere;
pathNode.SetPathNodeSphere(isShowingSphere);
track.trackPathSubmodule.pathNodeList.Add(pathNode);
return pathNode;
@@ -78,7 +82,13 @@ namespace Ichni.RhythmGame
{
public override void SaveBM()
{
matchedBM = new Beatmap.PathNode_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM);
matchedBM = new Beatmap.PathNode_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM, isShowingSphere);
}
public void SetPathNodeSphere(bool isShowing)
{
isShowingSphere = isShowing;
pathNodeSphere.SetActive(isShowing);
}
public override void SetUpInspector()
@@ -89,6 +99,8 @@ namespace Ichni.RhythmGame
var container = inspector.GenerateContainer("Path Node");
var indexText = inspector.GenerateHintText(this, container, "Index: " + index);
var isShowingSphereToggle = inspector.GenerateToggle(this, container, "Is Showing Sphere", nameof(isShowingSphere));
isShowingSphereToggle.AddListenerFunction(SetPathNodeSphere);
}
}
@@ -96,26 +108,28 @@ namespace Ichni.RhythmGame
{
public class PathNode_BM : GameElement_BM
{
public bool isShowingSphere;
public PathNode_BM()
{
}
public PathNode_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement)
public PathNode_BM(string elementName, Guid elementGuid, List<string> tags, GameElement_BM attachedElement,
bool isShowingSphere)
: base(elementName, elementGuid, tags, attachedElement)
{
this.isShowingSphere = isShowingSphere;
}
public override void ExecuteBM()
{
matchedElement = PathNode.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid) as Track);
GetElement(attachedElementGuid) as Track, isShowingSphere);
}
public override GameElement DuplicateBM(GameElement parent)
{
return PathNode.GenerateElement(elementName, elementGuid, tags, false, parent as Track);
return PathNode.GenerateElement(elementName, elementGuid, tags, false, parent as Track, isShowingSphere);
}
}
}

View File

@@ -75,35 +75,35 @@ namespace Ichni.RhythmGame
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
base.SetUpInspector();
var container = inspector.GenerateContainer("Track");
var trackPathButton = inspector.GenerateButton(this, container, "Track Path",
var trackSubmodulesContainer = inspector.GenerateContainer("Track Submodules"); //次级模块
var trackPathButton = inspector.GenerateButton(this, trackSubmodulesContainer, "Track Path",
() =>
{
trackPathSubmodule = new TrackPathSubmodule(this, TrackSpaceType.CatmullRom,
TrackSamplingType.TimeDistributed, false);
inspectorMain.SetInspector(this);
});
var trackTimeMovableButton = inspector.GenerateButton(this, container, "Track Time Movable",
var trackTimeMovableButton = inspector.GenerateButton(this, trackSubmodulesContainer, "Track Time Movable",
() =>
{
trackTimeSubmodule = new TrackTimeSubmoduleMovable(this, 0, 1, 1, AnimationCurveType.Linear);
inspectorMain.SetInspector(this);
});
var trackTimeStaticButton = inspector.GenerateButton(this, container, "Track Time Static",
var trackTimeStaticButton = inspector.GenerateButton(this, trackSubmodulesContainer, "Track Time Static",
() =>
{
trackTimeSubmodule = new TrackTimeSubmoduleStatic(this, 1, AnimationCurveType.Linear);
inspectorMain.SetInspector(this);
});
var trackRendererAutoOrientButton = inspector.GenerateButton(this, container, "Track Renderer Auto Orient",
var trackRendererAutoOrientButton = inspector.GenerateButton(this, trackSubmodulesContainer, "Track Renderer Auto Orient",
() =>
{
trackRendererSubmodule = new TrackRendererSubmoduleAutoOrient(this);
inspectorMain.SetInspector(this);
});
var trackRendererPathGeneratorButton = inspector.GenerateButton(this, container,
var trackRendererPathGeneratorButton = inspector.GenerateButton(this, trackSubmodulesContainer,
"Track Renderer Path Generator",
() =>
{
@@ -131,21 +131,70 @@ namespace Ichni.RhythmGame
trackRendererSubmodule.SetUpInspector();
}
var displacementButton = inspector.GenerateButton(this, container, "Displacement",
var generateContainer = inspector.GenerateContainer("Generate Elements"); //物体生成
var pathNodeButton = inspector.GenerateButton(this, generateContainer, "Path Node",
() =>
{
PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, this, true);
}); //路径点
var trackPercentPointButton = inspector.GenerateButton(this, generateContainer, "Track Percent Point",
() =>
{
TrackPercentPoint.GenerateElement("New Track Percent Point", Guid.NewGuid(), new List<string>(),
true, this, new FlexibleFloat());
}); //百分比点
var trackHeadPointButton = inspector.GenerateButton(this, generateContainer, "Track Head Point",
() =>
{
TrackHeadPoint.GenerateElement("New Track Head Point", Guid.NewGuid(), new List<string>(),
true, this);
}); //头部点必须先有TrackTimeSubmoduleMovable
if (trackTimeSubmodule is not TrackTimeSubmoduleMovable) trackHeadPointButton.button.interactable = false;
var tapButton = inspector.GenerateButton(this, generateContainer, "Tap",
() =>
{
Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f);
}); //Note Tap
var stayButton = inspector.GenerateButton(this, generateContainer, "Stay",
() =>
{
Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f);
}); //Note Stay
// var holdButton = inspector.GenerateButton(this, generateContainer, "Hold",
// () =>
// {
// Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f);
// }); //Note Hold
var flickButton = inspector.GenerateButton(this, generateContainer, "Flick",
() =>
{
Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f,
new List<Vector2>());
}); //Note Flick
var displacementButton = inspector.GenerateButton(this, generateContainer, "Displacement",
() =>
{
Displacement.GenerateElement("New Displacement", Guid.NewGuid(), new List<string>(), true, this,
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat());
});
}); //位移
var swirlButton = inspector.GenerateButton(this, container, "Swirl",
var swirlButton = inspector.GenerateButton(this, generateContainer, "Swirl",
() =>
{
Swirl.GenerateElement("New Swirl", Guid.NewGuid(), new List<string>(), true, this,
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat());
});
}); //旋转
var QuickCopyButton = inspector.GenerateButton(this, container, "QuickCopy", () =>
var toolsContainerTrack = inspector.GenerateContainer("Track Tools"); //轨道(整体)快捷工具
var quickCopyButton = inspector.GenerateButton(this, toolsContainerTrack, "QuickCopy", () =>
{
IHaveInspection qcWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Quick Copy");
var qcContainer = qcWindow.GenerateContainer();
@@ -163,9 +212,72 @@ namespace Ichni.RhythmGame
bool includeAnimation = includeAnimationToggle.toggle.isOn;
QuickCopy(positionOffset, timeOffset, includeAnimation, iteration);
});
}); //快速复制
var wholeTrackMoveButton = inspector.GenerateButton(this, toolsContainerTrack, "Whole Track Move", () =>
{
IHaveInspection wholeMoveWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Whole Track Move");
var wmContainer = wholeMoveWindow.GenerateContainer();
var xField = wholeMoveWindow.GenerateGetterInputField(wmContainer, "X offset", "0");
var yField = wholeMoveWindow.GenerateGetterInputField(wmContainer, "Y offset", "0");
var zField = wholeMoveWindow.GenerateGetterInputField(wmContainer, "Z offset", "0");
wholeMoveWindow.GenerateButton(this, wmContainer, "Move", () =>
{
Vector3 positionOffset = new Vector3(xField.GetResult<float>(), yField.GetResult<float>(), zField.GetResult<float>());
WholeTrackMove(positionOffset);
});
}); //整体移动
var wholeTrackSwirlButton = inspector.GenerateButton(this, toolsContainerTrack, "Whole Track Swirl", () =>
{
IHaveInspection wholeSwirlWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Whole Track Swirl");
var wsContainer = wholeSwirlWindow.GenerateContainer();
var angleField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Angle", "0");
var centerXField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Center X", "0");
var centerYField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Center Y", "0");
var centerZField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Center Z", "0");
var axisDirXField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Axis Direction X", "0");
var axisDirYField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Axis Direction Y", "0");
var axisDirZField = wholeSwirlWindow.GenerateGetterInputField(wsContainer, "Axis Direction Z", "0");
wholeSwirlWindow.GenerateButton(this, wsContainer, "Swirl", () =>
{
float angle = angleField.GetResult<float>();
Vector3 center = new Vector3(centerXField.GetResult<float>(), centerYField.GetResult<float>(), centerZField.GetResult<float>());
Vector3 axisDirection = new Vector3(axisDirXField.GetResult<float>(), axisDirYField.GetResult<float>(), axisDirZField.GetResult<float>());
WholeTrackSwirl(angle, center, axisDirection);
});
}); //整体旋转
var wholeTrackFlipButton = inspector.GenerateButton(this, toolsContainerTrack, "Whole Track Flip", () =>
{
IHaveInspection wholeFlipWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Whole Track Flip");
var wfContainer = wholeFlipWindow.GenerateContainer();
var axisStartXField = wholeFlipWindow.GenerateGetterInputField(wfContainer, "Axis Start X", "0");
var axisStartYField = wholeFlipWindow.GenerateGetterInputField(wfContainer, "Axis Start Y", "0");
var axisStartZField = wholeFlipWindow.GenerateGetterInputField(wfContainer, "Axis Start Z", "0");
var axisEndXField = wholeFlipWindow.GenerateGetterInputField(wfContainer, "Axis End X", "0");
var axisEndYField = wholeFlipWindow.GenerateGetterInputField(wfContainer, "Axis End Y", "0");
var axisEndZField = wholeFlipWindow.GenerateGetterInputField(wfContainer, "Axis End Z", "0");
wholeFlipWindow.GenerateButton(this, wfContainer, "Flip", () =>
{
Vector3 axisStart = new Vector3(axisStartXField.GetResult<float>(), axisStartYField.GetResult<float>(), axisStartZField.GetResult<float>());
Vector3 axisEnd = new Vector3(axisEndXField.GetResult<float>(), axisEndYField.GetResult<float>(), axisEndZField.GetResult<float>());
WholeTrackFlip(axisStart, axisEnd);
});
}); //整体翻转
var toolsContainerPathNode = inspector.GenerateContainer("Path Node Tools"); //路径点快捷工具
var setAllPathNodeSphereButton = inspector.GenerateButton(this, toolsContainerPathNode,
"Set All Path Node Sphere", () =>
{
bool firstPathNodeSphere = trackPathSubmodule.pathNodeList[0].isShowingSphere;
SetAllPathNodeSphere(!firstPathNodeSphere);
});
container.SetDeviver(1);
var setOnlyStartEndPathNodeSphereEnabledButton = inspector.GenerateButton(this, toolsContainerPathNode,
"Only Start & End Path Node's sphere enabled", SetOnlyStartEndPathNodeSphereEnabled);
trackSubmodulesContainer.SetDeviver(1);
}
}

View File

@@ -85,7 +85,7 @@ namespace Ichni.RhythmGame
isClosedToggle.AddListenerFunction(_ => ClosePath());
var generatePathNodeButton = inspector.GenerateButton(this, container, "Generate Path Node", () =>
{
PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, track);
PathNode.GenerateElement("New Path Node", Guid.NewGuid(), new List<string>(), true, track, true);
});
}
}

View File

@@ -4,7 +4,6 @@ using Dreamteck.Splines;
using Ichni.Editor;
using Unity.VisualScripting;
using UnityEngine;
using Inspector = Unity.VisualScripting.Inspector;
namespace Ichni.RhythmGame
{

View File

@@ -16,8 +16,8 @@ namespace Ichni.RhythmGame
/// <param name="iteration">迭代次数即产生几个粘贴的Track</param>
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1)
{
if(iteration <= 0) return;
if (iteration <= 0) return;
CopyPasteDeleteModule cpd = EditorManager.instance.operationManager.CopyPasteDeleteModule;
cpd.CopyElement(this);
for (int i = 1; i <= iteration; i++)
@@ -26,31 +26,34 @@ namespace Ichni.RhythmGame
Track newTrack = cpd.pastedElementList[0] as Track;
Vector3 positionOffset = unitPositionOffset * i;
float timeOffset = unitTimeOffset * i;
//对Track的所有有效的Submodule和子GameElement进行偏移
if (newTrack.trackTimeSubmodule is TrackTimeSubmoduleMovable movable)
{
movable.trackStartTime += timeOffset;
movable.trackEndTime += timeOffset;
}
//以下:对Track的所有有效的Submodule和子GameElement进行偏移 TODO: 需要思考是否有统一时间偏移的方法?
//PathNode位置偏移
newTrack.trackPathSubmodule.pathNodeList.ForEach(pn =>
{
pn.transformSubmodule.originalPosition += positionOffset;
pn.transformSubmodule.Refresh();
});
//TrackTimeSubmoduleMovable时间偏移
if (newTrack.trackTimeSubmodule is TrackTimeSubmoduleMovable movable)
{
movable.trackStartTime += timeOffset;
movable.trackEndTime += timeOffset;
}
//获取所有newTrack及之下所有layer的GameElement
List<GameElement> allNewGameElements = newTrack.GetAllGameElementsFromThis();
List<TrackPercentPoint> percentPoints = allNewGameElements
.FindAll(x => x is TrackPercentPoint).Cast<TrackPercentPoint>().ToList();
//TrackPercentPoint,时间偏移
List<TrackPercentPoint> percentPoints = allNewGameElements.FindAll(x => x is TrackPercentPoint).Cast<TrackPercentPoint>().ToList();
percentPoints.ForEach(pp =>
{
pp.trackPercent.animations.ForEach(anim => anim.ApplyTimeOffset(timeOffset));
});
//Note时间偏移
List<NoteBase> notes = allNewGameElements.FindAll(x => x is NoteBase).Cast<NoteBase>().ToList();
notes.ForEach(note =>
{
@@ -58,19 +61,97 @@ namespace Ichni.RhythmGame
note.Refresh();
});
//Animation时间偏移可以根据需要选择是否偏移
if (includeAnimations)
{
List<AnimationBase> animations = allNewGameElements
.FindAll(x => x.GetType().IsSubclassOf(typeof(AnimationBase))).Cast<AnimationBase>().ToList();
animations.ForEach(anim =>
{
anim.ApplyTimeOffset(timeOffset);
});
.FindAll(x => x is AnimationBase).Cast<AnimationBase>().ToList();
animations.ForEach(anim => { anim.ApplyTimeOffset(timeOffset); });
}
}
cpd.pastedElementList.Clear();
}
/// <summary>
/// Track整体移动
/// </summary>
/// <param name="positionOffset">坐标偏移量</param>
private void WholeTrackMove(Vector3 positionOffset)
{
trackPathSubmodule.pathNodeList.ForEach(pn =>
{
pn.transformSubmodule.originalPosition += positionOffset;
pn.transformSubmodule.Refresh();
});
}
/// <summary>
/// Track整体旋转
/// </summary>
/// <param name="angle">旋转角度,单位:度,方向:顺时针</param>
/// <param name="center">旋转中心</param>
/// <param name="axisDirection">旋转轴方向</param>
private void WholeTrackSwirl(float angle, Vector3 center, Vector3 axisDirection)
{
if (axisDirection == Vector3.zero)
{
LogWindow.Log("Axis direction cannot be zero!", Color.red);
return;
}
trackPathSubmodule.pathNodeList.ForEach(pn =>
{
Vector3 originalPosition = pn.transformSubmodule.originalPosition;
Vector3 rotatedPosition = Quaternion.AngleAxis(angle, axisDirection) * (originalPosition - center) + center;
pn.transformSubmodule.originalPosition = rotatedPosition;
pn.transformSubmodule.Refresh();
});
}
/// <summary>
/// Track整体翻转
/// </summary>
/// <param name="axisStart">翻转轴起点</param>
/// <param name="axisEnd">翻转轴终点</param>
private void WholeTrackFlip(Vector3 axisStart, Vector3 axisEnd)
{
trackPathSubmodule.pathNodeList.ForEach(pn =>
{
Vector3 originalPosition = pn.transformSubmodule.originalPosition;
Vector3 flippedPosition = Vector3.Reflect(originalPosition - axisStart, axisEnd - axisStart) + axisStart;
pn.transformSubmodule.originalPosition = flippedPosition;
pn.transformSubmodule.Refresh();
});
}
/// <summary>
/// 仅开启起点和终点的PathNode的Sphere显示中间的PathNode不显示
/// </summary>
private void SetOnlyStartEndPathNodeSphereEnabled()
{
if (trackPathSubmodule.pathNodeList.Count < 2)
{
LogWindow.Log("PathNode amount is less than 2!", Color.red);
return;
}
trackPathSubmodule.pathNodeList[0].SetPathNodeSphere(true);
trackPathSubmodule.pathNodeList[^1].SetPathNodeSphere(true);
for (int i = 1; i < trackPathSubmodule.pathNodeList.Count - 1; i++)
{
trackPathSubmodule.pathNodeList[i].SetPathNodeSphere(false);
}
}
/// <summary>
/// 批量开启或关闭所有PathNode的Sphere显示
/// </summary>
/// <param name="isShowing"></param>
private void SetAllPathNodeSphere(bool isShowing)
{
trackPathSubmodule.pathNodeList.ForEach(pn => pn.SetPathNodeSphere(isShowing));
}
}
}

View File

@@ -85,45 +85,5 @@ namespace Ichni
songInformation.SetUpInspector();
cameraManager.SetUpInspector();
}
private void CreateNew()
{
projectManager.GenerateProject("TestProject");
var f0 = ElementFolder.GenerateElement("Folder", Guid.NewGuid(), new List<string>(), true, null);
var dis0 = Displacement.GenerateElement("Displacement-0",Guid.NewGuid(), new List<string>(),true, f0,
new FlexibleFloat(),
new FlexibleFloat(new List<AnimatedFloat>(){new (0,2,0,10, AnimationCurveType.Linear)}),
new FlexibleFloat());
var dis1 = Displacement.GenerateElement("Displacement-1", Guid.NewGuid(), new List<string>(), true, f0,
new FlexibleFloat(new List<AnimatedFloat>()
{
new(0, 0.5f, 0, -4, AnimationCurveType.OutQuad),
new(0.5f, 1, -4, 0, AnimationCurveType.InQuad),
new(1, 1.5f, 0, 4, AnimationCurveType.OutQuad),
new(1.5f, 2, 4, 0, AnimationCurveType.InQuad),
}),
new FlexibleFloat(new List<AnimatedFloat>(){new (0,2,0,-10, AnimationCurveType.Linear)}),
new FlexibleFloat());
var t0 = Track.GenerateElement("Track", Guid.NewGuid(), new List<string>(), true, f0);
t0.trackPathSubmodule = new TrackPathSubmodule(t0, Track.TrackSpaceType.Linear, Track.TrackSamplingType.TimeDistributed, false);
t0.submoduleList.Add(t0.trackPathSubmodule);
t0.trackTimeSubmodule = new TrackTimeSubmoduleMovable(t0, 0, 2, 1, AnimationCurveType.OutQuad);
t0.submoduleList.Add(t0.trackTimeSubmodule);
var pp0 = TrackPercentPoint.GenerateElement("TrackPercentPoint-0", Guid.NewGuid(), new List<string>(), true, t0,
new FlexibleFloat(new List<AnimatedFloat>() { new(0, 2, 0, 1, AnimationCurveType.OutQuad) }));
var tr0 = Trail.GenerateElement("Trail-0", Guid.NewGuid(), new List<string>(), true, pp0, 5);
// t0.trackRendererSubmodule = new TrackRendererSubmoduleAutoOrient(t0);
var p0 = PathNode.GenerateElement("PathNode-0", Guid.NewGuid(), new List<string>(), true, t0);
p0.transformSubmodule = new TransformSubmodule(p0, new Vector3(-5, 5, 10), Vector3.zero, Vector3.one);
p0.colorSubmodule = new ColorSubmodule(p0, Color.white);
var p1 = PathNode.GenerateElement("PathNode-1", Guid.NewGuid(), new List<string>(), true, t0);
p1.transformSubmodule = new TransformSubmodule(p1, new Vector3(5, -5, 10), Vector3.zero, Vector3.one);
p1.colorSubmodule = new ColorSubmodule(p1, Color.red);
var n0 = Tap.GenerateElement("Note-0", Guid.NewGuid(), new List<string>(), true, t0, 1f);
var n0v = BasicNoteVisual.GenerateElement("Note-0-V", Guid.NewGuid(), new List<string>(), true, n0,
"basic", "BasicNoteTap3D");
}
}
}