This commit is contained in:
CortexCore
2023-10-04 16:50:27 +08:00
parent 947e52e748
commit 5cd094ed9a
263 changed files with 144068 additions and 66 deletions

View File

@@ -0,0 +1,38 @@
using UnityEngine;
using Lightbug.CharacterControllerPro.Core;
namespace Lightbug.CharacterControllerPro.Demo
{
/// <summary>
/// A "KinematicPlatform" implementation whose movement and rotation is defined by an action (movement and/or rotation).
/// </summary>
[AddComponentMenu("Character Controller Pro/Demo/Dynamic Platform/Action Based Platform")]
public class ActionBasedPlatform : Platform
{
[SerializeField]
protected MovementAction movementAction = new MovementAction();
[SerializeField]
protected RotationAction rotationAction = new RotationAction();
void Start()
{
movementAction.Initialize(transform);
rotationAction.Initialize(transform);
}
void FixedUpdate()
{
float dt = Time.deltaTime;
Vector3 position = RigidbodyComponent.Position;
Quaternion rotation = RigidbodyComponent.Rotation;
movementAction.Tick(dt, ref position);
rotationAction.Tick(dt, ref position, ref rotation);
RigidbodyComponent.MoveAndRotate(position, rotation);
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Lightbug.CharacterControllerPro.Core;
namespace Lightbug.CharacterControllerPro.Demo
{
public class ConveyorBeltPlatform : Platform
{
[SerializeField]
protected MovementAction movementAction = new MovementAction();
void Start()
{
movementAction.Initialize(transform);
StartCoroutine(PostSimulationUpdate());
}
Vector3 preSimulationPosition = Vector3.zero;
void FixedUpdate()
{
float dt = Time.deltaTime;
preSimulationPosition = RigidbodyComponent.Position;
Vector3 position = preSimulationPosition;
movementAction.Tick(dt, ref position);
RigidbodyComponent.Move(position);
}
IEnumerator PostSimulationUpdate()
{
YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
while (true)
{
yield return waitForFixedUpdate;
RigidbodyComponent.Position = preSimulationPosition;
}
}
}
}

View File

@@ -0,0 +1,231 @@
using UnityEngine;
using Lightbug.Utilities;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Lightbug.CharacterControllerPro.Demo
{
/// <summary>
/// This class represents a movement action, used by the ActionBasedPlatform component.
/// </summary>
[System.Serializable]
public class MovementAction
{
[SerializeField]
bool enabled = true;
[SerializeField]
bool useWorldCoordinates = true;
[SerializeField]
bool infiniteDuration = false;
[Min(0f)]
[SerializeField]
float cycleDuration = 2f;
[SerializeField]
bool waitAtTheEnd = true;
[Min(0f)]
[SerializeField]
float waitDuration = 1f;
[SerializeField]
Vector3 direction = Vector3.up;
[Min(0f)]
[SerializeField]
float speed = 2f;
Transform transform = null;
Vector3 initialLocalDirection;
public void Initialize(Transform transform)
{
this.transform = transform;
initialLocalDirection = transform.InverseTransformVectorUnscaled(direction);
}
Vector3 actionVector = Vector3.zero;
public Vector3 ActionVector
{
get
{
return actionVector;
}
}
public void Tick(float dt, ref Vector3 position)
{
if (!enabled)
return;
time += dt;
if (isWaiting)
{
if (time >= waitDuration)
{
time = 0f;
isWaiting = false;
}
actionVector = Vector3.zero;
}
else
{
if (!infiniteDuration && time >= cycleDuration)
{
time = 0;
if (useWorldCoordinates)
direction = -direction;
else
initialLocalDirection = -initialLocalDirection;
if (waitAtTheEnd)
isWaiting = true;
}
if (isWaiting)
actionVector = Vector3.zero;
else
actionVector = CustomUtilities.Multiply(
useWorldCoordinates ? direction : initialLocalDirection,
speed,
dt
);
}
position += actionVector;
}
public void ResetTimer()
{
time = 0f;
}
float time = 0f;
bool isWaiting = false;
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(MovementAction))]
public class MovementActionDrawer : PropertyDrawer
{
SerializedProperty enabled = null;
SerializedProperty useWorldCoordinates = null;
SerializedProperty infiniteDuration = null;
SerializedProperty cycleDuration = null;
SerializedProperty waitAtTheEnd = null;
SerializedProperty waitDuration = null;
SerializedProperty direction = null;
SerializedProperty speed = null;
float size = 0f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
enabled = property.FindPropertyRelative("enabled");
useWorldCoordinates = property.FindPropertyRelative("useWorldCoordinates");
infiniteDuration = property.FindPropertyRelative("infiniteDuration");
cycleDuration = property.FindPropertyRelative("cycleDuration");
waitAtTheEnd = property.FindPropertyRelative("waitAtTheEnd");
waitDuration = property.FindPropertyRelative("waitDuration");
direction = property.FindPropertyRelative("direction");
speed = property.FindPropertyRelative("speed");
// ----------------------------------------------------------------------------------
Rect fieldRect = position;
fieldRect.height = EditorGUIUtility.singleLineHeight;
Rect backgroundRect = position;
GUI.Box(backgroundRect, "", EditorStyles.helpBox);
fieldRect.y += 0.25f * fieldRect.height;
fieldRect.x += 5f;
fieldRect.width = 20f;
EditorGUI.PropertyField(fieldRect, enabled, GUIContent.none);
fieldRect.x += 20f;
fieldRect.width = position.width;
EditorGUI.LabelField(fieldRect, "Movement", EditorStyles.boldLabel);
fieldRect.x = position.x + 20f;
fieldRect.y += 1.5f * fieldRect.height;
fieldRect.width = position.width - 25;
if (enabled.boolValue)
{
EditorGUI.PropertyField(fieldRect, useWorldCoordinates);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, infiniteDuration);
fieldRect.y += fieldRect.height;
if (!infiniteDuration.boolValue)
{
EditorGUI.PropertyField(fieldRect, cycleDuration);
fieldRect.y += fieldRect.height;
}
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, waitAtTheEnd);
fieldRect.y += fieldRect.height;
if (waitAtTheEnd.boolValue)
{
EditorGUI.PropertyField(fieldRect, waitDuration);
fieldRect.y += fieldRect.height;
}
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, direction);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, speed);
fieldRect.y += fieldRect.height;
fieldRect.y += 0.5f * fieldRect.height;
}
size = fieldRect.y - position.y;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return size;
}
public override bool CanCacheInspectorGUI(SerializedProperty property)
{
return false;
}
}
#endif
}

