Thomas ICHÉ
3 年前
当前提交
67c99d51
共有 14 个文件被更改,包括 410 次插入 和 0 次删除
-
181Editor/PropertyDrawers/ReflectedMemberyPropertyDrawer.cs
-
11Editor/PropertyDrawers/ReflectedMemberyPropertyDrawer.cs.meta
-
8Runtime/Ingredients/Rigs/GenericAnimation.meta
-
8Runtime/ReflectedMember.meta
-
31Runtime/Ingredients/Rigs/GenericAnimation/GenericAnimationRig.cs
-
11Runtime/Ingredients/Rigs/GenericAnimation/GenericAnimationRig.cs.meta
-
33Runtime/Ingredients/Rigs/GenericAnimation/GenericFloatAnimationRig.cs
-
11Runtime/Ingredients/Rigs/GenericAnimation/GenericFloatAnimationRig.cs.meta
-
80Runtime/ReflectedMember/ReflectedMember.cs
-
11Runtime/ReflectedMember/ReflectedMember.cs.meta
-
14Runtime/ReflectedMember/ReflectedMemberAttribute.cs
-
11Runtime/ReflectedMember/ReflectedMemberAttribute.cs.meta
|
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using System.Reflection; |
|||
using System.Linq; |
|||
|
|||
namespace GameplayIngredients.Editor |
|||
{ |
|||
[CustomPropertyDrawer(typeof(ReflectedMember))] |
|||
public class ReflectedMemberyPropertyDrawer : PropertyDrawer |
|||
{ |
|||
Dictionary<(Object, System.Type), string[]> cachedMemberNames; |
|||
|
|||
GenericMenu nullMenu; |
|||
|
|||
void CacheMembersForObject(Object obj, System.Type filterType) |
|||
{ |
|||
if (obj == null) |
|||
return; |
|||
|
|||
if (cachedMemberNames == null) |
|||
cachedMemberNames = new Dictionary<(Object, System.Type), string[]>(); |
|||
|
|||
if (!cachedMemberNames.ContainsKey((obj, filterType))) |
|||
{ |
|||
List<string> names = new List<string>(); |
|||
foreach (var p in obj.GetType().GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.SetField)) |
|||
{ |
|||
if (p.MemberType == MemberTypes.Field && filterType.IsAssignableFrom((p as FieldInfo).FieldType)) |
|||
names.Add(p.Name); |
|||
else if (p.MemberType == MemberTypes.Property && filterType.IsAssignableFrom((p as PropertyInfo).PropertyType)) |
|||
names.Add(p.Name); |
|||
} |
|||
cachedMemberNames.Add((obj, filterType), names.ToArray()); |
|||
} |
|||
} |
|||
|
|||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) |
|||
{ |
|||
SerializedProperty obj = property.FindPropertyRelative("m_TargetObject"); |
|||
SerializedProperty propName = property.FindPropertyRelative("m_MemberName"); |
|||
|
|||
float width = EditorGUIUtility.currentViewWidth; |
|||
|
|||
var filterType = typeof(object); |
|||
var p = property.serializedObject.targetObject.GetType().GetMember(property.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.GetField).First(); |
|||
|
|||
var attr = p.GetCustomAttribute<ReflectedMemberAttribute>(); |
|||
|
|||
if (attr != null) // If using a ReflectedMemberAttribute for filtering type
|
|||
{ |
|||
var typeMember = property.serializedObject.targetObject.GetType().GetMember(attr.typeMemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.GetField).First(); |
|||
if (typeMember.DeclaringType is System.Type) |
|||
{ |
|||
|
|||
if (typeMember is PropertyInfo) |
|||
filterType = (typeMember as PropertyInfo).GetValue(property.serializedObject.targetObject) as System.Type; |
|||
else if (typeMember is FieldInfo) |
|||
filterType = (typeMember as FieldInfo).GetValue(property.serializedObject.targetObject) as System.Type; |
|||
} |
|||
} |
|||
|
|||
Rect objRect = position; |
|||
Rect btnRect = position; |
|||
Rect propRect = position; |
|||
|
|||
objRect.xMax = (width / 3) - 4; |
|||
btnRect.xMin = (width / 3); |
|||
btnRect.xMax = (2 * width / 3); |
|||
propRect.xMin = (2 * width / 3); |
|||
|
|||
EditorGUI.ObjectField(objRect, obj, GUIContent.none); |
|||
|
|||
var tgt = obj.objectReferenceValue; |
|||
|
|||
if (tgt == null || !(tgt is GameObject || tgt is Component)) |
|||
{ |
|||
if (EditorGUI.DropdownButton(btnRect, GUIContent.none, FocusType.Passive)) |
|||
{ |
|||
if (nullMenu == null) |
|||
{ |
|||
nullMenu = new GenericMenu(); |
|||
nullMenu.AddDisabledItem(new GUIContent("No Game Object or Component Selected"), false); |
|||
} |
|||
|
|||
nullMenu.DropDown(btnRect); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
Component[] comps = null; |
|||
int sel = -1; |
|||
if (tgt is GameObject) |
|||
{ |
|||
sel = 0; |
|||
comps = (tgt as GameObject).GetComponents(typeof(Component)); |
|||
} |
|||
else if (tgt is Component) |
|||
{ |
|||
|
|||
comps = (tgt as Component).GetComponents(typeof(Component)); |
|||
} |
|||
|
|||
List<string> names = new List<string>(); |
|||
names.Add("Game Object"); |
|||
|
|||
int i = 1; |
|||
foreach (var comp in comps) |
|||
{ |
|||
if (comp is Callable) |
|||
names.Add($"{comp.GetType().Name} ({(comp as Callable).Name})"); |
|||
else |
|||
names.Add(comp.GetType().Name); |
|||
|
|||
if (tgt == comp) |
|||
sel = i; |
|||
i++; |
|||
} |
|||
|
|||
EditorGUI.BeginChangeCheck(); |
|||
|
|||
int newSel = EditorGUI.Popup(btnRect, sel, names.ToArray()); |
|||
|
|||
if (EditorGUI.EndChangeCheck()) |
|||
{ |
|||
if (newSel == 0) |
|||
{ |
|||
if (tgt is GameObject) |
|||
obj.objectReferenceValue = (tgt as GameObject); |
|||
else if (tgt is Component) |
|||
obj.objectReferenceValue = (tgt as Component).gameObject; |
|||
} |
|||
else |
|||
obj.objectReferenceValue = comps[newSel - 1]; |
|||
|
|||
propName.stringValue = string.Empty; |
|||
} |
|||
|
|||
} |
|||
|
|||
if (obj.objectReferenceValue != null) |
|||
{ |
|||
CacheMembersForObject(obj.objectReferenceValue, filterType); |
|||
int propIdx = -1; |
|||
int i = 0; |
|||
if (!string.IsNullOrEmpty(propName.stringValue)) |
|||
foreach (var name in cachedMemberNames[(obj.objectReferenceValue, filterType)]) |
|||
{ |
|||
if (propName.stringValue == name) |
|||
propIdx = i; |
|||
i++; |
|||
} |
|||
|
|||
EditorGUI.BeginChangeCheck(); |
|||
|
|||
int newPropIdx = EditorGUI.Popup(propRect, propIdx, cachedMemberNames[(obj.objectReferenceValue, filterType)]); |
|||
if (EditorGUI.EndChangeCheck()) |
|||
{ |
|||
propName.stringValue = cachedMemberNames[(obj.objectReferenceValue, filterType)][newPropIdx]; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
using (new EditorGUI.DisabledGroupScope(true)) |
|||
{ |
|||
EditorGUI.DropdownButton(propRect, new GUIContent("(Please Select an object first)"), FocusType.Passive); |
|||
} |
|||
} |
|||
|
|||
// Validate data
|
|||
if (obj.objectReferenceValue != null) |
|||
{ |
|||
if (!(obj.objectReferenceValue is GameObject || obj.objectReferenceValue is Component)) // Invalid Component Type
|
|||
{ |
|||
obj.objectReferenceValue = null; |
|||
propName.stringValue = string.Empty; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 101539721cd4dbd4092347cc4f9a1714 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 2cdfdb3fcc6b5f64eb2254610fcc2891 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 7b4741ea51c1b4646974c0957033625f |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UnityEngine; |
|||
|
|||
namespace GameplayIngredients.Rigs |
|||
{ |
|||
|
|||
public abstract class GenericAnimationRig : Rig |
|||
{ |
|||
public override UpdateMode defaultUpdateMode => UpdateMode.Update; |
|||
|
|||
public override int defaultPriority => 0; |
|||
|
|||
public override bool canChangeUpdateMode => true; |
|||
|
|||
public abstract Type animatedType { get; } |
|||
|
|||
[Header("Target Property / Field"), ReflectedMember("animatedType")] |
|||
public ReflectedMember property; |
|||
|
|||
public override void UpdateRig(float deltaTime) |
|||
{ |
|||
if (property.targetObject != null) |
|||
{ |
|||
property.SetValue(UpdateAndGetValue(deltaTime)); |
|||
} |
|||
} |
|||
|
|||
protected abstract object UpdateAndGetValue(float deltaTime); |
|||
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6f6acdc002a4fea4a85a07db8133241e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using NaughtyAttributes; |
|||
using System; |
|||
using UnityEngine; |
|||
|
|||
namespace GameplayIngredients.Rigs |
|||
{ |
|||
public class GenericFloatAnimationRig : GenericAnimationRig |
|||
{ |
|||
[Header("Base Value")] |
|||
[SerializeField] |
|||
bool useStoredValueAsBase = true; |
|||
[SerializeField, DisableIf("useStoredValueAsBase")] |
|||
float baseValue = 1.0f; |
|||
|
|||
[Header("Animation")] |
|||
public float frequency = 1.0f; |
|||
public float amplitude = 1.0f; |
|||
|
|||
public override Type animatedType => typeof(float); |
|||
|
|||
private void Awake() |
|||
{ |
|||
if (useStoredValueAsBase) |
|||
baseValue = (float)property.GetValue(); |
|||
} |
|||
|
|||
protected override object UpdateAndGetValue(float deltaTime) |
|||
{ |
|||
return Mathf.Sin(Time.time * frequency * Mathf.PI) * amplitude + baseValue; |
|||
} |
|||
} |
|||
} |
|||
|
|
|||
fileFormatVersion: 2 |
|||
guid: 3d5a84f07865f0244beebd46a1ae8c1e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using UnityEngine; |
|||
|
|||
namespace GameplayIngredients |
|||
{ |
|||
|
|||
[Serializable] |
|||
public struct ReflectedMember |
|||
{ |
|||
public UnityEngine.Object targetObject { get => m_TargetObject; } |
|||
public MemberInfo member { get { UpdateMember(); return m_Member; } } |
|||
|
|||
[SerializeField] |
|||
UnityEngine.Object m_TargetObject; |
|||
|
|||
[SerializeField] |
|||
string m_MemberName; |
|||
|
|||
[SerializeField] |
|||
MemberInfo m_Member; |
|||
|
|||
public void SetMember(UnityEngine.Object obj, string memberName) |
|||
{ |
|||
m_TargetObject = obj; |
|||
m_MemberName = memberName; |
|||
UpdateMember(); |
|||
} |
|||
|
|||
public void SetValue(object value) |
|||
{ |
|||
if (m_TargetObject != null) |
|||
{ |
|||
if (m_Member == null) |
|||
UpdateMember(); |
|||
|
|||
if (m_Member.MemberType == MemberTypes.Field) |
|||
(m_Member as FieldInfo).SetValue(m_TargetObject, value); |
|||
else if (m_Member.MemberType == MemberTypes.Property) |
|||
(m_Member as PropertyInfo).SetValue(m_TargetObject, value); |
|||
else |
|||
throw new Exception($"Could not Set value of member {m_Member.Name} which is a {m_Member.MemberType}"); |
|||
} |
|||
else |
|||
throw new Exception($"Could not Find member '{m_MemberName}' of target object {m_TargetObject}"); |
|||
} |
|||
|
|||
public T GetValue<T>() |
|||
{ |
|||
return (T)GetValue(); |
|||
} |
|||
|
|||
public object GetValue() |
|||
{ |
|||
if (m_TargetObject != null) |
|||
{ |
|||
if (m_Member == null) |
|||
UpdateMember(); |
|||
|
|||
if (m_Member.MemberType == MemberTypes.Field) |
|||
return (m_Member as FieldInfo).GetValue(m_TargetObject); |
|||
else if (m_Member.MemberType == MemberTypes.Property) |
|||
return (m_Member as PropertyInfo).GetValue(m_TargetObject); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public void UpdateMember() |
|||
{ |
|||
if (m_TargetObject == null) |
|||
return; |
|||
|
|||
m_Member = m_TargetObject.GetType().GetMember(m_MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.SetField).First(); |
|||
|
|||
if (m_Member == null) |
|||
Debug.LogWarning($"Could not find member of name {m_MemberName} on type {m_TargetObject.GetType().Name}"); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c6d25824103303749a64c4f3026ffe33 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine; |
|||
|
|||
namespace GameplayIngredients |
|||
{ |
|||
public class ReflectedMemberAttribute : PropertyAttribute |
|||
{ |
|||
public string typeMemberName; |
|||
|
|||
public ReflectedMemberAttribute(string typeMemberName) |
|||
{ |
|||
this.typeMemberName = typeMemberName; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b835f96fcf72cb8449ff1447a1f36812 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue