1
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
||||
|
||||
}
|
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
||||
|
||||
}
|
@@ -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
|
||||
|
||||
}
|
Reference in New Issue
Block a user