Skip to content

Commit 6ba68b4

Browse files
committed
Refactor Grabbable/Draggable
* Now BasicGrabbable/StickyGrabbable/Draggable derive from GrabbableBase * Now Grabbable/Draggable apply PoseModifier when tracking grabber * Now pointer scroll can extend drag distance when dragging a Draggable item
1 parent f1e6ed1 commit 6ba68b4

File tree

8 files changed

+623
-433
lines changed

8 files changed

+623
-433
lines changed

Assets/HTC.UnityPlugin/Utility/Container/IndexedTable.cs

+15-4
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ public void RemoveAll(Predicate<KeyValuePair<TKey, TValue>> match)
261261
}
262262
else
263263
{
264-
if (removed != 0)
264+
if (removed > 0)
265265
{
266266
m_Dictionary[m_KeyList[i]] = i - removed;
267267
m_KeyList[i - removed] = m_KeyList[i];
@@ -270,10 +270,21 @@ public void RemoveAll(Predicate<KeyValuePair<TKey, TValue>> match)
270270
}
271271
}
272272

273-
for (; removed > 0; --removed)
273+
if (removed == 0)
274274
{
275-
m_KeyList.RemoveAt(m_KeyList.Count - 1);
276-
m_ValueList.RemoveAt(m_ValueList.Count - 1);
275+
return;
276+
}
277+
else if (removed == Count)
278+
{
279+
Clear();
280+
}
281+
else
282+
{
283+
for (; removed > 0; --removed)
284+
{
285+
m_KeyList.RemoveAt(m_KeyList.Count - 1);
286+
m_ValueList.RemoveAt(m_ValueList.Count - 1);
287+
}
277288
}
278289
}
279290

Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using HTC.UnityPlugin.Utility;
2+
using HTC.UnityPlugin.Vive;
23
using System;
34
using UnityEngine;
45
using UnityEngine.Events;
56
using UnityEngine.EventSystems;
7+
using UnityEngine.Serialization;
68

79
// demonstrate of dragging things useing built in EventSystem handlers
8-
public class Draggable : MonoBehaviour
10+
public class Draggable : GrabbableBase<Draggable.Grabber>
911
, IInitializePotentialDragHandler
1012
, IBeginDragHandler
1113
, IDragHandler
@@ -14,55 +16,131 @@ public class Draggable : MonoBehaviour
1416
[Serializable]
1517
public class UnityEventDraggable : UnityEvent<Draggable> { }
1618

