添加PositionSync正在考虑本体对策

Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
2026-07-16 10:55:30 +08:00
parent c16c2480ff
commit be0290372f
142 changed files with 6157247 additions and 123045 deletions

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
namespace Ichni.RhythmGame.Beatmap
{
public class PositionSync_BM : GameElement_BM
{
public FlexibleBool_BM enabling;
public Guid syncTargetObjectGuid;
public PositionSync_BM()
{
}
public PositionSync_BM(string elementName, Guid elementGuid, List<string> tags,
GameElement_BM attachedElement, FlexibleBool_BM enabling, Guid syncTargetObjectGuid)
: base(elementName, elementGuid, tags, attachedElement)
{
this.enabling = enabling;
this.syncTargetObjectGuid = syncTargetObjectGuid;
}
public override void ExecuteBM()
{
matchedElement = PositionSync.GenerateElement(elementName, elementGuid, tags, false,
GetElement(attachedElementGuid), GetElement(syncTargetObjectGuid), enabling.ConvertToGameType());
matchedElement.matchedBM = this;
}
public override GameElement DuplicateBM(GameElement parent)
{
return PositionSync.GenerateElement(elementName, Guid.NewGuid(), tags, false, parent,
GetElement(syncTargetObjectGuid), enabling.ConvertToGameType());
}
public override void AfterExecute()
{
(matchedElement as PositionSync).syncTargetObject = GetElement(syncTargetObjectGuid);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 95b5b1be02575774f9c399b637cfcf12

View File

@@ -0,0 +1,43 @@
using System.Linq;
using Ichni.Editor;
using UnityEngine;
namespace Ichni.RhythmGame
{
public partial class PositionSync
{
public override void SetUpInspector()
{
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
IHaveInspection inspection = inspectorMain;
var nameRef = new ElementRef<DynamicUIInputField>();
InspectorBuilder.For(this)
.Section("Position Sync")
.UnboundInputField("Try Get Element").WithRef(nameRef)
.Button("Connect Transform Element", () =>
{
GameElement found = EditorManager.instance.beatmapContainer.gameElementList
.Where(e => e is IHaveTransformSubmodule)
.FirstOrDefault(e => e.elementName == nameRef.Value?.GetValue<string>());
if (found == null)
{
LogWindow.Log("Transform Game Element not found.", Color.yellow);
return;
}
syncTargetObject = found;
inspectorMain.SetInspector(this);
})
.HintText(() => syncTargetObject == null
? "No Transform Game Element Connected"
: "Connected With: " + syncTargetObject.elementName)
.Button("Enabling", () =>
{
inspection.GenerateCompositeParameterWindow(this, "Enabling", nameof(enabling))
.SetAsFlexibleBool();
})
.Build();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8ee62caf923c281469adfc5cff298929

View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using Ichni.Editor;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
/// <summary>
/// Synchronizes this element's world position to another transform-bearing element.
/// The target world position is converted back into this element parent's local space.
/// </summary>
public partial class PositionSync : AnimationBase, IExportOverride
{
#region [] Property Caches
public TransformSubmodule targetTransformSubmodule;
public GameElement syncTargetObject;
public FlexibleBool enabling;
#endregion
#region [] Generation & Initialization
public static PositionSync GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement animatedObject,
GameElement syncTargetObject, FlexibleBool enabling)
{
PositionSync sync = Instantiate(EditorManager.instance.basePrefabs.emptyObject).AddComponent<PositionSync>();
sync.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
sync.animatedObject = animatedObject;
sync.syncTargetObject = syncTargetObject;
sync.enabling = enabling;
sync.animationReturnType = FlexibleReturnType.Before;
sync.targetTransformSubmodule = (animatedObject as IHaveTransformSubmodule)?.transformSubmodule;
CoreServices.UpdateScheduler.Register(UpdatePhase.Effect, sync);
return sync;
}
public override void SetDefaultSubmodules()
{
timeDurationSubmodule = new TimeDurationSubmodule(this);
}
public override void OnDelete()
{
base.OnDelete();
CoreServices.UpdateScheduler.Unregister(UpdatePhase.Effect, this);
if (targetTransformSubmodule != null)
{
targetTransformSubmodule.positionDirtyMark = true;
}
}
#endregion
#region [] Animation Update
public override void ScheduledUpdate(UpdatePhase phase, float songTime)
{
base.ScheduledUpdate(phase, songTime);
if (phase == UpdatePhase.Effect && enabling != null && enabling.value)
{
ApplyPositionSync();
}
}
protected override void UpdateAnimation(float songTime)
{
if (enabling == null)
{
animationReturnType = FlexibleReturnType.None;
return;
}
enabling.UpdateFlexibleBool(songTime);
if (enabling.value)
{
animationReturnType = FlexibleReturnType.MiddleExecuting;
if (targetTransformSubmodule != null)
{
targetTransformSubmodule.positionDirtyMark = true;
}
}
else if (animationReturnType != FlexibleReturnType.MiddleInterval)
{
animationReturnType = FlexibleReturnType.MiddleInterval;
if (targetTransformSubmodule != null)
{
targetTransformSubmodule.positionDirtyMark = true;
}
}
}
private void ApplyPositionSync()
{
if (targetTransformSubmodule == null || syncTargetObject == null) return;
if (syncTargetObject is not IHaveTransformSubmodule) return;
Transform self = targetTransformSubmodule.attachedGameElement.transform;
Transform parent = self.parent;
Vector3 targetWorldPosition = syncTargetObject.transform.position;
Vector3 desiredLocalPosition = parent != null
? parent.InverseTransformPoint(targetWorldPosition)
: targetWorldPosition;
Vector3 existingLocalOffset = targetTransformSubmodule.currentPosition - targetTransformSubmodule.originalPosition;
Vector3 syncOffset = desiredLocalPosition - targetTransformSubmodule.originalPosition + existingLocalOffset;
targetTransformSubmodule.positionOffset += syncOffset;
targetTransformSubmodule.positionDirtyMark = true;
(targetTransformSubmodule.attachedGameElement as IHaveTransformSubmodule)?.UpdateTransform(false);
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
enabling?.animations.ForEach(anim => anim.ApplyTimeOffset(offset));
}
public void OnDestroy()
{
if (targetTransformSubmodule != null)
{
targetTransformSubmodule.positionDirtyMark = true;
}
}
#endregion
#region [] Serialize & BM
public override void SaveBM()
{
matchedBM = new PositionSync_BM(elementName, elementGuid, tags, parentElement.matchedBM as GameElement_BM,
enabling.ConvertToBM(), syncTargetObject != null ? syncTargetObject.elementGuid : Guid.Empty);
}
public BaseElement_BM GetExportElement()
{
string message = $"PositionSync cannot be exported before baking is implemented. Element: {elementName}";
LogWindow.Log(message, Color.red);
Debug.LogError(message);
throw new InvalidOperationException(message);
}
#endregion
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c8e0717920cb3b547966d49d9d686146

View File

@@ -108,7 +108,7 @@ namespace Ichni.RhythmGame
base.UpdateNoteInStaticTrack(songTime);
if (noteVisual is INoteVisualHold noteVisualHold)
{
noteVisualHold.UpdateHoldInStaticTrack();
noteVisualHold.UpdateHoldInStaticTrack(songTime);
}
}
#endregion
@@ -252,4 +252,4 @@ namespace Ichni.RhythmGame
}
#endregion
}
}
}

View File

@@ -14,7 +14,7 @@ namespace Ichni.RhythmGame
}
public virtual void UpdateHoldInStaticTrack()
public virtual void UpdateHoldInStaticTrack(float songTime)
{
}
@@ -24,6 +24,6 @@ namespace Ichni.RhythmGame
{
public Hold hold { get; set; }
public void UpdateHoldInMovableTrack();
public void UpdateHoldInStaticTrack();
public void UpdateHoldInStaticTrack(float songTime);
}
}