Tanoda
AttachmentHands.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
10using System;
11using System.Collections;
12using System.Collections.Generic;
13#if UNITY_EDITOR
14using UnityEditor;
15#endif
16using UnityEngine;
17
18namespace Leap.Unity.Attachments {
19
28 [ExecuteInEditMode]
29 public class AttachmentHands : MonoBehaviour {
30
31 [SerializeField]
32 private AttachmentPointFlags _attachmentPoints = AttachmentPointFlags.Palm | AttachmentPointFlags.Wrist;
34 get {
35 return _attachmentPoints;
36 }
37 set {
38 if (_attachmentPoints != value) {
39 #if UNITY_EDITOR
40 Undo.IncrementCurrentGroup();
41 Undo.SetCurrentGroupName("Modify Attachment Points");
42
43 Undo.RecordObject(this, "Modify AttachmentHands Points");
44 #endif
45
46 _attachmentPoints = value;
47 refreshAttachmentHandTransforms();
48 }
49 }
50 }
51
52 private Func<Hand>[] _handAccessors;
62 public Func<Hand>[] handAccessors { get { return _handAccessors; } set { _handAccessors = value; } }
63
64 private AttachmentHand[] _attachmentHands;
73 public AttachmentHand[] attachmentHands { get { return _attachmentHands; } set { _attachmentHands = value; } }
74
75#if UNITY_EDITOR
76 void OnValidate() {
77 if (getIsPrefab()) return;
78
79 reinitialize();
80 }
81#endif
82
83 void Awake() {
84#if UNITY_EDITOR
85 if (getIsPrefab()) return;
86#endif
87
88 reinitialize();
89 }
90
91 private void reinitialize() {
92 refreshHandAccessors();
93 refreshAttachmentHands();
94
95 #if UNITY_EDITOR
96 EditorApplication.delayCall += refreshAttachmentHandTransforms;
97 #else
98 refreshAttachmentHandTransforms();
99 #endif
100 }
101
102 void Update() {
103 #if UNITY_EDITOR
104 if (Utils.IsObjectPartOfPrefabAsset(this.gameObject)) {
105 return;
106 }
107 #endif
108
109 bool requiresReinitialization = false;
110
111 using (new ProfilerSample("Attachment Hands Update", this.gameObject)) {
112 for (int i = 0; i < _attachmentHands.Length; i++) {
113 var attachmentHand = attachmentHands[i];
114
115 if (attachmentHand == null) {
116 requiresReinitialization = true;
117 break;
118 }
119
120 var leapHand = handAccessors[i]();
121 attachmentHand.isTracked = leapHand != null;
122
123 using (new ProfilerSample(attachmentHand.gameObject.name + " Update Points")) {
124 foreach (var point in attachmentHand.points) {
125 point.SetTransformUsingHand(leapHand);
126 }
127 }
128 }
129
130 if (requiresReinitialization) {
131 reinitialize();
132 }
133 }
134 }
135
136 private void refreshHandAccessors() {
137 // If necessary, generate a left-hand and right-hand set of accessors.
138 if (_handAccessors == null || _handAccessors.Length == 0) {
139 _handAccessors = new Func<Hand>[2];
140
141 _handAccessors[0] = new Func<Hand>(() => { return Hands.Left; });
142 _handAccessors[1] = new Func<Hand>(() => { return Hands.Right; });
143 }
144 }
145
146 private void refreshAttachmentHands() {
147 // If we're a prefab, we'll be unable to set parent transforms, so we shouldn't create new objects in general.
148 bool isPrefab = false;
149 #if UNITY_EDITOR
150 isPrefab = getIsPrefab();
151 #endif
152
153 // If necessary, generate a left and right AttachmentHand.
154 if (_attachmentHands == null || _attachmentHands.Length == 0 || (_attachmentHands[0] == null || _attachmentHands[1] == null)) {
155 _attachmentHands = new AttachmentHand[2];
156
157 // Try to use existing AttachmentHand objects first.
158 foreach (Transform child in this.transform.GetChildren()) {
159 var attachmentHand = child.GetComponent<AttachmentHand>();
160 if (attachmentHand != null) {
161 _attachmentHands[attachmentHand.chirality == Chirality.Left ? 0 : 1] = attachmentHand;
162 }
163 }
164
165 // If we are a prefab and there are missing AttachmentHands, we have to return early.
166 // We can't set parent transforms while a prefab. We're only OK if we already have attachmentHand
167 // objects and their parents are properly set.
168 if (isPrefab && (_attachmentHands[0] == null || _attachmentHands[0].transform.parent != this.transform
169 || _attachmentHands[1] == null || _attachmentHands[1].transform.parent != this.transform)) {
170 return;
171 }
172
173 // Construct any missing AttachmentHand objects.
174 if (_attachmentHands[0] == null) {
175 GameObject obj = new GameObject();
176 #if UNITY_EDITOR
177 Undo.RegisterCreatedObjectUndo(obj, "Created GameObject");
178 #endif
179 _attachmentHands[0] = obj.AddComponent<AttachmentHand>();
180 _attachmentHands[0].chirality = Chirality.Left;
181 }
182 _attachmentHands[0].gameObject.name = "Attachment Hand (Left)";
183 if (_attachmentHands[0].transform.parent != this.transform) _attachmentHands[0].transform.parent = this.transform;
184
185 if (_attachmentHands[1] == null) {
186 GameObject obj = new GameObject();
187 #if UNITY_EDITOR
188 Undo.RegisterCreatedObjectUndo(obj, "Created GameObject");
189 #endif
190 _attachmentHands[1] = obj.AddComponent<AttachmentHand>();
191 _attachmentHands[1].chirality = Chirality.Right;
192 }
193 _attachmentHands[1].gameObject.name = "Attachment Hand (Right)";
194 if (_attachmentHands[1].transform.parent != this.transform) _attachmentHands[1].transform.parent = this.transform;
195
196 // Organize left hand first in sibling order.
197 _attachmentHands[0].transform.SetSiblingIndex(0);
198 _attachmentHands[1].transform.SetSiblingIndex(1);
199 }
200 }
201
202 private void refreshAttachmentHandTransforms() {
203 if (this == null) return;
204
205 #if UNITY_EDITOR
206 if (getIsPrefab()) return;
207 #endif
208
209 bool requiresReinitialization = false;
210
211 if (_attachmentHands == null) {
212 requiresReinitialization = true;
213 }
214 else {
215 foreach (var hand in _attachmentHands) {
216 if (hand == null) {
217 // AttachmentHand must have been destroyed
218 requiresReinitialization = true;
219 break;
220 }
221
222 hand.refreshAttachmentTransforms(_attachmentPoints);
223 }
224
225 #if UNITY_EDITOR
226 EditorUtility.SetDirty(this);
227 #endif
228 }
229
230 if (requiresReinitialization) {
231 reinitialize();
232 }
233 }
234
235#if UNITY_EDITOR
236 private bool getIsPrefab() {
237 return Utils.IsObjectPartOfPrefabAsset(this.gameObject);
238 }
239#endif
240
241 }
242
243
244}
This MonoBehaviour is managed by an AttachmentHands component on a parent MonoBehaviour....
void refreshAttachmentTransforms(AttachmentPointFlags points)
Chirality chirality
Gets the chirality of this AttachmentHand. This is set automatically by the AttachmentHands parent ob...
Add an GameObject with this script to your scene if you would like to have a Transform hierarchy that...
AttachmentHand[] attachmentHands
Gets or sets the array of AttachmentHand objects that this component manages. The length of this arra...
Func< Hand >[] handAccessors
Gets or sets the functions used to get the latest Leap.Hand data for the corresponding AttachmentHand...
AttachmentPointFlags
Flags for attachment points on the hand.