Mercurial > hg > Game > Games
comparison Orchestland/Assets/LeapMotion/Widgets/Scripts/Dial/DialModeBase.cs @ 3:0030a1b971fb default tip
merge
author | Yuta ANSE <e135745@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2015 23:23:43 +0900 |
parents | f7675884f2a1 |
children |
comparison
equal
deleted
inserted
replaced
2:fdab88fc2cb9 | 3:0030a1b971fb |
---|---|
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 |