comparison 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
comparison
equal deleted inserted replaced
0:347d21cdfc22 1:f7675884f2a1
1 using UnityEngine;
2 using System.Collections;
3 //using VRWidgets;
4
5 namespace LMWidgets
6 {
7 [RequireComponent(typeof(Rigidbody))]
8 public class DialModeBase : MonoBehaviour
9 {
10 [SerializeField]
11 private float
12 minimumAngle = 0f;
13 [SerializeField]
14 private float
15 maximumAngle = 360f;
16 public int steps = 0; // Do not snap to steps when <= 0
17
18 private bool interacting_ = false; // If a GameObject is destroyed OnExit will not be called
19 private GameObject target_ = null; // Intersecting object that controls position
20 private Vector3 pivot_ = Vector3.zero; // Local position of first intersection
21
22 private float prev_angle_ = 0f;
23 private float curr_angle_ = 0f;
24 public DialGraphics dialGraphics;
25
26 // Standardize Minimum & Maximum
27 void Awake ()
28 {
29 //GetComponent<Collider>().isTrigger = true;
30 GetComponent<Rigidbody>().isKinematic = true;
31 if (minimumAngle == maximumAngle) {
32 // Use default ranges
33 minimumAngle = 0f;
34 maximumAngle = 360f;
35 return;
36 }
37 if (minimumAngle > maximumAngle) {
38 // Ensure correct orientation
39 float swap = minimumAngle;
40 minimumAngle = maximumAngle;
41 maximumAngle = swap;
42 }
43 float over = maximumAngle - minimumAngle - 360f;
44 if (over > 0f) {
45 // restrict range
46 maximumAngle -= over / 2f;
47 minimumAngle += over / 2f;
48 }
49 }
50
51 void OnEnable ()
52 {
53 if (steps > 0)
54 SnapToStep ();
55 }
56
57 void OnDisable ()
58 {
59 // Avoid lingering references to exited objects
60 //if (interacting_) Debug.Log ("NEVER STOPPED INTERACTING");
61 //if (target_ != null) Debug.Log ("TARGET WAS NOT RELEASED");
62 EndInteraction ();
63 }
64
65 // Maps angle to the range (-180, 180]
66 protected float MinAngleToZero (float angle)
67 {
68 float minAngle = angle % 360f;
69 if (minAngle > 180f)
70 minAngle = minAngle - 360f;
71 if (minAngle <= -180f)
72 minAngle = 360f + minAngle;
73 return minAngle;
74 }
75
76 // Restrictions to min & max evenly divide the out-of-range angles
77 protected float RestrictAngle (float setAngle)
78 {
79 float acceptDivider = (maximumAngle + minimumAngle) / 2f; // midpoint of acceptance region
80 float resAngle = MinAngleToZero (setAngle - acceptDivider);
81 if (resAngle > maximumAngle - acceptDivider)
82 resAngle = maximumAngle - acceptDivider;
83 if (resAngle < minimumAngle - acceptDivider)
84 resAngle = minimumAngle - acceptDivider;
85 resAngle += acceptDivider;
86 return resAngle;
87 }
88
89 protected int RestrictStep (float setAngle)
90 {
91 float setFraction = (RestrictAngle (setAngle) - minimumAngle) / (maximumAngle - minimumAngle);
92 int resStep = (int)((steps * setFraction) + 0.5f);
93 if (resStep == steps)
94 // When setAngle == maximumAngle int rounding will not yield a reduction
95 resStep = steps - 1;
96 return resStep;
97 }
98
99 // CurrentAngle ranges from minimumAngle to maximumAngle
100 public float CurrentAngle {
101 get {
102 return RestrictAngle (transform.localRotation.eulerAngles.y);
103 }
104 set {
105 // Debug.Log ("DialModeBase.CurrentAngle is being set to: " + value);
106 Vector3 eulerAngles = transform.localRotation.eulerAngles;
107 eulerAngles.x = 0f;
108 eulerAngles.y = RestrictAngle (value);
109 eulerAngles.z = 0f;
110 transform.localRotation = Quaternion.Euler (eulerAngles);
111 }
112 }
113
114 // CurrentStep ranges from 0 to steps-1
115 public int CurrentStep {
116 get {
117 return RestrictStep (transform.localRotation.eulerAngles.y);
118 }
119 set {
120 // Debug.Log ("DialModeBase.CurrentStep is being set to: " + value);
121 if (steps <= 0)
122 return;
123 CurrentAngle = (value * (maximumAngle - minimumAngle) / steps) + minimumAngle;
124 }
125 }
126
127 private bool IsHand (Collider other)
128 {
129 return other.transform.parent && other.transform.parent.parent && other.transform.parent.parent.GetComponent<HandModel> ();
130 }
131
132 void OnTriggerEnter (Collider other)
133 {
134 if (target_ == null && IsHand (other)) {
135 target_ = other.gameObject;
136 pivot_ = transform.InverseTransformPoint (target_.transform.position) - transform.localPosition;
137 if (GetComponent<Rigidbody>().isKinematic == false)
138 transform.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
139 interacting_ = true;
140 if (dialGraphics)
141 dialGraphics.HilightDial ();
142 }
143 }
144
145 void OnTriggerExit (Collider other)
146 {
147 if (other.gameObject == target_) {
148 EndInteraction ();
149 }
150 }
151
152 void EndInteraction ()
153 {
154 target_ = null;
155 if (steps > 0) {
156 SnapToStep ();
157 } else {
158 float FPS_INVERSE = 1f / Time.deltaTime;
159 float angular_velocity = (curr_angle_ - prev_angle_) * FPS_INVERSE;
160 transform.GetComponent<Rigidbody>().AddRelativeTorque (new Vector3 (0f, 0f, angular_velocity));
161 }
162 interacting_ = false;
163 // NOTE: External update should following internal state update,
164 // so that exceptions in external update do not yield inconsistent state
165 if (dialGraphics)
166 dialGraphics.UpdateDial ();
167 }
168
169 protected virtual void ApplyRotations ()
170 {
171 Vector3 curr_direction = transform.InverseTransformPoint (target_.transform.position) - transform.localPosition;
172 transform.localRotation = Quaternion.FromToRotation (pivot_, curr_direction) * transform.localRotation;
173 }
174
175 protected virtual void ApplyConstraints ()
176 {
177 Vector3 rotation = transform.localRotation.eulerAngles;
178 rotation.x = 0f;
179 // Allow dial manipulation to exceed range - it will snap back when released
180 prev_angle_ = curr_angle_;
181 curr_angle_ = rotation.y;
182 rotation.z = 0f;
183 transform.localRotation = Quaternion.Euler (rotation);
184 }
185
186 protected virtual void SnapToStep ()
187 {
188 CurrentStep = CurrentStep;
189 ApplyConstraints ();
190 }
191
192 void FixedUpdate ()
193 {
194 if (target_ == null && interacting_) {
195 // Hand destroyed while interacting
196 //Debug.Log ("HAND DESTROYED WHILE INTERACTING");
197 EndInteraction ();
198 }
199 if (target_ != null) {
200 ApplyRotations ();
201 }
202 ApplyConstraints ();
203 }
204 }
205 }
206