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

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