@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95b5b1be02575774f9c399b637cfcf12
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ee62caf923c281469adfc5cff298929
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8e0717920cb3b547966d49d9d686146
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user