Files
ichni_Official/Assets/Scripts/Game/Animations/Custom/PropertyAnimationVector3.cs
SoulliesOfficial 1bc9af280b 同步
2026-04-03 10:53:11 -04:00

153 lines
5.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class PropertyAnimationVector3 : AnimationBase
{
#region [] Exposed Fields & References
public string componentName;
public string propertyName;
public FlexibleFloat propertyValueX, propertyValueY, propertyValueZ;
private Component targetComponent;
private FieldInfo targetField;
private PropertyInfo targetProperty;
// 高性能赋值委托
private Action<Vector3> vectorSetterDelegate;
#endregion
#region [] Lifecycle & Factory
public static PropertyAnimationVector3 GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
GameElement animatedObject, string componentName, string propertyName,
FlexibleFloat propertyValueX, FlexibleFloat propertyValueY, FlexibleFloat propertyValueZ)
{
PropertyAnimationVector3 animation = Instantiate(GameManager.Instance.basePrefabs.emptyObject)
.AddComponent<PropertyAnimationVector3>();
animation.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
animation.animatedObject = animatedObject;
animation.componentName = componentName;
animation.propertyName = propertyName;
animation.propertyValueX = propertyValueX;
animation.propertyValueY = propertyValueY;
animation.propertyValueZ = propertyValueZ;
return animation;
}
public override void AfterInitialize()
{
if (animatedObject == null || string.IsNullOrEmpty(componentName)) return;
Type componentType = GetTypeFromAllAssemblies(componentName);
if (componentType != null)
{
targetComponent = animatedObject.GetComponentInChildren(componentType);
}
if (targetComponent != null)
{
InitializeReflection();
}
else
{
Debug.LogWarning($"[PropertyAnimationVector3] Cannot find Component '{componentName}' strictly on '{animatedObject.name}'.");
}
base.AfterInitialize();
}
private Type GetTypeFromAllAssemblies(string typeName)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type type = assembly.GetType(typeName);
if (type != null) return type;
}
return null;
}
private void InitializeReflection()
{
Type type = targetComponent.GetType();
targetProperty = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (targetProperty != null && targetProperty.CanWrite)
{
MethodInfo setMethod = targetProperty.GetSetMethod(nonPublic: true);
if (setMethod != null && targetProperty.PropertyType == typeof(Vector3))
{
try
{
vectorSetterDelegate = (Action<Vector3>)Delegate.CreateDelegate(typeof(Action<Vector3>), targetComponent, setMethod);
return;
}
catch { }
}
}
targetField = type.GetField(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (targetField == null && targetProperty == null)
{
Debug.LogWarning($"[PropertyAnimationVector3] Cannot find target Property or Field '{propertyName}' strictly on '{componentName}'.");
}
}
#endregion
#region [] Core Animation Logic
protected override void UpdateAnimation(float songTime, bool forceUpdate)
{
if (targetComponent == null) return;
propertyValueX?.UpdateFlexibleFloat(songTime);
propertyValueY?.UpdateFlexibleFloat(songTime);
propertyValueZ?.UpdateFlexibleFloat(songTime);
float x = propertyValueX != null ? propertyValueX.value : 0f;
float y = propertyValueY != null ? propertyValueY.value : 0f;
float z = propertyValueZ != null ? propertyValueZ.value : 0f;
Vector3 targetVector = new Vector3(x, y, z);
if (vectorSetterDelegate != null)
{
vectorSetterDelegate(targetVector);
}
else if (targetProperty != null)
{
targetProperty.SetValue(targetComponent, targetVector);
}
else if (targetField != null)
{
targetField.SetValue(targetComponent, targetVector);
}
if (animatedObject is IHaveDirtyMarkSubmodule dirtyTarget)
{
dirtyTarget.dirtyMarkSubmodule.MarkDirty(propertyName);
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
void ApplyOffset(FlexibleFloat ff)
{
if (ff == null || ff.animations == null) return;
foreach(var a in ff.animations) { a.startTime += offset; a.endTime += offset; }
}
ApplyOffset(propertyValueX);
ApplyOffset(propertyValueY);
ApplyOffset(propertyValueZ);
}
#endregion
}
}