Mercurial > hg > Game > Games
diff Orchestland/Assets/LeapMotion/Widgets/Scripts/Dial/DialModeBase.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/Dial/DialModeBase.cs Fri Jul 17 23:09:20 2015 +0900 @@ -0,0 +1,206 @@ +using UnityEngine; +using System.Collections; +//using VRWidgets; + +namespace LMWidgets +{ + [RequireComponent(typeof(Rigidbody))] + public class DialModeBase : MonoBehaviour + { + [SerializeField] + private float + minimumAngle = 0f; + [SerializeField] + private float + maximumAngle = 360f; + public int steps = 0; // Do not snap to steps when <= 0 + + private bool interacting_ = false; // If a GameObject is destroyed OnExit will not be called + private GameObject target_ = null; // Intersecting object that controls position + private Vector3 pivot_ = Vector3.zero; // Local position of first intersection + + private float prev_angle_ = 0f; + private float curr_angle_ = 0f; + public DialGraphics dialGraphics; + + // Standardize Minimum & Maximum + void Awake () + { + //GetComponent<Collider>().isTrigger = true; + GetComponent<Rigidbody>().isKinematic = true; + if (minimumAngle == maximumAngle) { + // Use default ranges + minimumAngle = 0f; + maximumAngle = 360f; + return; + } + if (minimumAngle > maximumAngle) { + // Ensure correct orientation + float swap = minimumAngle; + minimumAngle = maximumAngle; + maximumAngle = swap; + } + float over = maximumAngle - minimumAngle - 360f; + if (over > 0f) { + // restrict range + maximumAngle -= over / 2f; + minimumAngle += over / 2f; + } + } + + void OnEnable () + { + if (steps > 0) + SnapToStep (); + } + + void OnDisable () + { + // Avoid lingering references to exited objects + //if (interacting_) Debug.Log ("NEVER STOPPED INTERACTING"); + //if (target_ != null) Debug.Log ("TARGET WAS NOT RELEASED"); + EndInteraction (); + } + + // Maps angle to the range (-180, 180] + protected float MinAngleToZero (float angle) + { + float minAngle = angle % 360f; + if (minAngle > 180f) + minAngle = minAngle - 360f; + if (minAngle <= -180f) + minAngle = 360f + minAngle; + return minAngle; + } + + // Restrictions to min & max evenly divide the out-of-range angles + protected float RestrictAngle (float setAngle) + { + float acceptDivider = (maximumAngle + minimumAngle) / 2f; // midpoint of acceptance region + float resAngle = MinAngleToZero (setAngle - acceptDivider); + if (resAngle > maximumAngle - acceptDivider) + resAngle = maximumAngle - acceptDivider; + if (resAngle < minimumAngle - acceptDivider) + resAngle = minimumAngle - acceptDivider; + resAngle += acceptDivider; + return resAngle; + } + + protected int RestrictStep (float setAngle) + { + float setFraction = (RestrictAngle (setAngle) - minimumAngle) / (maximumAngle - minimumAngle); + int resStep = (int)((steps * setFraction) + 0.5f); + if (resStep == steps) + // When setAngle == maximumAngle int rounding will not yield a reduction + resStep = steps - 1; + return resStep; + } + + // CurrentAngle ranges from minimumAngle to maximumAngle + public float CurrentAngle { + get { + return RestrictAngle (transform.localRotation.eulerAngles.y); + } + set { +// Debug.Log ("DialModeBase.CurrentAngle is being set to: " + value); + Vector3 eulerAngles = transform.localRotation.eulerAngles; + eulerAngles.x = 0f; + eulerAngles.y = RestrictAngle (value); + eulerAngles.z = 0f; + transform.localRotation = Quaternion.Euler (eulerAngles); + } + } + + // CurrentStep ranges from 0 to steps-1 + public int CurrentStep { + get { + return RestrictStep (transform.localRotation.eulerAngles.y); + } + set { +// Debug.Log ("DialModeBase.CurrentStep is being set to: " + value); + if (steps <= 0) + return; + CurrentAngle = (value * (maximumAngle - minimumAngle) / steps) + minimumAngle; + } + } + + private bool IsHand (Collider other) + { + return other.transform.parent && other.transform.parent.parent && other.transform.parent.parent.GetComponent<HandModel> (); + } + + void OnTriggerEnter (Collider other) + { + if (target_ == null && IsHand (other)) { + target_ = other.gameObject; + pivot_ = transform.InverseTransformPoint (target_.transform.position) - transform.localPosition; + if (GetComponent<Rigidbody>().isKinematic == false) + transform.GetComponent<Rigidbody>().angularVelocity = Vector3.zero; + interacting_ = true; + if (dialGraphics) + dialGraphics.HilightDial (); + } + } + + void OnTriggerExit (Collider other) + { + if (other.gameObject == target_) { + EndInteraction (); + } + } + + void EndInteraction () + { + target_ = null; + if (steps > 0) { + SnapToStep (); + } else { + float FPS_INVERSE = 1f / Time.deltaTime; + float angular_velocity = (curr_angle_ - prev_angle_) * FPS_INVERSE; + transform.GetComponent<Rigidbody>().AddRelativeTorque (new Vector3 (0f, 0f, angular_velocity)); + } + interacting_ = false; + // NOTE: External update should following internal state update, + // so that exceptions in external update do not yield inconsistent state + if (dialGraphics) + dialGraphics.UpdateDial (); + } + + protected virtual void ApplyRotations () + { + Vector3 curr_direction = transform.InverseTransformPoint (target_.transform.position) - transform.localPosition; + transform.localRotation = Quaternion.FromToRotation (pivot_, curr_direction) * transform.localRotation; + } + + protected virtual void ApplyConstraints () + { + Vector3 rotation = transform.localRotation.eulerAngles; + rotation.x = 0f; + // Allow dial manipulation to exceed range - it will snap back when released + prev_angle_ = curr_angle_; + curr_angle_ = rotation.y; + rotation.z = 0f; + transform.localRotation = Quaternion.Euler (rotation); + } + + protected virtual void SnapToStep () + { + CurrentStep = CurrentStep; + ApplyConstraints (); + } + + void FixedUpdate () + { + if (target_ == null && interacting_) { + // Hand destroyed while interacting + //Debug.Log ("HAND DESTROYED WHILE INTERACTING"); + EndInteraction (); + } + if (target_ != null) { + ApplyRotations (); + } + ApplyConstraints (); + } + } +} +