1 using System.Collections;
2 using System.Collections.Generic;
22 public List<AVR_GrabNode> grabNodes => nodes;
23 private readonly List<AVR_GrabNode> nodes =
new List<AVR_GrabNode>();
38 public List<Collider> colliders =
new List<Collider>();
44 public List<AVR_BasicGrabProvider> AttachedHands =
new List<AVR_BasicGrabProvider>();
48 private List<Vector3> velocities =
new List<Vector3>();
49 const int velocity_count = 3;
51 private float last_dist = 0.0f;
56 public bool isGrabbed {
57 get {
return AttachedHands.Count>0; }
63 public bool isGrabbedByMultipleHands {
64 get {
return AttachedHands.Count>1; }
69 this.destroyOnRemote =
false;
76 if (rb == null) rb = GetComponent<Rigidbody>();
77 if (colliders==null || colliders.Count<1) colliders.AddRange(GetComponentsInChildren<Collider>());
78 if (nodes == null || nodes.Count < 1) nodes.AddRange(GetComponentsInChildren<AVR_GrabNode>());
79 if (objectType == null) objectType = GrabbableObjectType.defaultObjectType();
80 if (source == null) source = GetComponent<AudioSource>();
85 if (source.spatialBlend == 0.0f)
88 "'s Audio Source has no spatial blend. 3D audio will not work. Consider setting spatial blend to 1");
100 force = Vector3.zero;
108 if(IsOnline && !IsOwnedByServer && !IsOwner)
115 old_parent = this.transform.parent;
117 transform.SetParent(AVR.Core.AVR_PlayerRig.Instance.transform);
119 else if(isGrabbed && !_objType.allowTwoHanded) {
121 while(AttachedHands.Count>0) AttachedHands[0].makeRelease();
123 AttachedHands.Add(hand);
124 hand.controller.HapticPulse(0.3f, 0.05f);
127 if (source != null && objectType.soundData.pickupSound != null)
129 source.PlayOneShot(objectType.soundData.pickupSound, objectType.soundData.volumeMultiplier);
135 NetworkObject.ChangeOwnership(this.OwnerClientId);
143 if (IsOnline) NetworkObject.RemoveOwnership();
146 if(AttachedHands.Contains(hand)) AttachedHands.Remove(hand);
147 if(AttachedHands.Count<1) {
148 transform.SetParent(old_parent);
149 if(velocities.Count>0) rb.velocity =
new Vector3(velocities.Average(v => v.x), velocities.Average(v => v.y), velocities.Average(v => v.z));
153 if (source != null && objectType.soundData.releaseSound != null)
155 source.PlayOneShot(objectType.soundData.releaseSound, objectType.soundData.volumeMultiplier);
160 Vector3 lastVel = Vector3.zero;
161 Vector3 wacc = Vector3.zero;
162 Vector3 worldvel = Vector3.zero;
164 Vector3 force = Vector3.zero;
165 Vector3 cvel = Vector3.zero;
170 if(IsOnline && !IsOwner)
return;
174 Vector3 targetItemPosition = transform.position;
175 Quaternion targetItemRotation = transform.rotation;
176 Vector3 targetHandPosition = this.getTargetPosition();
177 Quaternion targetHandRotation = this.getTargetRotation();
180 _objType = (isGrabbedByMultipleHands && objectType.changeObjectTypeOnTwoHanded) ? objectType.typeOnTwoHanded : objectType;
183 if (Vector3.Distance(targetItemPosition, targetHandPosition) > last_dist && last_dist > _objType.Break_grab_distance)
185 while (AttachedHands.Count > 0) AttachedHands[0].makeRelease();
188 last_dist = Vector3.Distance(targetItemPosition, targetHandPosition);
191 switch(_objType.followType) {
192 case GrabbableObjectType.FollowType.FREE : {
194 Vector3 pDelta = (targetHandPosition - targetItemPosition);
195 Vector3 vel = pDelta / Time.fixedDeltaTime;
197 rb.velocity = vel * _objType.Lightness;
198 lastVel = rb.velocity;
201 Quaternion rotationDelta = targetHandRotation * Quaternion.Inverse(targetItemRotation);
203 rotationDelta.ToAngleAxis(out
float angle, out Vector3 axis);
204 while (angle > 180) angle -= 360;
206 rb.maxAngularVelocity = 99999.0f;
208 Vector3 angvel = (angle * axis * Mathf.Deg2Rad) / Time.fixedDeltaTime;
209 if (!
float.IsNaN(angvel.z)) rb.angularVelocity = angvel * _objType.Angular_Lightness;
212 case GrabbableObjectType.FollowType.STATIC : {
215 case GrabbableObjectType.FollowType.CONSTRAINED : {
216 Vector3 pDelta = (targetHandPosition - targetItemPosition);
217 Vector3 vel = pDelta / Time.fixedDeltaTime;
222 wacc = Vector3.Lerp(wacc, rb.velocity - lastVel, 0.5f);
224 worldvel = wacc / Time.fixedDeltaTime;
226 worldvel -= worldvel.normalized * Mathf.Min(worldvel.magnitude, 10);
227 vel = Vector3.ClampMagnitude(vel, 30);
229 if (!
float.IsNaN(worldvel.x) && !float.IsNaN(worldvel.y) && !
float.IsNaN(worldvel.z))
231 rb.velocity = vel + worldvel;
235 rb.velocity = Vector3.zero;
238 lastVel = rb.velocity;
242 Quaternion rotationDelta = targetHandRotation * Quaternion.Inverse(targetItemRotation);
244 rotationDelta.ToAngleAxis(out
float angle, out Vector3 axis);
245 while (angle > 180) angle -= 360;
247 rb.maxAngularVelocity = 99999.0f;
249 Vector3 angvel = (angle * axis * Mathf.Deg2Rad) / Time.fixedDeltaTime;
250 if (!
float.IsNaN(angvel.z)) rb.angularVelocity = (angvel * objectType.Angular_Lightness);
253 case GrabbableObjectType.FollowType.HEAVY : {
255 Vector3 closestp = AttachedHands[0].getWorldGrabLocation();
258 force = Vector3.Lerp(force, AttachedHands[0].grabPoint.position - closestp, 0.25f);
261 cvel = Vector3.Lerp(cvel, rb.GetPointVelocity(closestp), 0.25f);
265 Vector3 delta = force - Vector3.Lerp(Vector3.zero, cvel, k * Vector3.Distance(AttachedHands[0].grabPoint.position, closestp));
266 Vector3 f = delta * Time.fixedDeltaTime * 100.0f * _objType.Heavy_force_multiplier;
269 rb.AddForceAtPosition(f, closestp, ForceMode.Impulse);
273 velocities.Add(rb.velocity);
274 while (velocities.Count > velocity_count) velocities.RemoveAt(0);
279 return transform.position;
281 else if(AttachedHands.Count == 1) {
282 return AttachedHands[0].getTargetPosition();
285 Vector3 sum = Vector3.zero;
287 return sum/AttachedHands.Count;
293 return transform.rotation;
295 else if (AttachedHands.Count == 1) {
296 return AttachedHands[0].getTargetRotation();
301 float w = 1f / AttachedHands.Count;
302 Quaternion avg = Quaternion.identity;
303 for (
int i = 0; i < AttachedHands.Count; i++)
305 Quaternion q = AttachedHands[i].getTargetRotation();
306 avg *= Quaternion.Slerp(Quaternion.identity, q, w);
317 h.controller.HapticPulse(Mathf.Lerp(0, 0.5f, 0.2f * collision.relativeVelocity.magnitude), 0.05f);
321 if (source != null && objectType.soundData.collideSound != null && rb != null)
324 float soundMultiplier = objectType.soundData.volumeMultiplier;
326 float mass = rb.mass;
327 float speed = rb.velocity.magnitude;
328 float drag = rb.drag == 0.0f ? 0.5f : rb.drag;
330 const float frontalArea = 0.5f;
331 const float airDrag = 1.1f;
334 float terminalSpeed = Mathf.Sqrt(2.0f * mass * Physics.gravity.magnitude / airDrag * frontalArea * drag);
338 if (speed > terminalSpeed)
345 float physicsSoundMultiplier = speed / terminalSpeed;
347 soundMultiplier *= physicsSoundMultiplier;
349 source.PlayOneShot(objectType.soundData.collideSound, soundMultiplier);
AudioSource source
Optional AudioSource to play sounds from GrabbableObjectType data
Defines how an object behaves whilst grabbed.
Represents a grabbable object.
Quaternion getTargetRotation()
Rigidbody rb
Rigidbody of this grabbable object.
Sets the documentation html file inside of Packages/com.avr.core/Documentation/html of a given class...
Simplest GrabProvider. Grabbed objects will move their center (obj.transform.position) towards the re...
void OnCollisionEnter(Collision collision)
Vector3 getTargetPosition()
void Release(AVR_BasicGrabProvider hand)
void Grab(AVR_BasicGrabProvider hand)