17-
public const float MIN_FOLLOWING_DURATION = 0.02f;
18-
public const float DEFAULT_FOLLOWING_DURATION = 0.04f;
19-
public const float MAX_FOLLOWING_DURATION = 0.5f;
19+
public class Grabber : IGrabber
20+
{
21+
private static ObjectPool<Grabber> m_pool;
22+
23+
public static Grabber Get(PointerEventData eventData)
24+
{
25+
if (m_pool == null)
26+
{
27+
m_pool = new ObjectPool<Grabber>(() => new Grabber());
28+
}
29+
30+
var grabber = m_pool.Get();
31+
grabber.eventData = eventData;
32+
return grabber;
33+
}
34+
35+
public static void Release(Grabber grabber)
36+
{
37+
grabber.eventData = null;
38+
m_pool.Release(grabber);
39+
}
40+
41+
public PointerEventData eventData { get; private set; }
42+
43+
public RigidPose grabberOrigin
44+
{
45+
get
46+
{
47+
var cam = eventData.pointerPressRaycast.module.eventCamera;
48+
var ray = cam.ScreenPointToRay(eventData.position);
49+
return new RigidPose(ray.origin, Quaternion.LookRotation(ray.direction, cam.transform.up));
50+
}
51+
}
52+
53+
public RigidPose grabOffset { get { return grabber2hit * hit2pivot; } set { } }
2054

21-
private OrderedIndexedTable<PointerEventData, RigidPose> eventList = new OrderedIndexedTable<PointerEventData, RigidPose>();
55+
public RigidPose grabber2hit { get; set; }
2256

23-
public float initGrabDistance = 0.5f;
57+
public RigidPose hit2pivot { get; set; }
58+
59+
public float hitDistance
60+
{
61+
get { return grabber2hit.pos.z; }
62+
set
63+
{
64+
var p = grabber2hit;
65+
p.pos.z = value;
66+
grabber2hit = p;
67+
}
68+
}
69+
}
70+
71+
private IndexedTable<PointerEventData, Grabber> m_eventGrabberSet;
72+
73+
[FormerlySerializedAs("initGrabDistance")]
74+
[SerializeField]
75+
private float m_initGrabDistance = 0.5f;
2476
[Range(MIN_FOLLOWING_DURATION, MAX_FOLLOWING_DURATION)]
25-
public float followingDuration = DEFAULT_FOLLOWING_DURATION;
26-
public bool overrideMaxAngularVelocity = true;
27-
public bool unblockableGrab = true;
77+
[FormerlySerializedAs("followingDuration")]
78+
[SerializeField]
79+
private float m_followingDuration = DEFAULT_FOLLOWING_DURATION;
80+
[FormerlySerializedAs("overrideMaxAngularVelocity")]
81+
[SerializeField]
82+
private bool m_overrideMaxAngularVelocity = true;
83+
[FormerlySerializedAs("unblockableGrab")]
84+
[SerializeField]
85+
private bool m_unblockableGrab = true;
86+
[FormerlySerializedAs("afterGrabbed")]
87+
[SerializeField]
88+
private UnityEventDraggable m_afterGrabbed = new UnityEventDraggable();
89+
[FormerlySerializedAs("beforeRelease")]
90+
[SerializeField]
91+
private UnityEventDraggable m_beforeRelease = new UnityEventDraggable();
92+
[FormerlySerializedAs("onDrop")]
93+
[SerializeField]
94+
private UnityEventDraggable m_onDrop = new UnityEventDraggable(); // change rigidbody drop velocity here
2895

29-
public UnityEventDraggable afterDragged = new UnityEventDraggable();
30-
public UnityEventDraggable beforeRelease = new UnityEventDraggable();
31-
public UnityEventDraggable onDrop = new UnityEventDraggable(); // change rigidbody drop velocity here
96+
public bool isDragged { get { return isGrabbed; } }
3297

33-
private RigidPose m_prevPose = RigidPose.identity; // last frame world pose
98+
public PointerEventData draggedEvent { get { return isGrabbed ? currentGrabber.eventData : null; } }
3499

35-
public bool isDragged { get { return eventList.Count > 0; } }
100+
public float initGrabDistance { get { return m_initGrabDistance; } set { m_initGrabDistance = value; } }
36101

37-
public PointerEventData draggedEvent { get { return isDragged ? eventList.GetLastKey() : null; } }
102+
public override float followingDuration { get { return m_followingDuration; } set { m_followingDuration = Mathf.Clamp(value, MIN_FOLLOWING_DURATION, MAX_FOLLOWING_DURATION); } }
38103

39-
// effected rigidbody
40-
public Rigidbody rigid { get; set; }
104+
public override bool overrideMaxAngularVelocity { get { return m_overrideMaxAngularVelocity; } set { m_overrideMaxAngularVelocity = value; } }
41105

42-
private bool moveByVelocity { get { return !unblockableGrab && rigid != null && !rigid.isKinematic; } }
106+
public bool unblockableGrab { get { return m_unblockableGrab; } set { m_unblockableGrab = value; } }
43107