View File

@@ -0,0 +1,310 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Lightbug.CharacterControllerPro.Core;
using Lightbug.Utilities;
namespace Lightbug.CharacterControllerPro.Demo
{
/// <summary>
/// A "KinematicPlatform" implementation whose movement and rotation are purely based on nodes. Use this component to create platforms that moves and
/// rotate precisely following a predefined path.
/// </summary>
[AddComponentMenu("Character Controller Pro/Demo/Dynamic Platform/Node Based Platform")]
public class NodeBasedPlatform : Platform
{
public enum SequenceType
{
Rewind,
Loop,
OneWay
}
enum ActionState
{
Idle,
Ready,
Waiting,
Working,
Done
}
//[Header("Debug Options")]
[SerializeField] bool drawHandles = true;
public bool DrawHandles
{
get
{
return drawHandles;
}
}
//[Header("Actions")]
public bool move = true;
public bool rotate = false;
[SerializeField]
List<PlatformNode> actionsList = new List<PlatformNode>();
public List<PlatformNode> ActionsList
{
get
{
return actionsList;
}
}
public SequenceType sequenceType;
public bool positiveSequenceDirection = true;
[Range(0.1f, 50)]
[SerializeField]
float globalSpeedModifier = 1;
ActionState actionState;
Vector3 targetPosition;
Vector3 targetRotation;
Vector3 startingPosition;
Vector3 startingRotation;
bool updateInitialPosition = true;
public bool UpdateInitialPosition
{
get
{
return updateInitialPosition;
}
}
Vector3 initialPosition;
public Vector3 InitialPosition
{
get
{
return initialPosition;
}
}
float time = 0;
PlatformNode currentAction = null;
int currentActionIndex = 0;
public int CurrentActionIndex
{
get
{
return currentActionIndex;
}
}
protected override void Awake()
{
base.Awake();
updateInitialPosition = false;
initialPosition = transform.position;
actionState = ActionState.Ready;
currentActionIndex = 0;
currentAction = actionsList[0];
}
void FixedUpdate()
{
float dt = Time.deltaTime;
switch (actionState)
{
case ActionState.Idle:
break;
case ActionState.Ready:
SetTargets();
actionState = ActionState.Working;
break;
case ActionState.Working:
time += dt * globalSpeedModifier;
if (time >= currentAction.targetTime)
{
actionState = ActionState.Done;
time = 0;
}
else
{
if (move)
RigidbodyComponent.Move(CalculatePosition());
Quaternion rotation = RigidbodyComponent.Rotation;
if (rotate)
RigidbodyComponent.Rotate(CalculateRotation());
}
break;
case ActionState.Done:
time = 0;
if (positiveSequenceDirection)
{
if (currentActionIndex != (actionsList.Count - 1))
{
currentActionIndex++;
actionState = ActionState.Ready;
}
else
{
switch (sequenceType)
{
case SequenceType.Loop:
currentActionIndex = 0;
actionState = ActionState.Ready;
break;
case SequenceType.Rewind:
currentActionIndex--;
positiveSequenceDirection = false;
actionState = ActionState.Ready;
break;
case SequenceType.OneWay:
actionState = ActionState.Idle;
break;
}
}
}
else
{
if (currentActionIndex != 0)
{
currentActionIndex--;
actionState = ActionState.Ready;
}
else
{
switch (sequenceType)
{
case SequenceType.Loop:
currentActionIndex = actionsList.Count - 1;
actionState = ActionState.Ready;
break;
case SequenceType.Rewind:
currentActionIndex++;
positiveSequenceDirection = true;
actionState = ActionState.Ready;
break;
case SequenceType.OneWay:
actionState = ActionState.Idle;
break;
}
}
}
currentAction = actionsList[currentActionIndex];
break;
}
}
public override string ToString()
{
return "Current Index = " + currentActionIndex + '\n' +
"State = " + actionState;
}
void SetTargets()
{
startingPosition = transform.position;
startingRotation = transform.eulerAngles;
targetPosition = initialPosition + currentAction.position;
targetRotation = currentAction.eulerAngles;
}
Vector3 CalculatePosition()
{
float curveTime = time / currentAction.targetTime;
Vector3 position = Vector3.Lerp(
startingPosition,
this.targetPosition,
currentAction.movementCurve.Evaluate(curveTime)
);
return position;
}
Quaternion CalculateRotation()
{
float curveTime = time / currentAction.targetTime;
float curveResult = currentAction.rotationCurve.Evaluate(curveTime);
Vector3 finalAngle;
finalAngle.x = Mathf.LerpAngle(startingRotation.x, this.targetRotation.x, curveResult);
finalAngle.y = Mathf.LerpAngle(startingRotation.y, this.targetRotation.y, curveResult);
finalAngle.z = Mathf.LerpAngle(startingRotation.z, this.targetRotation.z, curveResult);
Quaternion rotation = Quaternion.Euler(finalAngle);
return rotation;
}
}
}

