Mercurial > hg > Game > Games
diff Orchestland/Assets/LeapMotion/Widgets/Scripts/Physics/LeapPhysicsBase.cs @ 1:f7675884f2a1
Add Orchestland project
author | Daiki OYAKAWA <e135764@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2015 23:09:20 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orchestland/Assets/LeapMotion/Widgets/Scripts/Physics/LeapPhysicsBase.cs Fri Jul 17 23:09:20 2015 +0900 @@ -0,0 +1,174 @@ +using System; +using UnityEngine; + +namespace LMWidgets +{ + public enum LeapPhysicsState + { + Interacting, // Responsible for moving the widgets with the fingers + Reflecting, // Responsible for reflecting widget information and simulating the physics + Disabled // State in which the widget is disabled + } + + /// <summary> + /// Base class for physics. + /// Handles state changes between Interacting and Reflecting. + /// </summary> + public abstract class LeapPhysicsBase : MonoBehaviour + { + protected event EventHandler<LMWidgets.EventArg<LeapPhysicsState>> StateChangeHandler; + + private LeapPhysicsState m_state = LeapPhysicsState.Reflecting; // Don't set this directly. Use accessor. + protected GameObject m_target = null; + protected Vector3 m_pivot = Vector3.zero; + protected Vector3 m_targetPivot = Vector3.zero; + + /// <summary> + /// Represents the current Physics state. + /// </summary> + /// <remarks> + /// Use this property to set the state rather than the m_state field so that proper events and functions are called on changes. + /// Chaning the property will also call onInteractionEnabled and onInteractionDisabled as appropritate. + /// </remarks> + protected LeapPhysicsState State { + get { + return m_state; + } + set { + + // Call enabled and disabled functions as appropriate. + if ( m_state != LeapPhysicsState.Disabled && value == LeapPhysicsState.Disabled ) { + onInteractionDisabled(); + } + else if ( m_state == LeapPhysicsState.Disabled && value != LeapPhysicsState.Disabled ) { + onInteractionEnabled(); + } + + m_state = value; // Update underlying value + + // Fire changed event + EventHandler<LMWidgets.EventArg<LeapPhysicsState>> handler = StateChangeHandler; + if ( handler != null ) { handler(this, new EventArg<LeapPhysicsState>(State)); } + } + } + + /// <summary> + /// Represents whether the widget is enabled or disabled. + /// </summary> + public bool Interactable { + get { + return !(State == LeapPhysicsState.Disabled); + } + set { + if (State == LeapPhysicsState.Disabled && value == true ) { + State = LeapPhysicsState.Reflecting; + } + else if (State != LeapPhysicsState.Disabled && value == false) { + State = LeapPhysicsState.Disabled; + } + } + } + + // Apply the physics interactions when the hand is no longer interacting with the object + protected abstract void ApplyPhysics(); + // Apply interactions with the objects + protected abstract void ApplyInteractions(); + // Apply constraints for the object (e.g. Constrain movements along a specific axis) + protected abstract void ApplyConstraints(); + + /// <summary> + /// Called when widget becomes interactable. + /// </summary> + /// <remarks> + /// Implement this function to handle changes to the widget when interaction is enabled (ie. starting an enable animation) + /// </remarks> + protected virtual void onInteractionEnabled() {} + /// <summary> + /// Called when widget becomes non-interactable. + /// </summary> + /// <remarks> + /// Implement this function to handle changes to the widget when interaction is disabled (ie. starting a disable animation) + /// </remarks> + protected virtual void onInteractionDisabled() {} + + /// <summary> + /// Resets the pivots + /// </summary> + protected virtual void ResetPivots() + { + m_pivot = transform.localPosition; + if (m_target != null) + m_targetPivot = transform.parent.InverseTransformPoint(m_target.transform.position); + } + + /// <summary> + /// Returns true or false by checking if "HandModel" exits in the parent of the collider + /// </summary> + /// <param name="collider"></param> + /// <returns></returns> + private bool IsHand(Collider collider) + { + return collider.transform.parent && collider.transform.parent.parent && collider.transform.parent.parent.GetComponent<HandModel>(); + } + + /// <summary> + /// Change the state of the physics to "Interacting" if no other hands were interacting and if the collider is a hand + /// </summary> + /// <param name="collider"></param> + protected virtual void OnTriggerEnter(Collider collider) + { + if (m_target == null && IsHand(collider) && State != LeapPhysicsState.Disabled) + { + State = LeapPhysicsState.Interacting; + m_target = collider.gameObject; + ResetPivots(); + } + } + + /// <summary> + /// Change the state of the physics to "Reflecting" if the object exiting is the hand + /// </summary> + /// <param name="collider"></param> + protected virtual void OnTriggerExit(Collider collider) + { + // TODO: Use interpolation to determine if the hand should still continue interacting with the widget to solve low-FPS + // TODO(cont): It should solve low-FPS or fast hand movement problems + if (collider.gameObject == m_target) + { + State = LeapPhysicsState.Reflecting; + m_target = null; + } + } + + protected virtual void Awake() + { + if (GetComponent<Collider>() == null) + { + Debug.LogWarning("This Widget lacks a collider. Will not function as expected."); + } + } + + protected virtual void FixedUpdate() + { + if (m_target == null && State == LeapPhysicsState.Interacting) + { + State = LeapPhysicsState.Reflecting; + } + + switch (State) + { + case LeapPhysicsState.Interacting: + ApplyInteractions(); + break; + case LeapPhysicsState.Reflecting: + ApplyPhysics(); + break; + case LeapPhysicsState.Disabled: + break; + default: + break; + } + ApplyConstraints(); + } + } +}