44-
private RigidPose GetEventPose(PointerEventData eventData)
108+
public UnityEventDraggable afterGrabbed { get { return m_afterGrabbed; } }
109+
110+
public UnityEventDraggable beforeRelease { get { return m_beforeRelease; } }
111+
112+
public UnityEventDraggable onDrop { get { return m_onDrop; } }
113+
114+
private bool moveByVelocity { get { return !unblockableGrab && grabRigidbody != null && !grabRigidbody.isKinematic; } }
115+
116+
[Obsolete("Use grabRigidbody instead")]
117+
public Rigidbody rigid { get { return grabRigidbody; } set { grabRigidbody = value; } }
118+
119+
protected override void Awake()
45120
{
46-
var cam = eventData.pointerPressRaycast.module.eventCamera;
47-
var ray = cam.ScreenPointToRay(eventData.position);
48-
return new RigidPose(ray.origin, Quaternion.LookRotation(ray.direction, cam.transform.up));
121+
base.Awake();
122+
123+
afterGrabberGrabbed += () => m_afterGrabbed.Invoke(this);
124+
beforeGrabberReleased += () => m_beforeRelease.Invoke(this);
125+
onGrabberDrop += () => m_onDrop.Invoke(this);
49126
}
50127

51-
protected virtual void Awake()
128+
protected virtual void OnDisable()
52129
{
53-
rigid = GetComponent<Rigidbody>();
130+
ClearGrabbers(true);
131+
ClearEventGrabberSet();
54132
}
55133

56-
protected virtual void OnDisable()
134+
private void ClearEventGrabberSet()
57135
{
58-
if (isDragged && beforeRelease != null)
136+
if (m_eventGrabberSet == null) { return; }
137+
138+
for (int i = m_eventGrabberSet.Count - 1; i >= 0; --i)
59139
{
60-
beforeRelease.Invoke(this);
140+
Grabber.Release(m_eventGrabberSet.GetValueByIndex(i));
61141
}
62142

63-
eventList.Clear();
64-
65-
DoDrop();
143+
m_eventGrabberSet.Clear();
66144
}
67145

68146
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
@@ -72,119 +150,67 @@ public virtual void OnInitializePotentialDrag(PointerEventData eventData)
72150

73151
public virtual void OnBeginDrag(PointerEventData eventData)
74152
{
75-
var casterPose = GetEventPose(eventData);
76-
var offsetPose = new RigidPose();
153+
var hitDistance = 0f;
154+
77155
switch (eventData.button)
78156
{
79157
case PointerEventData.InputButton.Middle:
80158
case PointerEventData.InputButton.Right:
81-
{
82-
var hitResult = eventData.pointerPressRaycast;
83-
var hitPose = new RigidPose(hitResult.worldPosition, casterPose.rot);
84-
85-
var caster2hit = new RigidPose(Vector3.forward * Mathf.Min(hitResult.distance, initGrabDistance), Quaternion.identity);
86-
var hit2center = RigidPose.FromToPose(hitPose, new RigidPose(transform));
87-
88-
offsetPose = caster2hit * hit2center;
89-
break;
90-
}
159+
hitDistance = Mathf.Min(eventData.pointerPressRaycast.distance, m_initGrabDistance);
160+
break;
91161
case PointerEventData.InputButton.Left:
162+
hitDistance = eventData.pointerPressRaycast.distance;
163+
break;
92164
default:
93-
{
94-
offsetPose = RigidPose.FromToPose(casterPose, new RigidPose(transform));
95-
break;
96-
}
165+
return;
97166
}
98167

99-
if (eventData != draggedEvent && beforeRelease != null)
100-
{
101-
beforeRelease.Invoke(this);
102-
}
168+
var grabber = Grabber.Get(eventData);
169+
grabber.grabber2hit = new RigidPose(new Vector3(0f, 0f, hitDistance), Quaternion.identity);
170+
grabber.hit2pivot = RigidPose.FromToPose(grabber.grabberOrigin * grabber.grabber2hit, new RigidPose(transform));
103171

104-
eventList.AddUniqueKey(eventData, offsetPose);
172+
if (m_eventGrabberSet == null) { m_eventGrabberSet = new IndexedTable<PointerEventData, Grabber>(); }
173+
m_eventGrabberSet.Add(eventData, grabber);
105174

106-
if (afterDragged != null)
107-
{
108-
afterDragged.Invoke(this);
109-
}
175+
AddGrabber(grabber);
110176
}
111177

