Net.Like.Xue.Tokyo/Assets/Plugins/Character Controller Pro/Utilities/Scripts/CustomUtilities.cs

1070 lines
36 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Lightbug.Utilities
{
public enum Direction
{
Right,
Left,
Up,
Down,
Forward,
Back
}
/// <summary>
/// This static class contains all kind of useful methods used across the package.
/// </summary>
public static class CustomUtilities
{
public static Vector3 Add(Vector3 vectorA, Vector3 vectorB)
{
vectorA.x += vectorB.x;
vectorA.y += vectorB.y;
return vectorA;
}
public static Vector3 Substract(Vector3 vectorA, Vector3 vectorB)
{
vectorA.x -= vectorB.x;
vectorA.y -= vectorB.y;
return vectorA;
}
public static Vector3 Multiply(Vector3 vectorValue, float floatValue)
{
vectorValue.x *= floatValue;
vectorValue.y *= floatValue;
vectorValue.z *= floatValue;
return vectorValue;
}
public static Vector3 Multiply(Vector3 vectorValue, float floatValueA, float floatValueB)
{
vectorValue.x *= floatValueA * floatValueB;
vectorValue.y *= floatValueA * floatValueB;
vectorValue.z *= floatValueA * floatValueB;
return vectorValue;
}
public static void AddMagnitude(ref Vector3 vector, float magnitude)
{
if (vector == Vector3.zero)
return;
float vectorMagnitude = Vector3.Magnitude(vector);
Vector3 vectorDirection = vector / vectorMagnitude;
vector += vectorDirection * magnitude;
}
public static void ChangeMagnitude(ref Vector3 vector, float magnitude)
{
if (vector == Vector3.zero)
return;
Vector3 vectorDirection = Vector3.Normalize(vector);
vector = vectorDirection * magnitude;
}
public static void ChangeDirection(ref Vector3 vector, Vector3 direction)
{
if (vector == Vector3.zero)
return;
float vectorMagnitude = Vector3.Magnitude(vector);
vector = direction * vectorMagnitude;
}
public static void ChangeDirectionOntoPlane(ref Vector3 vector, Vector3 planeNormal)
{
if (vector == Vector3.zero)
return;
Vector3 direction = Vector3.Normalize(Vector3.ProjectOnPlane(vector, planeNormal));
float vectorMagnitude = Vector3.Magnitude(vector);
vector = direction * vectorMagnitude;
}
public static void GetMagnitudeAndDirection(this Vector3 vector, out Vector3 direction, out float magnitude)
{
magnitude = Vector3.Magnitude(vector);
direction = Vector3.Normalize(vector);
}
/// <summary>
/// Projects an input vector onto the tangent of a given plane (defined by its normal).
/// </summary>
public static Vector3 ProjectOnTangent(Vector3 inputVector, Vector3 planeNormal, Vector3 up)
{
Vector3 inputVectorDirection = Vector3.Normalize(inputVector);
if (inputVectorDirection == -up)
{
inputVector += planeNormal * 0.01f;
}
else if (inputVectorDirection == up)
{
return Vector3.zero;
}
Vector3 rotationAxis = GetPerpendicularDirection(inputVector, up);
Vector3 tangent = GetPerpendicularDirection(planeNormal, rotationAxis);
return Multiply(tangent, Vector3.Magnitude(inputVector));
}
/// <summary>
/// Projects an input vector onto plane A and plane B orthonormal direction.
/// </summary>
public static Vector3 DeflectVector(Vector3 inputVector, Vector3 planeA, Vector3 planeB, bool maintainMagnitude = false)
{
Vector3 direction = GetPerpendicularDirection(planeA, planeB);
if (maintainMagnitude)
return direction * inputVector.magnitude;
else
return Vector3.Project(inputVector, direction);
}
public static Vector3 GetPerpendicularDirection(Vector3 vectorA, Vector3 vectorB)
{
return Vector3.Normalize(Vector3.Cross(vectorA, vectorB));
}
public static float GetTriangleValue(float center, float height, float width, float independentVariable, float minIndependentVariableLimit = Mathf.NegativeInfinity, float maxIndependentVariableLimit = Mathf.Infinity)
{
float minValue = center - width / 2f;
float maxValue = center + width / 2f;
if (independentVariable < minValue || independentVariable > maxValue)
{
return 0f;
}
else if (independentVariable < center)
{
return height * (independentVariable - minValue) / (center - minValue);
}
else
{
return -height * (independentVariable - center) / (maxValue - center) + height;
}
}
/// <summary>
/// Makes a value greater than or equal to zero (default value).
/// </summary>
public static void SetPositive<T>(ref T value) where T : System.IComparable<T>
{
SetMin<T>(ref value, default(T));
}
/// <summary>
/// Makes a value less than or equal to zero (default value).
/// </summary>
public static void SetNegative<T>(ref T value) where T : System.IComparable<T>
{
SetMax<T>(ref value, default(T));
}
/// <summary>
/// Makes a value greater than or equal to a minimum value.
/// </summary>
public static void SetMin<T>(ref T value, T minValue) where T : System.IComparable<T>
{
bool isLess = value.CompareTo(minValue) < 0;
if (isLess)
value = minValue;
}
/// <summary>
/// Makes a value less than or equal to a maximum value.
/// </summary>
public static void SetMax<T>(ref T value, T maxValue) where T : System.IComparable<T>
{
bool isGreater = value.CompareTo(maxValue) > 0;
if (isGreater)
value = maxValue;
}
/// <summary>
/// Limits a value range from a minimum value to a maximum value (similar to Mathf.Clamp).
/// </summary>
public static void SetRange<T>(ref T value, T minValue, T maxValue) where T : System.IComparable<T>
{
SetMin<T>(ref value, minValue);
SetMax<T>(ref value, maxValue);
}
/// <summary>
/// Returns true if the target value is between a and b ( both exclusive ).
/// To include the limits values set the "inclusive" parameter to true.
/// </summary>
public static bool isBetween(float target, float a, float b, bool inclusive = false)
{
if (b > a)
return (inclusive ? target >= a : target > a) && (inclusive ? target <= b : target < b);
else
return (inclusive ? target >= b : target > b) && (inclusive ? target <= a : target < a);
}
/// <summary>
/// Returns true if the target value is between a and b ( both exclusive ).
/// To include the limits values set the "inclusive" parameter to true.
/// </summary>
public static bool isBetween(int target, int a, int b, bool inclusive = false)
{
if (b > a)
return (inclusive ? target >= a : target > a) && (inclusive ? target <= b : target < b);
else
return (inclusive ? target >= b : target > b) && (inclusive ? target <= a : target < a);
}
public static bool isCloseTo(Vector3 input, Vector3 target, float tolerance)
{
return Vector3.Distance(input, target) <= tolerance;
}
public static bool isCloseTo(float input, float target, float tolerance)
{
return Mathf.Abs(target - input) <= tolerance;
}
public static Vector3 TransformVectorUnscaled(this Transform transform, Vector3 vector)
{
return transform.rotation * vector;
}
public static Vector3 InverseTransformVectorUnscaled(this Transform transform, Vector3 vector)
{
return Quaternion.Inverse(transform.rotation) * vector;
}
public static Vector3 RotatePointAround(Vector3 point, Vector3 center, float angle, Vector3 axis)
{
Quaternion rotation = Quaternion.AngleAxis(angle, axis);
Vector3 pointToCenter = center - point;
Vector3 rotatedPointToCenter = rotation * pointToCenter;
return center - rotatedPointToCenter;
}
public static T GetOrAddComponent<T>(this GameObject targetGameObject, bool includeChildren = false) where T : Component
{
T existingComponent = includeChildren ? targetGameObject.GetComponentInChildren<T>() : targetGameObject.GetComponent<T>();
if (existingComponent != null)
{
return existingComponent;
}
T component = targetGameObject.AddComponent<T>();
return component;
}
/// <summary>
/// Gets a "target" component within a particular branch (inside the hierarchy). The branch is defined by the "branch root object", which is also defined by the chosen
/// "branch root component". The returned component must come from a child of the "branch root object".
/// </summary>
/// <param name="callerComponent"></param>
/// <param name="includeInactive">Include inactive objects?</param>
/// <typeparam name="T1">Branch root component type.</typeparam>
/// <typeparam name="T2">Target component type.</typeparam>
/// <returns>The target component.</returns>
public static T2 GetComponentInBranch<T1, T2>(this Component callerComponent, bool includeInactive = true) where T1 : Component where T2 : Component
{
T1[] rootComponents = callerComponent.transform.root.GetComponentsInChildren<T1>(includeInactive);
if (rootComponents.Length == 0)
{
Debug.LogWarning($"Root component: No objects found with {typeof(T1).Name} component");
return null;
}
for (int i = 0; i < rootComponents.Length; i++)
{
T1 rootComponent = rootComponents[i];
// Is the caller a child of this root?
if (!callerComponent.transform.IsChildOf(rootComponent.transform) && !rootComponent.transform.IsChildOf(callerComponent.transform))
continue;
T2 targetComponent = rootComponent.GetComponentInChildren<T2>(includeInactive);
if (targetComponent == null)
continue;
return targetComponent;
}
return null;
}
/// <summary>
/// Gets a "target" component within a particular branch (inside the hierarchy). The branch is defined by the "branch root object", which is also defined by the chosen
/// "branch root component". The returned component must come from a child of the "branch root object".
/// </summary>
/// <param name="callerComponent"></param>
/// <param name="includeInactive">Include inactive objects?</param>
/// <typeparam name="T1">Target component type.</typeparam>
/// <returns>The target component.</returns>
public static T1 GetComponentInBranch<T1>(this Component callerComponent, bool includeInactive = true) where T1 : Component
{
return callerComponent.GetComponentInBranch<T1, T1>(includeInactive);
}
public static bool IsNullOrEmpty(this string target)
{
return target == null || target.Length == 0;
}
public static bool IsNullOrWhiteSpace(this string target)
{
if (target == null)
return true;
for (int i = 0; i < target.Length; i++)
{
if (target[i] != ' ')
return false;
}
return true;
}
public static string Between(this string targetString, string firstString, string lastString)
{
int start = targetString.IndexOf(firstString) + firstString.Length;
int end = targetString.IndexOf(lastString);
if (end - start < 0)
return "";
return targetString.Substring(start, end - start);
}
public static bool BelongsToLayerMask(int layer, int layerMask)
{
return (layerMask & (1 << layer)) > 0;
}
public static T1 GetOrAddComponent<T1>(this GameObject gameObject) where T1 : Component
{
if (!gameObject.TryGetComponent(out T1 component))
component = gameObject.AddComponent<T1>();
return component;
}
public static T1 GetOrAddComponent<T1, T2>(this GameObject gameObject) where T1 : Component where T2 : Component
{
if (!gameObject.TryGetComponent(out T1 component))
{
if (gameObject.TryGetComponent(out T2 requiredComponent))
component = gameObject.AddComponent<T1>();
}
return component;
}
public static T1 GetOrAddComponent<T1>(this Component baseComponent) where T1 : Component
{
if (!baseComponent.TryGetComponent(out T1 component))
component = baseComponent.gameObject.AddComponent<T1>();
return component;
}
public static T1 GetOrAddComponent<T1, T2>(this Component baseComponent) where T1 : Component where T2 : Component
{
if (!baseComponent.TryGetComponent(out T1 component))
{
if (baseComponent.TryGetComponent(out T2 requiredComponent))
component = baseComponent.gameObject.AddComponent<T1>();
}
return component;
}
public static T1 GetOrAddComponent<T1, T2>(this Component baseComponent, T2 requiredComponentType) where T1 : Component where T2 : System.Type
{
if (!baseComponent.TryGetComponent(out T1 component))
{
if (baseComponent.TryGetComponent(out T2 requiredComponent))
component = (T1)baseComponent.gameObject.AddComponent(requiredComponentType);
}
return component;
}
/// <summary>
/// Gets a particular value from this dictionary. If the value isn't there, it gets added.
/// </summary>
/// <typeparam name="T1">Key type.</typeparam>
/// <typeparam name="T2">Value type.</typeparam>
/// <param name="dictionary">A dictionary container.</param>
/// <param name="key">The key parameter</param>
/// <param name="addIfNull">Indicates if the component should be added if it doesn't exist.</param>
/// <returns></returns>
public static T2 GetOrRegisterValue<T1, T2>(this Dictionary<T1, T2> dictionary, T1 key, bool addIfNull = false) where T1 : Component where T2 : Component
{
if (key == null)
return null;
bool found = dictionary.TryGetValue(key, out T2 value);
if (!found)
{
value = addIfNull ? key.gameObject.GetOrAddComponent<T2>() : key.GetComponent<T2>();
if (value != null)
dictionary.Add(key, value);
}
return value;
}
/// <summary>
/// Gets a particular value from this dictionary. If the value isn't there, it gets added.
/// </summary>
/// <typeparam name="T1">Key type.</typeparam>
/// <typeparam name="T2">Value type.</typeparam>
/// <typeparam name="T3">Required component type.</typeparam>
/// <param name="dictionary">A dictionary container.</param>
/// <param name="key">The key parameter</param>
/// <param name="addIfNull">Indicates if the component should be added if it doesn't exist and the
/// required component exist.</param>
/// <returns></returns>
public static T2 GetOrRegisterValue<T1, T2, T3>(this Dictionary<T1, T2> dictionary, T1 key, bool addIfNull = false) where T1 : Component where T2 : Component where T3 : Component
{
if (key == null)
return null;
bool found = dictionary.TryGetValue(key, out T2 value);
if (!found)
{
value = addIfNull ? key.gameObject.GetOrAddComponent<T2, T3>() : key.GetComponent<T2>();
if (value != null)
dictionary.Add(key, value);
}
return value;
}
public static float SignedAngle(Vector3 from, Vector3 to, Vector3 axis)
{
float angle = Vector3.Angle(from, to);
Vector3 cross = Vector3.Cross(from, to);
cross.Normalize();
float sign = cross == axis ? 1f : -1f;
return sign * angle;
}
public static void DebugRay(Vector3 point, Vector3 direction = default(Vector3), float duration = 2f, Color color = default(Color))
{
Vector3 drawDirection = direction == default(Vector3) ? Vector3.up : direction;
Color drawColor = color == default(Color) ? Color.blue : color;
Debug.DrawRay(point, drawDirection, drawColor, duration);
}
public static void DrawArrowGizmo(Vector3 start, Vector3 end, Color color, float radius = 0.25f)
{
Gizmos.color = color;
Gizmos.DrawLine(start, end);
Gizmos.DrawRay(
end,
Quaternion.AngleAxis(45, Vector3.forward) * Vector3.Normalize(start - end) * radius
);
Gizmos.DrawRay(
end,
Quaternion.AngleAxis(-45, Vector3.forward) * Vector3.Normalize(start - end) * radius
);
}
public static void DrawGizmoCross(Vector3 point, float radius, Color color)
{
Gizmos.color = color;
Gizmos.DrawRay(
point + Vector3.up * 0.5f * radius,
Vector3.down * radius
);
Gizmos.DrawRay(
point + Vector3.right * 0.5f * radius,
Vector3.left * radius
);
}
public static void DrawDebugCross(Vector3 point, float radius, Color color, float angleOffset = 0f)
{
Debug.DrawRay(
point + Quaternion.Euler(0, 0, angleOffset) * Vector3.up * 0.5f * radius,
Quaternion.Euler(0, 0, angleOffset) * Vector3.down * radius,
color
);
Debug.DrawRay(
point + Quaternion.Euler(0, 0, angleOffset) * Vector3.right * 0.5f * radius,
Quaternion.Euler(0, 0, angleOffset) * Vector3.left * radius,
color
);
}
#region Animator
/// <summary>
/// Gets the current clip effective length, that is, the original length divided by the playback speed. The length value is always positive, regardless of the speed sign.
/// It returns false if the clip is not valid.
/// </summary>
public static bool GetCurrentClipLength(this Animator animator, ref float length)
{
if (animator.runtimeAnimatorController == null)
return false;
AnimatorClipInfo[] clipInfo = animator.GetCurrentAnimatorClipInfo(0);
if (clipInfo.Length == 0)
return false;
float clipLength = clipInfo[0].clip.length;
float speed = animator.GetCurrentAnimatorStateInfo(0).speed;
length = Mathf.Abs(clipLength / speed);
return true;
}
public static bool MatchTarget(this Animator animator, Vector3 targetPosition, Quaternion targetRotation, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
MatchTargetWeightMask weightMask = new MatchTargetWeightMask(Vector3.one, 1f);
animator.MatchTarget(
targetPosition,
targetRotation,
avatarTarget,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
public static bool MatchTarget(this Animator animator, Vector3 targetPosition, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
MatchTargetWeightMask weightMask = new MatchTargetWeightMask(Vector3.one, 0f);
animator.MatchTarget(
targetPosition,
Quaternion.identity,
avatarTarget,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
public static bool MatchTarget(this Animator animator, Transform target, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
MatchTargetWeightMask weightMask = new MatchTargetWeightMask(Vector3.one, 1f);
animator.MatchTarget(
target.position,
target.rotation,
avatarTarget,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
public static bool MatchTarget(this Animator animator, Transform target, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime, MatchTargetWeightMask weightMask)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
animator.MatchTarget(
target.position,
target.rotation,
AvatarTarget.Root,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
#endregion
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
#if UNITY_EDITOR
public static List<T> FindInterfaces<T>()
{
List<T> interfaces = new List<T>();
GameObject[] rootGameObjects = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
foreach (var rootGameObject in rootGameObjects)
{
T[] childrenInterfaces = rootGameObject.GetComponentsInChildren<T>();
foreach (T childInterface in childrenInterfaces)
{
interfaces.Add(childInterface);
}
}
return interfaces;
}
public static MethodInfo[] GetMethods(this MonoBehaviour monoBehaviour)
{
MonoScript monoScript = MonoScript.FromMonoBehaviour(monoBehaviour);
MethodInfo[] methods = monoScript.GetClass().GetMethods();
return methods;
}
public static MethodInfo[] GetMethods(this ScriptableObject scriptableObject)
{
MonoScript monoScript = MonoScript.FromScriptableObject(scriptableObject);
MethodInfo[] methods = monoScript.GetClass().GetMethods();
return methods;
}
public static System.Type[] GetAllDerivedObjects<T>(bool allowAbstract = true) where T : Component
{
List<System.Type> result = new List<System.Type>();
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(T)))
{
if (type.IsAbstract)
{
if (allowAbstract)
result.Add(type);
}
else
{
result.Add(type);
}
}
}
}
return result.ToArray();
}
public static T GetInterface<T>(this MonoBehaviour monoBehaviour)
{
T[] walkInterfaces = monoBehaviour.GetComponents<T>();
for (int i = 0; i < walkInterfaces.Length; i++)
{
T @interface = walkInterfaces[i];
Object interfaceObject = @interface as object as Object;
if (interfaceObject == monoBehaviour)
return @interface;
}
return default(T);
}
public static System.Type[] GetAllDerivedComponents(System.Type componentType, bool allowAbstract = true)
{
if (!componentType.IsSubclassOf(typeof(Component)))
return null;
List<System.Type> result = new List<System.Type>();
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(componentType))
{
if (type.IsAbstract)
{
if (allowAbstract)
result.Add(type);
}
else
{
result.Add(type);
}
}
}
}
return result.ToArray();
}
public static System.Type[] GetAllDerivedObjectsClass<T>(bool allowAbstract = true) where T : class
{
List<System.Type> result = new List<System.Type>();
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(T)))
{
if (type.IsAbstract)
{
if (allowAbstract)
result.Add(type);
}
else
{
result.Add(type);
}
}
}
}
return result.ToArray();
}
public static void DrawMonoBehaviourField<T>(T target) where T : MonoBehaviour
{
GUI.enabled = false;
EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour(target), typeof(T), false);
GUI.enabled = true;
}
public static void DrawScriptableObjectField<T>(T target) where T : ScriptableObject
{
GUI.enabled = false;
EditorGUILayout.ObjectField("Script:", MonoScript.FromScriptableObject(target), typeof(T), false);
GUI.enabled = true;
}
public static void DrawEditorLayoutHorizontalLine(Color color, int thickness = 1, int padding = 10)
{
Rect rect = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
rect.height = thickness;
rect.y += padding / 2;
//rect.x -= 2;
//rect.width +=6;
EditorGUI.DrawRect(rect, color);
}
public static void DrawEditorHorizontalLine(ref Rect rect, Color color, int thickness = 1, int padding = 10)
{
rect.height = thickness;
rect.y += padding / 2;
//rect.x -= 2;
//rect.width +=6;
EditorGUI.DrawRect(rect, color);
rect.y += padding;
rect.height = EditorGUIUtility.singleLineHeight;
}
public static void DrawWireCapsule(Vector3 position, Quaternion rotation, float radius, float height, Color color = default(Color))
{
if (color != default(Color))
Handles.color = color;
Matrix4x4 angleMatrix = Matrix4x4.TRS(position, rotation, Handles.matrix.lossyScale);
using (new Handles.DrawingScope(angleMatrix))
{
var pointOffset = (height - (radius * 2)) / 2;
//draw sideways
Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.left, Vector3.back, -180, radius);
Handles.DrawLine(new Vector3(0, pointOffset, -radius), new Vector3(0, -pointOffset, -radius));
Handles.DrawLine(new Vector3(0, pointOffset, radius), new Vector3(0, -pointOffset, radius));
Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.left, Vector3.back, 180, radius);
//draw frontways
Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.back, Vector3.left, 180, radius);
Handles.DrawLine(new Vector3(-radius, pointOffset, 0), new Vector3(-radius, -pointOffset, 0));
Handles.DrawLine(new Vector3(radius, pointOffset, 0), new Vector3(radius, -pointOffset, 0));
Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.back, Vector3.left, -180, radius);
//draw center
Handles.DrawWireDisc(Vector3.up * pointOffset, Vector3.up, radius);
Handles.DrawWireDisc(Vector3.down * pointOffset, Vector3.up, radius);
}
}
public static void DrawArray(SerializedProperty rootProperty, string namePropertyString = null, bool showAddElement = true, bool removeIconToTheRight = true)
{
if (!rootProperty.isArray)
return;
for (int i = 0; i < rootProperty.arraySize; i++)
{
SerializedProperty item = rootProperty.GetArrayElementAtIndex(i);
item.isExpanded = true;
GUILayout.BeginVertical(EditorStyles.helpBox);
// if( removeIconToTheRight )
// GUILayout.BeginHorizontal();
CustomUtilities.DrawArrayElement(item, namePropertyString);
GUILayout.Space(20);
if (GUILayout.Button("Remove element", EditorStyles.miniButton))
{
rootProperty.DeleteArrayElementAtIndex(i);
break;
}
// if( removeIconToTheRight )
// GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUILayout.Space(20);
}
if (showAddElement)
if (GUILayout.Button("Add element"))
rootProperty.arraySize++;
}
public static void DrawArrayElement(SerializedProperty property, string namePropertyString = null, bool skipFirstChild = false)
{
// if( property.isArray )
// return;
EditorGUI.indentLevel++;
SerializedProperty nameProperty = null;
if (namePropertyString != null)
{
nameProperty = property.FindPropertyRelative(namePropertyString);
if (nameProperty != null)
{
string name = nameProperty.stringValue;
EditorGUILayout.LabelField(name, EditorStyles.boldLabel);
}
EditorGUI.indentLevel++;
}
SerializedProperty itr = property.Copy();
bool enterChildren = true;
while (itr.Next(enterChildren))
{
if (SerializedProperty.EqualContents(itr, property.GetEndProperty()))
break;
if (enterChildren && skipFirstChild)
{
enterChildren = false;
continue;
}
EditorGUILayout.PropertyField(itr, enterChildren);
enterChildren = false;
}
EditorGUI.indentLevel = nameProperty != null ? EditorGUI.indentLevel - 2 : EditorGUI.indentLevel - 1;
}
public static void DrawArrayElement(Rect rect, SerializedProperty property, string namePropertyString = null, bool skipFirstChild = false)
{
if (property.isArray)
return;
EditorGUI.indentLevel++;
SerializedProperty nameProperty = null;
if (namePropertyString != null)
{
nameProperty = property.FindPropertyRelative(namePropertyString);
if (nameProperty != null)
{
string name = nameProperty.stringValue;
EditorGUI.LabelField(rect, name, EditorStyles.boldLabel);
rect.y += rect.height;
}
EditorGUI.indentLevel++;
}
SerializedProperty itr = property.Copy();
bool enterChildren = true;
while (itr.Next(enterChildren))
{
if (SerializedProperty.EqualContents(itr, property.GetEndProperty()))
break;
if (enterChildren && skipFirstChild)
{
enterChildren = false;
continue;
}
EditorGUI.PropertyField(rect, itr, enterChildren);
rect.y += rect.height;
enterChildren = false;
}
EditorGUI.indentLevel = nameProperty != null ? EditorGUI.indentLevel - 2 : EditorGUI.indentLevel - 1;
}
#endif
}
}