整合SLSUtilities
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
@@ -24,45 +23,49 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
{
|
||||
public static bool EditorWantsRepaint = false;
|
||||
|
||||
[ReadOnly, ShowInInspector]
|
||||
public FuncAnimDataCollection parentCollection;
|
||||
|
||||
[Title("编辑器设置")]
|
||||
[EnumToggleButtons]
|
||||
[OnValueChanged("RequestRepaint")] // <-- 修改
|
||||
[OnValueChanged("RequestRepaint")]
|
||||
public TimeDisplayMode timeMode;
|
||||
|
||||
[Title("核心动画")]
|
||||
[Required("必须指定一个动画片段")]
|
||||
[OnValueChanged("RequestRepaint")] // <-- 修改
|
||||
[OnValueChanged("RequestRepaint")]
|
||||
public AnimationClip animationClip;
|
||||
|
||||
[Title("编辑时信息")]
|
||||
public FuncAnimInfo animInfo = new FuncAnimInfo("AnimationName", "StateName", true, new List<string>(),
|
||||
DisruptionType.NormalAction, 1.0f, 0, true, new Dictionary<string, List<string>>());
|
||||
[Title("编辑时信息")] public FuncAnimInfo animInfo = new FuncAnimInfo("AnimationName", "StateName",
|
||||
true, new List<string>(), DisruptionType.NormalAction, 1.0f, 0, true);
|
||||
|
||||
[Title("技能区间")]
|
||||
[ListDrawerSettings(
|
||||
ListElementLabelName = "@this.GetIntervalLabel()", // <-- 修改为调用方法
|
||||
ListElementLabelName = "@this.GetIntervalLabel()",
|
||||
AddCopiesLastElement = true)]
|
||||
public List<FuncAnimInterval> intervals = new List<FuncAnimInterval>()
|
||||
{
|
||||
new FuncAnimInterval(IntervalType.Cancellable),
|
||||
new FuncAnimInterval(IntervalType.Startup),
|
||||
new FuncAnimInterval(IntervalType.ExternalDisruption),
|
||||
new FuncAnimInterval(IntervalType.Active),
|
||||
new FuncAnimInterval(IntervalType.Invincible),
|
||||
new FuncAnimInterval(IntervalType.Preinput),
|
||||
new FuncAnimInterval(IntervalType.ActionDisruption),
|
||||
new FuncAnimInterval(IntervalType.MovementDisruption),
|
||||
new FuncAnimInterval(IntervalType.RootMotion)
|
||||
};
|
||||
|
||||
[Title("交互处理")]
|
||||
[Tooltip("技能交互标签,用于标记技能与其他系统的交互关系,例如可以用来标记哪些技能可以被特定状态打断等")]
|
||||
public Dictionary<string, List<string>> interactions = new Dictionary<string, List<string>>();
|
||||
|
||||
[Title("动画事件")]
|
||||
public EventCollection eventCollection;
|
||||
public EventCollection eventCollection = new EventCollection();
|
||||
|
||||
[Title("变量存储")]
|
||||
public VariableCollection variableCollection;
|
||||
public VariableCollection variableCollection = new VariableCollection();
|
||||
|
||||
// (新增) 核心方法:将父级引用传递给子级
|
||||
// 这让子对象 (Event/Interval) 能够访问 animationClip 来计算帧
|
||||
[OnInspectorInit("UpdateChildReferences")]
|
||||
[OnInspectorGUI("UpdateChildReferences")] // 在绘制其他所有内容之前运行
|
||||
private void UpdateChildReferences()
|
||||
{
|
||||
@@ -73,11 +76,32 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
if (interval != null) interval.parentData = this;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventCollection.animEvents != null)
|
||||
{
|
||||
foreach (var evt in eventCollection.animEvents)
|
||||
foreach (var animEvent in eventCollection.animEvents)
|
||||
{
|
||||
if (evt != null) evt.parentData = this;
|
||||
if (animEvent is { payload: not null }) animEvent.payload.parentData = this;
|
||||
}
|
||||
|
||||
foreach (var payload in eventCollection.startEvents)
|
||||
{
|
||||
if (payload != null) payload.parentData = this;
|
||||
}
|
||||
|
||||
foreach (var payload in eventCollection.disruptionEvents)
|
||||
{
|
||||
if (payload != null) payload.parentData = this;
|
||||
}
|
||||
|
||||
foreach (var payload in eventCollection.updateEvents)
|
||||
{
|
||||
if (payload != null) payload.parentData = this;
|
||||
}
|
||||
|
||||
foreach (var payload in eventCollection.updateUntilEvents)
|
||||
{
|
||||
if (payload != null) payload.parentData = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,8 +310,7 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
public class FuncAnimEvent
|
||||
{
|
||||
// (新增) 非序列化的父级引用
|
||||
[NonSerialized]
|
||||
public FuncAnimData parentData;
|
||||
private FuncAnimData parentData => payload?.parentData;
|
||||
|
||||
// (新增) 辅助方法
|
||||
private bool ShowSeconds() => parentData == null || parentData.timeMode == TimeDisplayMode.Seconds || parentData.animationClip == null;
|
||||
@@ -341,9 +364,8 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
[PropertyOrder(2)]
|
||||
public FuncAnimPayloadBase payload;
|
||||
|
||||
public FuncAnimEvent(FuncAnimData parentData, float triggerTime, FuncAnimPayloadBase payload, bool isEnd)
|
||||
public FuncAnimEvent(float triggerTime, FuncAnimPayloadBase payload, bool isEnd)
|
||||
{
|
||||
this.parentData = parentData;
|
||||
this.triggerTime = triggerTime;
|
||||
this.isEnd = isEnd;
|
||||
this.payload = payload;
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SLSUtilities.FunctionalAnimation
|
||||
{
|
||||
[CreateAssetMenu(fileName = "FuncAnimDataCollection", menuName = "Functional Animation/FuncAnimDataCollection", order = 0)]
|
||||
public class FuncAnimDataCollection : SerializedScriptableObject
|
||||
{
|
||||
[Title("武器动作集")]
|
||||
[ListDrawerSettings(ShowFoldout = true, CustomRemoveIndexFunction = "OnRemoveItem")]
|
||||
[OnValueChanged("OnListChanged", true)]
|
||||
public List<FuncAnimData> animDataList = new List<FuncAnimData>();
|
||||
|
||||
[ListDrawerSettings(ListElementLabelName = "functionName")]
|
||||
public List<CustomFunction> preloadFunctions = new List<CustomFunction>();
|
||||
|
||||
/// <summary>
|
||||
/// 当列表发生任何变化(添加、拖入、重新排序)时调用
|
||||
/// </summary>
|
||||
private void OnListChanged()
|
||||
{
|
||||
if (animDataList == null) return;
|
||||
|
||||
foreach (var data in animDataList)
|
||||
{
|
||||
if (data != null && data.parentCollection != this)
|
||||
{
|
||||
data.parentCollection = this;
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义删除逻辑:先解绑,再删除
|
||||
/// </summary>
|
||||
private void OnRemoveItem(int index)
|
||||
{
|
||||
if (index < 0 || index >= animDataList.Count) return;
|
||||
FuncAnimData dataToRemove = animDataList[index];
|
||||
if (dataToRemove != null)
|
||||
{
|
||||
// 如果它的父级确实是当前这个 Collection (防止误删别人的引用)
|
||||
if (dataToRemove.parentCollection == this)
|
||||
{
|
||||
dataToRemove.parentCollection = null;
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(dataToRemove);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
animDataList.RemoveAt(index);
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[HideReferenceObjectPicker]
|
||||
public partial class CustomFunction
|
||||
{
|
||||
[LabelText("Function Name")]
|
||||
public string functionName;
|
||||
|
||||
[HideInInspector] // 平时隐藏,点开下面的 Foldout 再显示
|
||||
public Dictionary<string, string> paramLabels = new Dictionary<string, string>();
|
||||
|
||||
[ShowInInspector]
|
||||
[ShowIf("@paramCollectionType != null")]
|
||||
[LabelText("Parameter Labels")]
|
||||
[OnInspectorGUI("UpdateLabelConfig")] // 每次绘制时检查是否有新参数
|
||||
private Dictionary<string, string> LabelConfigDrawer
|
||||
{
|
||||
get => paramLabels;
|
||||
set => paramLabels = value;
|
||||
}
|
||||
|
||||
[LabelText("Parameter Collection Type")]
|
||||
[ValueDropdown("GetFilteredTypeList")]
|
||||
public Type paramCollectionType;
|
||||
|
||||
public CustomFunction()
|
||||
{
|
||||
functionName = string.Empty;
|
||||
paramCollectionType = typeof(PC_Void);
|
||||
}
|
||||
|
||||
public string GetParamLabel(string fieldName, string defaultLabel)
|
||||
{
|
||||
if (paramLabels != null && paramLabels.TryGetValue(fieldName, out string label))
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
return defaultLabel;
|
||||
}
|
||||
|
||||
private void UpdateLabelConfig()
|
||||
{
|
||||
if (paramCollectionType == null) return;
|
||||
paramLabels ??= new Dictionary<string, string>();
|
||||
FieldInfo[] fields = paramCollectionType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
|
||||
foreach (var field in fields)
|
||||
{
|
||||
if (!paramLabels.ContainsKey(field.Name))
|
||||
{
|
||||
if(field.Name == "function") continue; // 跳过 function 字段
|
||||
|
||||
paramLabels.Add(field.Name, field.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CustomFunction
|
||||
{
|
||||
public IEnumerable<Type> GetFilteredTypeList()
|
||||
{
|
||||
IEnumerable<Type> q = typeof(ParameterCollectionBase).Assembly.GetTypes()
|
||||
.Where(x => !x.IsAbstract)
|
||||
.Where(x => !x.IsGenericTypeDefinition)
|
||||
.Where(x => typeof(ParameterCollectionBase).IsAssignableFrom(x));
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
[HideReferenceObjectPicker]
|
||||
public abstract class ParameterCollectionBase
|
||||
{
|
||||
public CustomFunction function;
|
||||
}
|
||||
|
||||
public class PC_Void : ParameterCollectionBase { }
|
||||
|
||||
public class PC_String : ParameterCollectionBase
|
||||
{
|
||||
[LabelText("@function.GetParamLabel(\"str0\", \"字符串参数\")")]
|
||||
public string str0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a78388ab9bdedb344aa863421d703861
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SLSUtilities.FunctionalAnimation
|
||||
@@ -45,16 +46,12 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
|
||||
[Tooltip("技能是否受速度倍率影响 (例如:角色的攻速属性)")]
|
||||
public bool isAffectedBySpeedMultiplier;
|
||||
|
||||
[Tooltip("技能交互标签,用于标记技能与其他系统的交互关系,例如可以用来标记哪些技能可以被特定状态打断等")]
|
||||
public Dictionary<string, List<string>> interactionTags;
|
||||
|
||||
[Tooltip("技能描述,通常是给开发者看的,便于回忆,可以不写,不会在游戏中显示")]
|
||||
[TextArea]
|
||||
public string description;
|
||||
|
||||
public FuncAnimInfo(string animationName, string stateName, bool useRootMotion, List<string> tags, DisruptionType disruptionType,
|
||||
float overridePlaySpeed, int overrideStartFrame, bool isAffectedBySpeedMultiplier, Dictionary<string, List<string>> interactionTags)
|
||||
float overridePlaySpeed, int overrideStartFrame, bool isAffectedBySpeedMultiplier)
|
||||
{
|
||||
this.animationName = animationName;
|
||||
this.stateName = stateName;
|
||||
@@ -64,7 +61,6 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
this.overridePlaySpeed = overridePlaySpeed;
|
||||
this.overrideStartFrame = overrideStartFrame;
|
||||
this.isAffectedBySpeedMultiplier = isAffectedBySpeedMultiplier;
|
||||
this.interactionTags = interactionTags;
|
||||
this.description = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -28,11 +27,15 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
{
|
||||
[Tooltip("在时间轴上显示的事件名称 (如果为空,则显示类名)")]
|
||||
[PropertyOrder(-1)] // 把它显示在最上面
|
||||
[HideInInspector]
|
||||
public string eventName;
|
||||
|
||||
[NonSerialized]
|
||||
public FuncAnimData parentData;
|
||||
|
||||
[NonSerialized]
|
||||
public RuntimeFuncAnim runtimeFuncAnim;
|
||||
protected CharacterBase character => runtimeFuncAnim?.executor;
|
||||
protected IFuncAnimExecutor character => runtimeFuncAnim?.executor;
|
||||
|
||||
protected FuncAnimPayloadBase()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SLSUtilities.FunctionalAnimation
|
||||
{
|
||||
public interface IFuncAnimExecutor
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7e0ef4fb190a594db8961ab69270568
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
public string animationName => funcAnimData.animInfo.animationName;
|
||||
public bool isLooping => funcAnimData.animationClip.isLooping;
|
||||
|
||||
public CharacterBase executor;
|
||||
public IFuncAnimExecutor executor;
|
||||
public float currentPlayTime;
|
||||
public bool isDisrupted;
|
||||
public int dataAnimEventIndex;
|
||||
@@ -23,8 +23,11 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
public VariableCollection runtimeVariables;
|
||||
public Dictionary<string, bool> updateUntilStatus;
|
||||
private List<FuncAnimEvent> playedEndEvents;
|
||||
|
||||
[NonSerialized]
|
||||
public object currentActionParams;
|
||||
|
||||
public RuntimeFuncAnim(FuncAnimData funcAnimData, CharacterBase character)
|
||||
public RuntimeFuncAnim(FuncAnimData funcAnimData, IFuncAnimExecutor character)
|
||||
{
|
||||
this.funcAnimData = funcAnimData;
|
||||
this.executor = character;
|
||||
@@ -43,10 +46,24 @@ namespace SLSUtilities.FunctionalAnimation
|
||||
dataEvents.updateUntilEvents.ForEach(payload => payload.runtimeFuncAnim = this);
|
||||
}
|
||||
|
||||
public T GetParams<T>() where T : class
|
||||
{
|
||||
if (currentActionParams is T typedParams)
|
||||
{
|
||||
return typedParams;
|
||||
}
|
||||
|
||||
Debug.LogWarning(currentActionParams != null
|
||||
? $"[RuntimeFuncAnim] 参数类型不匹配。期望: {typeof(T).Name}, 实际: {currentActionParams.GetType().Name}"
|
||||
: $"[RuntimeFuncAnim] 尝试获取 {typeof(T).Name},但当前参数为空。");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void AddAnimEvent(float time, FuncAnimPayloadBase payload, bool isEnd = false)
|
||||
{
|
||||
payload.runtimeFuncAnim = this;
|
||||
runtimeEvents.animEvents.Add(new FuncAnimEvent(funcAnimData, time, payload, isEnd));
|
||||
runtimeEvents.animEvents.Add(new FuncAnimEvent(time, payload, isEnd));
|
||||
}
|
||||
|
||||
public void UpdateAnimEvent()
|
||||
|
||||
Reference in New Issue
Block a user