View File

@@ -0,0 +1,312 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using Lightbug.Utilities;
namespace Lightbug.CharacterControllerPro.Demo
{
[CustomEditor(typeof(NodeBasedPlatform), true)]
public class NodeBasedPlatformEditor : Editor
{
NodeBasedPlatform monoBehaviour;
Transform transform;
ReorderableList reorderableList = null;
#region Properties
SerializedProperty drawHandles = null;
SerializedProperty move = null;
SerializedProperty rotate = null;
SerializedProperty actionsList = null;
SerializedProperty sequenceType;
SerializedProperty positiveSequenceDirection = null;
SerializedProperty globalSpeedModifier = null;
#endregion
int deletedObjectIndex = -1;
GUIStyle style = new GUIStyle();
void OnEnable()
{
monoBehaviour = (NodeBasedPlatform)target;
transform = monoBehaviour.GetComponent<Transform>();
style.fontSize = 25;
style.normal.textColor = Color.white;
drawHandles = serializedObject.FindProperty("drawHandles");
move = serializedObject.FindProperty("move");
rotate = serializedObject.FindProperty("rotate");
actionsList = serializedObject.FindProperty("actionsList");
sequenceType = serializedObject.FindProperty("sequenceType");
positiveSequenceDirection = serializedObject.FindProperty("positiveSequenceDirection");
globalSpeedModifier = serializedObject.FindProperty("globalSpeedModifier");
reorderableList = new ReorderableList(
serializedObject,
actionsList,
true,
false,
false,
false
);
//reorderableList.headerHeight = 0f;
reorderableList.footerHeight = 0f;
reorderableList.drawElementCallback += OnDrawElement;
reorderableList.elementHeightCallback += OnElementHeight;
reorderableList.onAddCallback += OnAddElement;
reorderableList.drawHeaderCallback += OnDrawHeader;
}
void OnDisable()
{
reorderableList.drawElementCallback -= OnDrawElement;
reorderableList.elementHeightCallback -= OnElementHeight;
reorderableList.onAddCallback -= OnAddElement;
reorderableList.drawHeaderCallback -= OnDrawHeader;
}
void OnDrawHeader(Rect rect)
{
GUI.Label(rect, "Nodes");
}
void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
GUI.Box(rect, "", EditorStyles.helpBox);
SerializedProperty element = actionsList.GetArrayElementAtIndex(index);
Rect fieldRect = rect;
fieldRect.x += 4;
fieldRect.width -= 8;
fieldRect.height = EditorGUI.GetPropertyHeight(element);
fieldRect.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(fieldRect, element);
fieldRect.y += fieldRect.height + EditorGUIUtility.singleLineHeight;
Rect buttonRect = fieldRect;
buttonRect.height = EditorGUIUtility.singleLineHeight;
if (GUI.Button(buttonRect, "x"))
{
deletedObjectIndex = index;
}
}
float OnElementHeight(int index)
{
SerializedProperty element = actionsList.GetArrayElementAtIndex(index);
return EditorGUI.GetPropertyHeight(element) + 4 * EditorGUIUtility.singleLineHeight;
}
void OnAddElement(ReorderableList list)
{
actionsList.arraySize++;
SerializedProperty element = actionsList.GetArrayElementAtIndex(actionsList.arraySize - 1);
// PlatformNode node = monobehaviour.ActionsList[ monobehaviour.ActionsList.Count ];
// node = new PlatformNode();
// PlatformNode node = element.objectReferenceValue as PlatformNode;
// node = new PlatformNode();
// //node.Initialize();
// //actionsList.
}
void OnSceneGUI()
{
if (!monoBehaviour.enabled)
return;
if (transform == null)
transform = monoBehaviour.GetComponent<Transform>();
if (!monoBehaviour.DrawHandles)
return;
for (int i = 0; i < monoBehaviour.ActionsList.Count; i++)
{
Vector3 position = monoBehaviour.UpdateInitialPosition ? transform.position : monoBehaviour.InitialPosition;
DrawHandle(position, monoBehaviour.ActionsList[i]);
DrawText(position, monoBehaviour.ActionsList[i], i);
if (i > 0)
{
//Line between nodes
Handles.color = new Color(1, 1, 1, 0.2f);
Handles.DrawDottedLine(position + monoBehaviour.ActionsList[i].position,
position + monoBehaviour.ActionsList[i - 1].position, 2);
Handles.color = new Color(1, 1, 1, 0.8f);
//Middle
Vector3 middle = ((position + monoBehaviour.ActionsList[i].position) + (position + monoBehaviour.ActionsList[i - 1].position)) / 2;
Vector3 direction = ((position + monoBehaviour.ActionsList[i].position) - (position + monoBehaviour.ActionsList[i - 1].position));
direction.Normalize();
float distance = ((position + monoBehaviour.ActionsList[i].position) - (position + monoBehaviour.ActionsList[i - 1].position)).magnitude;
float arrowSize = distance / 4;
Vector3 arrowPosition = middle - direction * arrowSize / 2;
if (direction != Vector3.zero)
DrawArrowCap(i, arrowPosition, Quaternion.LookRotation(direction, -Vector3.forward), arrowSize, EventType.Repaint);
if (monoBehaviour.sequenceType == NodeBasedPlatform.SequenceType.Loop)
{
if (i == (monoBehaviour.ActionsList.Count - 1))
{
Handles.color = new Color(1, 1, 1, 0.2f);
Handles.DrawDottedLine(position + monoBehaviour.ActionsList[i].position,
position + monoBehaviour.ActionsList[0].position, 2);
}
}
}
}
}
void DrawText(Vector3 referencePosition, PlatformNode currentAction, int index)
{
Vector3 TextPosition = referencePosition + currentAction.position;
style.fontSize = 25;
style.normal.textColor = Color.white;
Handles.Label(TextPosition, index.ToString(), style);
}
void DrawHandle(Vector3 referencePosition, PlatformNode currentAction)
{
float radius = 0.5f;
Handles.color = Color.white;
Handles.DrawWireDisc(referencePosition + currentAction.position, -Vector3.forward, radius);
Vector3[] lines = new Vector3[]{
referencePosition + currentAction.position + Vector3.up * radius ,
referencePosition + currentAction.position - Vector3.up * radius ,
referencePosition + currentAction.position + Vector3.right * radius ,
referencePosition + currentAction.position - Vector3.right * radius
};
Handles.DrawLines(lines);
//Position Handle
currentAction.position = Handles.PositionHandle(
referencePosition + currentAction.position, Quaternion.identity) - referencePosition;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
CustomUtilities.DrawMonoBehaviourField<NodeBasedPlatform>(monoBehaviour);
GUILayout.Space(10);
GUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.Label("Debug Options", EditorStyles.boldLabel);
GUILayout.Space(5);
EditorGUILayout.PropertyField(drawHandles);
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.Label("Actions", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(move);
EditorGUILayout.PropertyField(rotate);
reorderableList.DoLayoutList();
if (deletedObjectIndex != -1)
{
actionsList.DeleteArrayElementAtIndex(deletedObjectIndex);
deletedObjectIndex = -1;
}
if (GUILayout.Button("Add Node", EditorStyles.miniButton))
{
monoBehaviour.ActionsList.Add(new PlatformNode());
}
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.Label("Properties", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(sequenceType);
EditorGUILayout.PropertyField(positiveSequenceDirection);
EditorGUILayout.PropertyField(globalSpeedModifier);
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
//SceneView.RepaintAll();
}
void DrawArrowCap(int controlID, Vector3 position, Quaternion rotation, float size, EventType eventType)
{
#if UNITY_5_6_OR_NEWER
Handles.ArrowHandleCap(controlID, position, rotation, size, eventType);
#else
Handles.ArrowCap( controlID , position , rotation , size );
#endif
}
}
}
#endif

View File

@@ -0,0 +1,34 @@
using UnityEngine;
using Lightbug.Utilities;
namespace Lightbug.CharacterControllerPro.Demo
{
/// <summary>
/// This abstract class represents a basic platform.
/// </summary>
public abstract class Platform : MonoBehaviour
{
/// <summary>
/// Gets the RigidbodyComponent component associated to the character.
/// </summary>
public RigidbodyComponent RigidbodyComponent { get; protected set; }
protected virtual void Awake()
{
RigidbodyComponent = RigidbodyComponent.CreateInstance(gameObject);
if (RigidbodyComponent == null)
{
Debug.Log("(2D/3D)Rigidbody component not found! \nDynamic platforms must have a Rigidbody component associated.");
this.enabled = false;
}
}
}
}

View File

@@ -0,0 +1,91 @@
using UnityEngine;
using Lightbug.Utilities;
namespace Lightbug.CharacterControllerPro.Demo
{
#if UNITY_EDITOR
using UnityEditor;
#endif
[System.Serializable]
public class PlatformNode
{
public Vector3 position = Vector3.zero;
public Vector3 eulerAngles = Vector3.zero;
public AnimationCurve movementCurve = AnimationCurve.Linear(0, 0, 1, 1);
public AnimationCurve rotationCurve = AnimationCurve.Linear(0, 0, 1, 1);
[Min(0f)]
public float targetTime = 1;
public void Initialize()
{
position = Vector3.zero;
eulerAngles = Vector3.zero;
movementCurve = AnimationCurve.Linear(0, 0, 1, 1);
rotationCurve = AnimationCurve.Linear(0, 0, 1, 1);
targetTime = 1;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(PlatformNode))]
public class PlatformNodeDrawer : PropertyDrawer
{
SerializedProperty position = null;
SerializedProperty eulerAngles = null;
SerializedProperty movementCurve = null;
SerializedProperty rotationCurve = null;
SerializedProperty targetTime = null;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
this.position = property.FindPropertyRelative("position");
this.eulerAngles = property.FindPropertyRelative("eulerAngles");
this.movementCurve = property.FindPropertyRelative("movementCurve");
this.rotationCurve = property.FindPropertyRelative("rotationCurve");
this.targetTime = property.FindPropertyRelative("targetTime");
Rect fieldRect = position;
fieldRect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(fieldRect, this.position);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, this.eulerAngles);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, this.movementCurve);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, this.rotationCurve);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, this.targetTime);
fieldRect.y += fieldRect.height;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 5 * EditorGUIUtility.singleLineHeight;
}
}
#endif
}

