导入角色动画,和增加角色控制

This commit is contained in:
2025-12-11 19:30:20 +08:00
parent a60a92e7ba
commit 7775fa30bb
1452 changed files with 592217 additions and 42573 deletions

View File

@@ -0,0 +1,175 @@
// Designed by KINEMATION, 2025.
using KINEMATION.KAnimationCore.Runtime.Attributes;
using KINEMATION.KAnimationCore.Runtime.Rig;
using KINEMATION.KAnimationCore.Runtime.Input;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
[CustomPropertyDrawer(typeof(CurveSelectorAttribute))]
public class CurveSelectorDrawer : PropertyDrawer
{
private void AddAnimatorNames(ref List<string> options, RuntimeAnimatorController controller)
{
if (controller == null)
{
return;
}
AnimatorController animatorController = controller as AnimatorController;
if (animatorController != null)
{
var parameters = animatorController.parameters;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].type != AnimatorControllerParameterType.Float)
{
continue;
}
options.Add($"{parameters[i].name} (Animator)");
}
}
}
private void AddInputNames(ref List<string> options, UserInputConfig config)
{
if (config == null) return;
foreach (var property in config.floatProperties)
{
options.Add($"{property.name} (Input)");
}
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
CurveSelectorAttribute curveAttribute = attribute as CurveSelectorAttribute;
if (curveAttribute == null)
{
return;
}
KRig rig = (property.serializedObject.targetObject as IRigUser)?.GetRigAsset();
if (rig == null)
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
SerializedProperty name = property.FindPropertyRelative("name");
SerializedProperty source = property.FindPropertyRelative("source");
SerializedProperty mode = property.FindPropertyRelative("mode");
SerializedProperty clampMin = property.FindPropertyRelative("clampMin");
List<string> options = new List<string>();
options.Add("None");
if (rig != null)
{
if (curveAttribute.useAnimator)
{
// Add the Animator curves.
AddAnimatorNames(ref options, rig.targetAnimator);
}
if (curveAttribute.usePlayables)
{
// Add the Playables curves.
foreach (var curve in rig.rigCurves)
{
options.Add($"{curve} (Playables)");
}
}
// Add the Input parameters.
if (curveAttribute.useInput)
{
AddInputNames(ref options, rig.inputConfig);
}
}
name ??= property;
int index = options.IndexOf(name.stringValue);
if (index < 0)
{
index = options.ToList().IndexOf(name.stringValue + " (Animator)");
}
if (index < 0)
{
index = options.ToList().IndexOf(name.stringValue + " (Playables)");
}
if (index < 0)
{
index = options.ToList().IndexOf(name.stringValue + " (Input)");
}
Rect propertyRect = position;
propertyRect.height = EditorGUIUtility.singleLineHeight;
index = EditorGUI.Popup(propertyRect, label.text, index, options.ToArray());
string selection = index >= 0 ? options[index] : "None";
if (source != null)
{
if (selection.EndsWith("(Animator)"))
{
source.intValue = 0;
}
if (selection.EndsWith("(Playables)"))
{
source.intValue = 1;
}
if (selection.EndsWith("(Input)"))
{
source.intValue = 2;
}
}
selection = selection.Replace(" (Playables)", "");
selection = selection.Replace(" (Animator)", "");
selection = selection.Replace(" (Input)", "");
name.stringValue = selection;
if (mode != null)
{
propertyRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(propertyRect, mode);
}
if (clampMin != null)
{
propertyRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(propertyRect, clampMin);
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty name = property.FindPropertyRelative("name");
SerializedProperty mode = property.FindPropertyRelative("mode");
SerializedProperty clampMin = property.FindPropertyRelative("clampMin");
if (name == null || mode == null || clampMin == null)
{
return base.GetPropertyHeight(property, label);
}
return EditorGUIUtility.singleLineHeight * 3f + EditorGUIUtility.standardVerticalSpacing;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 291f05330bc74df98860957b47e438f2
timeCreated: 1704268108

View File

@@ -0,0 +1,131 @@
// Designed by KINEMATION, 2025.
using System;
using KINEMATION.KAnimationCore.Runtime.Rig;
using System.Collections.Generic;
using KINEMATION.KAnimationCore.Editor.Rig;
using KINEMATION.KAnimationCore.Runtime.Attributes;
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
[CustomPropertyDrawer(typeof(KRigElementChain))]
public class ElementChainDrawer : PropertyDrawer
{
private CustomElementChainDrawerAttribute GetCustomChainAttribute()
{
CustomElementChainDrawerAttribute attr = null;
var attributes = fieldInfo.GetCustomAttributes(true);
foreach (var customAttribute in attributes)
{
attr = customAttribute as CustomElementChainDrawerAttribute;
if (attr != null) break;
}
return attr;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
IRigProvider rig = RigEditorUtility.TryGetRigProvider(fieldInfo, property);
SerializedProperty elementChain = property.FindPropertyRelative("elementChain");
SerializedProperty chainName = property.FindPropertyRelative("chainName");
if (rig != null)
{
float labelWidth = EditorGUIUtility.labelWidth;
var customChain = GetCustomChainAttribute();
Rect labelRect = new Rect(position.x, position.y, labelWidth, EditorGUIUtility.singleLineHeight);
Rect buttonRect = position;
string buttonText = $"Edit {chainName.stringValue}";
if (customChain is {drawLabel: true})
{
EditorGUI.PrefixLabel(labelRect, label);
labelRect.x += labelRect.width;
labelRect.width = (position.width - labelWidth) / 2f;
buttonRect.x = labelRect.x;
buttonRect.width = position.width - labelWidth;
buttonText = $"Edit {label.text}";
}
if (customChain is {drawTextField: true})
{
chainName.stringValue = EditorGUI.TextField(labelRect, chainName.stringValue);
buttonRect.width = position.width - labelRect.width - (labelRect.x - position.x);
buttonRect.x = labelRect.x + labelRect.width;
buttonText = "Edit";
}
if (GUI.Button(buttonRect, buttonText))
{
var hierarchy = rig.GetHierarchy();
if (hierarchy != null)
{
List<int> selectedIds = null;
// Get the active element indexes.
int arraySize = elementChain.arraySize;
if (arraySize > 0)
{
selectedIds = new List<int>();
for (int i = 0; i < arraySize; i++)
{
var boneName
= elementChain.GetArrayElementAtIndex(i).FindPropertyRelative("name").stringValue;
selectedIds.Add(Array.FindIndex(hierarchy,
element => element.name.Equals(boneName)) + 1);
}
}
RigWindow.ShowWindow(hierarchy,
(selectedElement) => { },
items =>
{
elementChain.ClearArray();
foreach (var selection in items)
{
elementChain.arraySize++;
int lastIndex = elementChain.arraySize - 1;
var element = elementChain.GetArrayElementAtIndex(lastIndex);
var name = element.FindPropertyRelative("name");
var index = element.FindPropertyRelative("index");
name.stringValue = selection.name;
index.intValue = selection.index;
}
property.serializedObject.ApplyModifiedProperties();
},
true, selectedIds, "Element Chain Selection"
);
}
}
}
else
{
GUI.enabled = false;
EditorGUI.PropertyField(position, property, label, true);
GUI.enabled = true;
}
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1a14bd657f5c4df59493632603d3441f
timeCreated: 1711355637

View File

@@ -0,0 +1,52 @@
// Designed by KINEMATION, 2024.
using KINEMATION.KAnimationCore.Runtime.Attributes;
using KINEMATION.KAnimationCore.Runtime.Rig;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
[CustomPropertyDrawer(typeof(ElementChainSelectorAttribute))]
public class ElementChainSelectorDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
ElementChainSelectorAttribute chainSelectorAttribute = attribute as ElementChainSelectorAttribute;
if (chainSelectorAttribute == null)
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
KRig rig = (property.serializedObject.targetObject as IRigUser)?.GetRigAsset();
SerializedProperty assetProp = property.serializedObject.FindProperty(chainSelectorAttribute.assetName);
if (rig == null || assetProp != null)
{
if (assetProp == null) return;
rig = assetProp.objectReferenceValue as KRig;
}
if (rig == null)
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
List<string> options = new List<string> {"None"};
var chainNames = rig.rigElementChains.Select(chain => chain.chainName).ToArray();
options.AddRange(chainNames);
int currentIndex = options.IndexOf(property.stringValue);
currentIndex = EditorGUI.Popup(position, label.text, currentIndex, options.ToArray());
string selection = currentIndex >= 0 ? options[currentIndex] : "None";
property.stringValue = selection;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: df661746193b43b98e92a78be79cd084
timeCreated: 1710236013

View File

@@ -0,0 +1,102 @@
// Designed by KINEMATION, 2024.
using KINEMATION.KAnimationCore.Runtime.Attributes;
using KINEMATION.KAnimationCore.Runtime.Input;
using System.Collections.Generic;
using KINEMATION.KAnimationCore.Runtime.Rig;
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
[CustomPropertyDrawer(typeof(InputProperty))]
public class InputPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
MonoBehaviour component = property.serializedObject.targetObject as MonoBehaviour;
UserInputConfig config = null;
if (component != null)
{
var root = component.transform.root;
UserInputController controller = root.gameObject.GetComponentInChildren<UserInputController>();
config = controller == null ? null : controller.inputConfig;
}
if (config == null)
{
config = (property.serializedObject.targetObject as IRigUser)?.GetRigAsset().inputConfig;
}
if (config == null)
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
int selectedIndex = -1;
int indexOffset = 0;
List<string> properties = new List<string>();
List<string> options = new List<string>();
int count = config.boolProperties.Count;
for (int i = 0; i < count; i++)
{
var inputProperty = config.boolProperties[i];
properties.Add(inputProperty.name);
options.Add($"{inputProperty.name} (bool)");
if (property.stringValue.Equals(inputProperty.name))
{
selectedIndex = i + indexOffset;
}
}
indexOffset += count;
count = config.intProperties.Count;
for (int i = 0; i < count; i++)
{
var inputProperty = config.intProperties[i];
properties.Add(inputProperty.name);
options.Add($"{inputProperty.name} (int)");
if (property.stringValue.Equals(inputProperty.name))
{
selectedIndex = i + indexOffset;
}
}
indexOffset += count;
count = config.floatProperties.Count;
for (int i = 0; i < count; i++)
{
var inputProperty = config.floatProperties[i];
properties.Add(inputProperty.name);
options.Add($"{inputProperty.name} (float)");
if (property.stringValue.Equals(inputProperty.name))
{
selectedIndex = i + indexOffset;
}
}
indexOffset += count;
count = config.vectorProperties.Count;
for (int i = 0; i < count; i++)
{
var inputProperty = config.vectorProperties[i];
properties.Add(inputProperty.name);
options.Add($"{inputProperty.name} (Vector4)");
if (property.stringValue.Equals(inputProperty.name))
{
selectedIndex = i + indexOffset;
}
}
selectedIndex = EditorGUI.Popup(position, label.text, selectedIndex,
options.ToArray());
property.stringValue = selectedIndex == -1 ? "None" : properties[selectedIndex];
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d71581c42592488289ee2189885f2deb
timeCreated: 1711297253

View File

@@ -0,0 +1,23 @@
// Designed by KINEMATION, 2024
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
public class KAttributesEditor
{
public static T GetComponent<T>(SerializedProperty property) where T : class
{
Object targetObject = property.serializedObject.targetObject;
Component targetComponent = targetObject as Component;
if (targetComponent != null)
{
return targetComponent.GetComponentInChildren<T>();
}
return null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d63cd2c08ebe834286c4a63636ea284
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
// Designed by KINEMATION, 2024.
using KINEMATION.KAnimationCore.Runtime.Attributes;
using KINEMATION.KAnimationCore.Runtime.Rig;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
public class RigEditorUtility
{
public static IRigProvider TryGetRigProvider(FieldInfo fieldInfo, SerializedProperty property)
{
IRigProvider provider = null;
RigAssetSelectorAttribute assetAttribute = null;
foreach (var customAttribute in fieldInfo.GetCustomAttributes(false))
{
if (customAttribute is RigAssetSelectorAttribute)
{
assetAttribute = customAttribute as RigAssetSelectorAttribute;
}
}
if (assetAttribute != null && !string.IsNullOrEmpty(assetAttribute.assetName))
{
if (property.serializedObject.FindProperty(assetAttribute.assetName) is var prop)
{
provider = prop.objectReferenceValue as IRigProvider;
}
}
if (provider == null)
{
provider = property.serializedObject.targetObject as IRigProvider;
}
if (provider == null && property.serializedObject.targetObject is MonoBehaviour component)
{
provider = component.GetComponentInChildren<IRigProvider>();
}
return provider;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fa2c3b5e5c3a4334a4d0ac853266c22f
timeCreated: 1722195056

View File

@@ -0,0 +1,80 @@
// Designed by KINEMATION, 2024.
using System.Collections.Generic;
using KINEMATION.KAnimationCore.Runtime.Rig;
using KINEMATION.KAnimationCore.Editor.Rig;
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
[CustomPropertyDrawer(typeof(KRigElement))]
public class RigElementDrawer : PropertyDrawer
{
private void DrawRigElement(Rect position, SerializedProperty property, GUIContent label)
{
IRigProvider rig = RigEditorUtility.TryGetRigProvider(fieldInfo, property);
SerializedProperty name = property.FindPropertyRelative("name");
SerializedProperty index = property.FindPropertyRelative("index");
if (rig == null)
{
EditorGUI.PropertyField(position, name, label, true);
return;
}
// Calculate label width
float labelWidth = EditorGUIUtility.labelWidth;
float indentLevel = EditorGUI.indentLevel;
// Calculate button width and property field width
float totalWidth = position.width - indentLevel - labelWidth;
// Display the default property field
Rect propertyFieldRect = new Rect(position.x + indentLevel, position.y,
labelWidth, position.height);
EditorGUI.LabelField(propertyFieldRect, label.text);
// Display the bone selection button
Rect buttonRect = new Rect(position.x + indentLevel + labelWidth, position.y,
totalWidth, EditorGUIUtility.singleLineHeight);
string currentName = string.IsNullOrEmpty(name.stringValue) ? "None" : name.stringValue;
if (GUI.Button(buttonRect, currentName))
{
var hierarchy = rig.GetHierarchy();
if (hierarchy == null) return;
List<int> selection = null;
if (index.intValue > -1 || !string.IsNullOrEmpty(name.stringValue))
{
int foundIndex = ArrayUtility.FindIndex(hierarchy,
element => element.name.Equals(name.stringValue));
if(foundIndex >= 0) selection = new List<int>() { foundIndex + 1 };
}
RigWindow.ShowWindow(hierarchy, (selectedElement) =>
{
name.stringValue = selectedElement.name;
index.intValue = selectedElement.index;
name.serializedObject.ApplyModifiedProperties();
},
items => { },
false, selection, "Rig Element Selection"
);
}
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
DrawRigElement(position, property, label);
EditorGUI.EndProperty();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8de53271a60e4843b40829a26b606311
timeCreated: 1704268272

View File

@@ -0,0 +1,74 @@
using KINEMATION.KAnimationCore.Runtime.Attributes;
using UnityEditor;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Editor.Attributes
{
[CustomPropertyDrawer(typeof(UnfoldAttribute))]
public class UnfoldDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
if (property.propertyType == SerializedPropertyType.Generic && !property.isArray)
{
SerializedProperty iterator = property.Copy();
bool enterChildren = true;
// Calculate the initial position rect for the first property
Rect propertyPosition = position;
propertyPosition.height = EditorGUIUtility.singleLineHeight;
while (iterator.NextVisible(enterChildren))
{
if (SerializedProperty.EqualContents(iterator, property.GetEndProperty()))
{
break;
}
enterChildren = false;
EditorGUI.PropertyField(propertyPosition, iterator, new GUIContent(iterator.displayName), true);
// Update the position for the next property
propertyPosition.y +=
EditorGUI.GetPropertyHeight(iterator, new GUIContent(iterator.displayName), true) +
EditorGUIUtility.standardVerticalSpacing;
}
}
else
{
EditorGUI.PropertyField(position, property, GUIContent.none, false);
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property.propertyType == SerializedPropertyType.Generic && !property.isArray)
{
float totalHeight = 0;
SerializedProperty iterator = property.Copy();
bool enterChildren = true;
while (iterator.NextVisible(enterChildren))
{
if (SerializedProperty.EqualContents(iterator, property.GetEndProperty()))
{
break;
}
enterChildren = false;
totalHeight +=
EditorGUI.GetPropertyHeight(iterator, new GUIContent(iterator.displayName), true) +
EditorGUIUtility.standardVerticalSpacing;
}
return totalHeight;
}
return EditorGUI.GetPropertyHeight(property, GUIContent.none, false);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a0cfc4757c394ac39bff808454cc13bc
timeCreated: 1708710029