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

146 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Reflection;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
namespace Ichni.RhythmGame
{
public class PropertyAnimationFloat : AnimationBase
{
#region [] Exposed Fields & References
public string componentName;
public string propertyName;
public FlexibleFloat propertyValue;
private Component targetComponent;
private FieldInfo targetField;
private PropertyInfo targetProperty;
// 我们尝试通过原生的 Action 来降低反射 SetValue 带来的性能损耗装箱与GC
private Action<float> floatSetterDelegate;
#endregion
#region [] Lifecycle & Factory
public static PropertyAnimationFloat GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
GameElement animatedObject, string componentName, string propertyName, FlexibleFloat propertyValue)
{
PropertyAnimationFloat animation = Instantiate(GameManager.Instance.basePrefabs.emptyObject)
.AddComponent<PropertyAnimationFloat>();
animation.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
animation.animatedObject = animatedObject;
animation.componentName = componentName;
animation.propertyName = propertyName;
animation.propertyValue = propertyValue;
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($"[PropertyAnimationFloat] 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();
// 1. 尝试寻找 Property
targetProperty = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (targetProperty != null && targetProperty.CanWrite)
{
MethodInfo setMethod = targetProperty.GetSetMethod(nonPublic: true);
if (setMethod != null)
{
try
{
floatSetterDelegate = (Action<float>)Delegate.CreateDelegate(typeof(Action<float>), targetComponent, setMethod);
return; // 建立快速委托成功!
}
catch { /* 回落 */ }
}
}
// 2. 尝试寻找 Field (直接包含公有/私有)
targetField = type.GetField(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (targetField == null && targetProperty == null)
{
Debug.LogWarning($"[PropertyAnimationFloat] 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 || propertyValue == null || propertyValue.animations.Count == 0) return;
propertyValue.UpdateFlexibleFloat(songTime);
float value = propertyValue.value;
if (floatSetterDelegate != null)
{
floatSetterDelegate(value);
}
else if (targetProperty != null)
{
targetProperty.SetValue(targetComponent, value);
}
else if (targetField != null)
{
targetField.SetValue(targetComponent, value);
}
if (animatedObject is IHaveDirtyMarkSubmodule dirtyTarget)
{
dirtyTarget.dirtyMarkSubmodule.MarkDirty(propertyName);
}
}
public override void ApplyTimeOffset(float offset)
{
base.ApplyTimeOffset(offset);
if (propertyValue != null && propertyValue.animations != null)
{
foreach(var a in propertyValue.animations)
{
a.startTime += offset;
a.endTime += offset;
}
}
}
#endregion
}
}