View File

@@ -0,0 +1,234 @@
using UnityEngine;
using Lightbug.Utilities;
namespace Lightbug.CharacterControllerPro.Demo
{
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary>
/// This class represents a rotation action, used by the ActionBasedPlatform component.
/// </summary>
[System.Serializable]
public class RotationAction
{
[SerializeField]
bool enabled = true;
[SerializeField]
bool infiniteDuration = false;
[Min(0f)]
[SerializeField]
float cycleDuration = 2f;
[SerializeField]
bool waitAtTheEnd = true;
[Min(0f)]
[SerializeField]
float waitDuration = 1f;
[SerializeField]
Vector3 direction = Vector3.up;
[Min(0f)]
[SerializeField]
float speed = 2f;
[SerializeField]
Transform pivotObject = null;
Transform transform = null;
public void Initialize(Transform transform)
{
this.transform = transform;
}
Vector3 actionVector = Vector3.zero;
public Vector3 ActionVector
{
get
{
return actionVector;
}
}
public void Tick(float dt, ref Vector3 position, ref Quaternion rotation)
{
if (!enabled)
return;
time += dt;
if (isWaiting)
{
if (time > waitDuration)
{
time = 0f;
isWaiting = false;
}
actionVector = Vector3.zero;
}
else
{
if (!infiniteDuration && time > cycleDuration)
{
time = 0;
direction = -direction;
if (waitAtTheEnd)
isWaiting = true;
}
if (isWaiting)
actionVector = Vector3.zero;
else
actionVector = CustomUtilities.Multiply(direction, speed, dt);
}
if (pivotObject != null)
RotateAround(ref position, ref rotation, dt);
else
rotation *= Quaternion.AngleAxis(speed * dt, direction);
}
void RotateAround(ref Vector3 position, ref Quaternion rotation, float dt)
{
Vector3 delta = position - pivotObject.position;
Quaternion thisRotation = Quaternion.AngleAxis(speed * dt, direction);
delta = thisRotation * delta;
position = pivotObject.position + delta;
rotation = rotation * thisRotation;
}
public void ResetTimer()
{
time = 0f;
}
float time = 0f;
bool isWaiting = false;
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(RotationAction))]
public class RotationActionDrawer : PropertyDrawer
{
SerializedProperty enabled = null;
SerializedProperty infiniteDuration = null;
SerializedProperty cycleDuration = null;
SerializedProperty waitAtTheEnd = null;
SerializedProperty waitDuration = null;
SerializedProperty direction = null;
SerializedProperty speed = null;
SerializedProperty pivotObject = null;
float size = 0f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
enabled = property.FindPropertyRelative("enabled");
infiniteDuration = property.FindPropertyRelative("infiniteDuration");
cycleDuration = property.FindPropertyRelative("cycleDuration");
waitAtTheEnd = property.FindPropertyRelative("waitAtTheEnd");
waitDuration = property.FindPropertyRelative("waitDuration");
direction = property.FindPropertyRelative("direction");
speed = property.FindPropertyRelative("speed");
pivotObject = property.FindPropertyRelative("pivotObject");
// ----------------------------------------------------------------------------------
Rect fieldRect = position;
fieldRect.height = EditorGUIUtility.singleLineHeight;
Rect backgroundRect = position;
GUI.Box(backgroundRect, "", EditorStyles.helpBox);
fieldRect.y += 0.25f * fieldRect.height;
fieldRect.x += 5f;
fieldRect.width = 20f;
EditorGUI.PropertyField(fieldRect, enabled, GUIContent.none);
fieldRect.x += 20f;
fieldRect.width = position.width;
EditorGUI.LabelField(fieldRect, "Rotation", EditorStyles.boldLabel);
fieldRect.x = position.x + 20f;
fieldRect.y += 1.5f * fieldRect.height;
fieldRect.width = position.width - 25;
if (enabled.boolValue)
{
EditorGUI.PropertyField(fieldRect, infiniteDuration);
fieldRect.y += fieldRect.height;
if (!infiniteDuration.boolValue)
{
EditorGUI.PropertyField(fieldRect, cycleDuration);
fieldRect.y += fieldRect.height;
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, waitAtTheEnd);
fieldRect.y += fieldRect.height;
if (waitAtTheEnd.boolValue)
{
EditorGUI.PropertyField(fieldRect, waitDuration);
fieldRect.y += fieldRect.height;
}
}
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, direction);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, speed);
fieldRect.y += fieldRect.height;
EditorGUI.PropertyField(fieldRect, pivotObject);
fieldRect.y += fieldRect.height;
fieldRect.y += 0.5f * fieldRect.height;
}
size = fieldRect.y - position.y;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return size;
}
}
#endif
}