更新
This commit is contained in:
8
Assets/Scripts/Game/DataCore/Animations_BM/Custom.meta
Normal file
8
Assets/Scripts/Game/DataCore/Animations_BM/Custom.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2081115ed032ff546aed97d26f25a4dc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ichni.RhythmGame.Beatmap
|
||||
{
|
||||
[System.Serializable]
|
||||
public class PropertyAnimationColor_BM : AnimationBase_BM
|
||||
{
|
||||
public string componentName;
|
||||
public string propertyName;
|
||||
public FlexibleFloat_BM propertyValueR, propertyValueG, propertyValueB, propertyValueA;
|
||||
|
||||
public PropertyAnimationColor_BM()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ExecuteBM()
|
||||
{
|
||||
matchedElement = PropertyAnimationColor.GenerateElement(elementName, elementGuid, tags, true,
|
||||
GetElement(attachedElementGuid), componentName, propertyName,
|
||||
propertyValueR?.ConvertToGameType(), propertyValueG?.ConvertToGameType(),
|
||||
propertyValueB?.ConvertToGameType(), propertyValueA?.ConvertToGameType());
|
||||
}
|
||||
|
||||
public override GameElement DuplicateBM(GameElement parent)
|
||||
{
|
||||
return PropertyAnimationColor.GenerateElement(elementName, Guid.NewGuid(), tags, false,
|
||||
parent, componentName, propertyName,
|
||||
propertyValueR?.ConvertToGameType(), propertyValueG?.ConvertToGameType(),
|
||||
propertyValueB?.ConvertToGameType(), propertyValueA?.ConvertToGameType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa7ab3d12a4d5a3499e7fcb9b2988090
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ichni.RhythmGame.Beatmap
|
||||
{
|
||||
[System.Serializable]
|
||||
public class PropertyAnimationFloat_BM : AnimationBase_BM
|
||||
{
|
||||
public string componentName;
|
||||
public string propertyName;
|
||||
public FlexibleFloat_BM propertyValue;
|
||||
|
||||
public PropertyAnimationFloat_BM()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ExecuteBM()
|
||||
{
|
||||
matchedElement = PropertyAnimationFloat.GenerateElement(elementName, elementGuid, tags, true,
|
||||
GetElement(attachedElementGuid), componentName, propertyName, propertyValue?.ConvertToGameType());
|
||||
}
|
||||
|
||||
public override GameElement DuplicateBM(GameElement parent)
|
||||
{
|
||||
return PropertyAnimationFloat.GenerateElement(elementName, Guid.NewGuid(), tags, false,
|
||||
parent, componentName, propertyName, propertyValue?.ConvertToGameType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e45326d885c3f8b4688e3475f6093823
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ichni.RhythmGame.Beatmap
|
||||
{
|
||||
[System.Serializable]
|
||||
public class PropertyAnimationVector3_BM : AnimationBase_BM
|
||||
{
|
||||
public string componentName;
|
||||
public string propertyName;
|
||||
public FlexibleFloat_BM propertyValueX, propertyValueY, propertyValueZ;
|
||||
|
||||
public PropertyAnimationVector3_BM()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ExecuteBM()
|
||||
{
|
||||
matchedElement = PropertyAnimationVector3.GenerateElement(elementName, elementGuid, tags, true,
|
||||
GetElement(attachedElementGuid), componentName, propertyName,
|
||||
propertyValueX?.ConvertToGameType(), propertyValueY?.ConvertToGameType(), propertyValueZ?.ConvertToGameType());
|
||||
}
|
||||
|
||||
public override GameElement DuplicateBM(GameElement parent)
|
||||
{
|
||||
return PropertyAnimationVector3.GenerateElement(elementName, Guid.NewGuid(), tags, false,
|
||||
parent, componentName, propertyName,
|
||||
propertyValueX?.ConvertToGameType(), propertyValueY?.ConvertToGameType(), propertyValueZ?.ConvertToGameType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2608612d47188b24280707b2d49cdbc4
|
||||
@@ -41,26 +41,26 @@ namespace Ichni.RhythmGame
|
||||
if (fieldOfView.returnType == FlexibleReturnType.MiddleExecuting)
|
||||
{
|
||||
targetGameCamera.perspectiveAngle = fieldOfView.value;
|
||||
targetGameCamera.gameCamera.fieldOfView = fieldOfView.value;
|
||||
targetGameCamera.cam.fieldOfView = fieldOfView.value;
|
||||
}
|
||||
else if (fieldOfView.isSwitchingReturnType)
|
||||
{
|
||||
animationReturnType = FlexibleReturnType.MiddleExecuting;
|
||||
targetGameCamera.perspectiveAngle = fieldOfView.value;
|
||||
targetGameCamera.gameCamera.fieldOfView = fieldOfView.value;
|
||||
targetGameCamera.cam.fieldOfView = fieldOfView.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CoreServices.TimeProvider.IsPlaying && animationReturnType != FlexibleReturnType.MiddleInterval)
|
||||
{
|
||||
targetGameCamera.perspectiveAngle = fieldOfView.value;
|
||||
targetGameCamera.gameCamera.fieldOfView = fieldOfView.value;
|
||||
targetGameCamera.cam.fieldOfView = fieldOfView.value;
|
||||
animationReturnType = FlexibleReturnType.After;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetGameCamera.perspectiveAngle = fieldOfView.value;
|
||||
targetGameCamera.gameCamera.fieldOfView = fieldOfView.value;
|
||||
targetGameCamera.cam.fieldOfView = fieldOfView.value;
|
||||
animationReturnType = FlexibleReturnType.Before;
|
||||
}
|
||||
}
|
||||
|
||||
8
Assets/Scripts/Game/RuntimeCore/Animations/Custom.meta
Normal file
8
Assets/Scripts/Game/RuntimeCore/Animations/Custom.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f39758d8920acb4591ba3fd1ccb5aeb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public partial class PropertyAnimationColor : AnimationBase
|
||||
{
|
||||
#region [暴露属性字段与关联] Exposed Fields & References
|
||||
public string componentName;
|
||||
public string propertyName;
|
||||
public FlexibleFloat propertyValueR, propertyValueG, propertyValueB, propertyValueA;
|
||||
|
||||
private Component targetComponent;
|
||||
private FieldInfo targetField;
|
||||
private PropertyInfo targetProperty;
|
||||
|
||||
// 高性能赋值委托
|
||||
private Action<Color> colorSetterDelegate;
|
||||
#endregion
|
||||
|
||||
#region [生命周期与工厂] Lifecycle & Factory
|
||||
public static PropertyAnimationColor GenerateElement(string elementName, Guid id, List<string> tags, bool isFirstGenerated,
|
||||
GameElement animatedObject, string componentName, string propertyName,
|
||||
FlexibleFloat propertyValueR, FlexibleFloat propertyValueG, FlexibleFloat propertyValueB, FlexibleFloat propertyValueA)
|
||||
{
|
||||
PropertyAnimationColor animation = Instantiate(EditorManager.instance.basePrefabs.emptyObject)
|
||||
.AddComponent<PropertyAnimationColor>();
|
||||
|
||||
animation.Initialize(elementName, id, tags, isFirstGenerated, animatedObject);
|
||||
|
||||
animation.animatedObject = animatedObject;
|
||||
|
||||
animation.componentName = componentName;
|
||||
animation.propertyName = propertyName;
|
||||
animation.propertyValueR = propertyValueR;
|
||||
animation.propertyValueG = propertyValueG;
|
||||
animation.propertyValueB = propertyValueB;
|
||||
animation.propertyValueA = propertyValueA;
|
||||
|
||||
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($"[PropertyAnimationColor] 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(Color))
|
||||
{
|
||||
try
|
||||
{
|
||||
colorSetterDelegate = (Action<Color>)Delegate.CreateDelegate(typeof(Action<Color>), targetComponent, setMethod);
|
||||
return;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
targetField = type.GetField(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (targetField == null && targetProperty == null)
|
||||
{
|
||||
Debug.LogWarning($"[PropertyAnimationColor] Cannot find target Property or Field '{propertyName}' strictly on '{componentName}'.");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region [核心动画逻辑] Core Animation Logic
|
||||
protected override void UpdateAnimation(float songTime)
|
||||
{
|
||||
if (targetComponent == null) return;
|
||||
|
||||
propertyValueR?.UpdateFlexibleFloat(songTime);
|
||||
propertyValueG?.UpdateFlexibleFloat(songTime);
|
||||
propertyValueB?.UpdateFlexibleFloat(songTime);
|
||||
propertyValueA?.UpdateFlexibleFloat(songTime);
|
||||
|
||||
// 获取最新颜色(如果没有对应颜色参数或者为空则默认 1 避免黑屏,但这依赖具体业务传值安全度)
|
||||
float r = propertyValueR != null ? propertyValueR.value : 1f;
|
||||
float g = propertyValueG != null ? propertyValueG.value : 1f;
|
||||
float b = propertyValueB != null ? propertyValueB.value : 1f;
|
||||
float a = propertyValueA != null ? propertyValueA.value : 1f;
|
||||
|
||||
Color targetColor = new Color(r, g, b, a);
|
||||
|
||||
if (colorSetterDelegate != null)
|
||||
{
|
||||
colorSetterDelegate(targetColor);
|
||||
}
|
||||
else if (targetProperty != null)
|
||||
{
|
||||
targetProperty.SetValue(targetComponent, targetColor);
|
||||
}
|
||||
else if (targetField != null)
|
||||
{
|
||||
targetField.SetValue(targetComponent, targetColor);
|
||||
}
|
||||
|
||||
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(propertyValueR);
|
||||
ApplyOffset(propertyValueG);
|
||||
ApplyOffset(propertyValueB);
|
||||
ApplyOffset(propertyValueA);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a37afb8d761f9794f92f706f64962956
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public partial 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(EditorManager.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)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3f645fa7bbdc344cbb4cd8631ce11ef
|
||||
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public partial 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(EditorManager.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)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88547daf9d775f24c94586fbc65e195b
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public class DirtyMarkSubmodule : SubmoduleBase
|
||||
{
|
||||
public bool isAnyDirty { get; private set; }
|
||||
public Dictionary<string, bool> dirtyFlags;
|
||||
|
||||
public DirtyMarkSubmodule(GameElement attachedGameElement) : base(attachedGameElement)
|
||||
{
|
||||
isAnyDirty = false;
|
||||
dirtyFlags = new Dictionary<string, bool>();
|
||||
|
||||
if (!HaveSameSubmodule && attachedGameElement is IHaveDirtyMarkSubmodule host)
|
||||
{
|
||||
host.dirtyMarkSubmodule = this;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkDirty(string flagKey = "All")
|
||||
{
|
||||
isAnyDirty = true;
|
||||
if (!string.IsNullOrEmpty(flagKey))
|
||||
{
|
||||
dirtyFlags[flagKey] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteDeferredRefresh()
|
||||
{
|
||||
if (isAnyDirty && attachedGameElement is IHaveDirtyMarkSubmodule host)
|
||||
{
|
||||
host.OnDirtyRefresh(dirtyFlags);
|
||||
ClearDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearDirty()
|
||||
{
|
||||
isAnyDirty = false;
|
||||
dirtyFlags.Clear();
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
MarkDirty("All");
|
||||
}
|
||||
|
||||
public override void SaveBM()
|
||||
{
|
||||
//运行时组件不需要保存BM
|
||||
}
|
||||
}
|
||||
|
||||
public interface IHaveDirtyMarkSubmodule
|
||||
{
|
||||
DirtyMarkSubmodule dirtyMarkSubmodule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当有一帧收到来自于动画或者其它管理器的脏标记篡改时,在此方法中处理推送至具体表现层的工作。
|
||||
/// </summary>
|
||||
void OnDirtyRefresh(Dictionary<string, bool> flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f95a37c68ec795429bb18308ad12060
|
||||
@@ -4,8 +4,23 @@ using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public partial class EnvironmentObject : SubstantialObject
|
||||
public partial class EnvironmentObject : SubstantialObject, IHaveDirtyMarkSubmodule
|
||||
{
|
||||
#region [脏数据标记] Dirty Mark Submodule
|
||||
public DirtyMarkSubmodule dirtyMarkSubmodule { get; set; }
|
||||
|
||||
public virtual void OnDirtyRefresh(Dictionary<string, bool> flags)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void SetDefaultSubmodules()
|
||||
{
|
||||
base.SetDefaultSubmodules();
|
||||
dirtyMarkSubmodule = new DirtyMarkSubmodule(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region [运行时缓存数据] Property Caches
|
||||
public bool isStatic;
|
||||
#endregion
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Ichni.RhythmGame
|
||||
public partial class GameCamera : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule
|
||||
{
|
||||
#region [暴露属性字段] Camera View & Settings
|
||||
[FormerlySerializedAs("camera")]
|
||||
public Camera gameCamera;
|
||||
[FormerlySerializedAs("gameCamera")] [FormerlySerializedAs("camera")]
|
||||
public Camera cam;
|
||||
public Transform rotationPoint;
|
||||
public Transform positionPoint;
|
||||
public Transform cameraTransform;
|
||||
@@ -45,12 +45,12 @@ namespace Ichni.RhythmGame
|
||||
gameCamera.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
|
||||
|
||||
cameraManager.gameCamera = gameCamera;
|
||||
gameCamera.gameCamera.GetComponent<UniversalAdditionalCameraData>().cameraStack.Add(cameraManager.backgroundCamera);
|
||||
if (cameraManager.isSceneCameraActive) gameCamera.gameCamera.enabled = false;
|
||||
gameCamera.cam.GetComponent<UniversalAdditionalCameraData>().cameraStack.Add(cameraManager.backgroundCamera);
|
||||
if (cameraManager.isSceneCameraActive) gameCamera.cam.enabled = false;
|
||||
|
||||
gameCamera.parentElement = parentElement;
|
||||
gameCamera.cameraViewType = cameraViewType;
|
||||
gameCamera.gameCamera.orthographic = cameraViewType == CameraViewType.Orthographic;
|
||||
gameCamera.cam.orthographic = cameraViewType == CameraViewType.Orthographic;
|
||||
gameCamera.perspectiveAngle = perspectiveAngle;
|
||||
gameCamera.orthographicSize = orthographicSize;
|
||||
gameCamera.cameraTransform = gameCamera.transform;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Ichni.RhythmGame
|
||||
#region [扩展功能] Extension Methods
|
||||
public void ApplyExtension()
|
||||
{
|
||||
gameCamera.gameCamera.farClipPlane = farClipRange;
|
||||
gameCamera.cam.farClipPlane = farClipRange;
|
||||
sceneCamera.sceneCamera.farClipPlane = farClipRange;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Ichni.RhythmGame
|
||||
public Vector3 offsetValue;
|
||||
public AnimationCurve offsetCurve;
|
||||
|
||||
Transform gameCameraTransform => EditorManager.instance.cameraManager.gameCamera.gameCamera.transform;
|
||||
Transform gameCameraTransform => EditorManager.instance.cameraManager.gameCamera.cam.transform;
|
||||
Tweener offsetTweener;
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Ichni.RhythmGame
|
||||
public Vector3 tiltValue;
|
||||
public AnimationCurve tiltCurve;
|
||||
|
||||
Transform gameCameraTransform => EditorManager.instance.cameraManager.gameCamera.gameCamera.transform;
|
||||
Transform gameCameraTransform => EditorManager.instance.cameraManager.gameCamera.cam.transform;
|
||||
Tweener tiltTweener;
|
||||
#endregion
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Ichni.RhythmGame
|
||||
public override void Disrupt()
|
||||
{
|
||||
tiltTweener?.Kill();
|
||||
EditorManager.instance.cameraManager.gameCamera.gameCamera.transform.DOLocalRotate(Vector3.zero, 0.4f);
|
||||
EditorManager.instance.cameraManager.gameCamera.cam.transform.DOLocalRotate(Vector3.zero, 0.4f);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Ichni.RhythmGame
|
||||
public float relativeZoom;
|
||||
public AnimationCurve zoomCurve;
|
||||
|
||||
Camera gameCamera => EditorManager.instance.cameraManager.gameCamera.gameCamera;
|
||||
Camera gameCamera => EditorManager.instance.cameraManager.gameCamera.cam;
|
||||
#endregion
|
||||
|
||||
#region [生成与初始化] Generation & Initialization
|
||||
|
||||
@@ -212,7 +212,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
if (EditorManager.instance.cameraManager.haveGameCamera)
|
||||
{
|
||||
noteScreenPosition = EditorManager.instance.cameraManager.gameCamera.gameCamera.WorldToScreenPoint(noteVisual.noteVisualPosition);
|
||||
noteScreenPosition = EditorManager.instance.cameraManager.gameCamera.cam.WorldToScreenPoint(noteVisual.noteVisualPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace Ichni.RhythmGame
|
||||
// 屏幕位置更新
|
||||
if (cameraManager.haveGameCamera)
|
||||
{
|
||||
noteScreenPosition = cameraManager.gameCamera.gameCamera.WorldToScreenPoint(noteVisual.noteVisualPosition);
|
||||
noteScreenPosition = cameraManager.gameCamera.cam.WorldToScreenPoint(noteVisual.noteVisualPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Ichni.Editor
|
||||
|
||||
public GameCamera gameCamera;
|
||||
public bool haveGameCamera => gameCamera != null;
|
||||
public Camera currentCamera => haveGameCamera && !isSceneCameraActive ? gameCamera.gameCamera : sceneCamera.sceneCamera;
|
||||
public Camera currentCamera => haveGameCamera && !isSceneCameraActive ? gameCamera.cam : sceneCamera.sceneCamera;
|
||||
|
||||
public BaseElement_BM matchedBM { get; set; }
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Ichni.Editor
|
||||
|
||||
isSceneCameraActive = !isSceneCameraActive;
|
||||
sceneCamera.sceneCamera.enabled = isSceneCameraActive;
|
||||
gameCamera.gameCamera.enabled = !isSceneCameraActive;
|
||||
gameCamera.cam.enabled = !isSceneCameraActive;
|
||||
|
||||
EditorManager.instance.backgroundController.backgroundCanvas.worldCamera = currentCamera;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user