112178
protected virtual void FixedUpdate()
113179
{
114-
if (!isDragged) { return; }
115-
116-
if (moveByVelocity)
180+
if (isGrabbed && moveByVelocity)
117181
{
118-
// if rigidbody exists, follow eventData caster using physics
119-
var casterPose = GetEventPose(draggedEvent);
120-
var offsetPose = eventList.GetLastValue();
121-
122-
var targetPose = casterPose * offsetPose;
123-
RigidPose.SetRigidbodyVelocity(rigid, rigid.position, targetPose.pos, followingDuration);
124-
RigidPose.SetRigidbodyAngularVelocity(rigid, rigid.rotation, targetPose.rot, followingDuration, overrideMaxAngularVelocity);
182+
OnGrabRigidbody();
125183
}
126184
}
127185

128-
public virtual void OnDrag(PointerEventData eventData)
186+
protected virtual void Update()
129187
{
130-
if (eventData != draggedEvent) { return; }
188+
if (!isGrabbed) { return; }
131189

132190
if (!moveByVelocity)
133191
{
134-
// if rigidbody doen't exist, just move transform to eventData caster's pose
135-
var casterPose = GetEventPose(eventData);
136-
var offsetPose = eventList.GetLastValue();
137-
138-
m_prevPose = new RigidPose(transform);
139-
140-
if (rigid != null)
141-
{
142-
rigid.velocity = Vector3.zero;
143-
rigid.angularVelocity = Vector3.zero;
144-
}
145-
146-
var targetPose = casterPose * offsetPose;
147-
transform.position = targetPose.pos;
148-
transform.rotation = targetPose.rot;
192+
RecordLatestPosesForDrop(Time.time, 0.05f);
193+
OnGrabTransform();
149194
}
150-
}
151195

152-
public virtual void OnEndDrag(PointerEventData eventData)
153-
{
154-
var released = eventData == draggedEvent;
155-
if (released && beforeRelease != null)
156-
{
157-
beforeRelease.Invoke(this);
158-
}
159-
160-
eventList.Remove(eventData);
161-
162-
if (isDragged)
163-
{
164-
if (released && afterDragged != null)
165-
{
166-
afterDragged.Invoke(this);
167-
}
168-
}
169-
else
196+
var scrollDelta = currentGrabber.eventData.scrollDelta * 0.01f;
197+
if (scrollDelta != Vector2.zero)
170198
{
171-
DoDrop();
199+
currentGrabber.hitDistance = Mathf.Max(0f, currentGrabber.hitDistance + scrollDelta.y);
172200
}
173201
}
174202

175-
private void DoDrop()
203+
public virtual void OnDrag(PointerEventData eventData) { }
204+
205+
public virtual void OnEndDrag(PointerEventData eventData)
176206
{
177-
if (!moveByVelocity && rigid != null && !rigid.isKinematic && m_prevPose != RigidPose.identity)
178-
{
179-
RigidPose.SetRigidbodyVelocity(rigid, m_prevPose.pos, transform.position, Time.deltaTime);
180-
RigidPose.SetRigidbodyAngularVelocity(rigid, m_prevPose.rot, transform.rotation, Time.deltaTime, overrideMaxAngularVelocity);
207+
if (m_eventGrabberSet == null) { return; }
181208

182-
m_prevPose = RigidPose.identity;
183-
}
209+
Grabber grabber;
210+
if (!m_eventGrabberSet.TryGetValue(eventData, out grabber)) { return; }
184211

185-
if (onDrop != null)
186-
{
187-
onDrop.Invoke(this);
188-
}
212+
RemoveGrabber(grabber);
213+
m_eventGrabberSet.Remove(eventData);
214+
Grabber.Release(grabber);
189215
}
190216
}

0 commit comments

Comments
 (0)