Skip to content

Commit

Permalink
feat(Utilities): add track object option to rigidbody follow
Browse files Browse the repository at this point in the history
The Rigidbody Follow script now has a `Track` option for the Movement
Option. The track option uses the same mechanic as the track object
grab mechanic to make a rigidbody track another rigidbody based on
the velocity differences and use MoveTowards to move the rigidbody
velocity towards the intended target.
  • Loading branch information
thestonefox committed Nov 7, 2017
1 parent 3d9c9d5 commit a911bfe
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 18 deletions.
32 changes: 30 additions & 2 deletions Assets/VRTK/Documentation/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -9375,18 +9375,33 @@ Follow `gameObjectToFollow` using the current settings.

### Overview

Changes one game object's rigidbody to follow another game object's rigidbody.
Changes one GameObject's rigidbody to follow another GameObject's rigidbody.

### Inspector Parameters

* **Movement Option:** Specifies how to position and rotate the rigidbody.
* **Track Max Distance:** The maximum distance the tracked `Game Object To Change` Rigidbody can be from the `Game Object To Follow` Rigidbody before the position is forcibly set to match the position.

### Class Variables

* `public enum MovementOption` - Specifies how to position and rotate the rigidbody.
* `Set` - Use Rigidbody.position and Rigidbody.rotation.
* `Move` - Use Rigidbody.MovePosition and Rigidbody.MoveRotation.
* `Add` - Use Rigidbody.AddForce(Vector3) and Rigidbody.AddTorque(Vector3).
* `Track` - Use velocity and angular velocity with MoveTowards.

### Class Methods

#### Follow/0

> `public override void Follow()`

* Parameters
* _none_
* Returns
* _none_

Follow `gameObjectToFollow` using the current settings.

---

Expand All @@ -9395,7 +9410,7 @@ Changes one game object's rigidbody to follow another game object's rigidbody.

### Overview

Changes one game object's transform to follow another game object's transform.
Changes one GameObject's transform to follow another GameObject's transform.

### Class Variables

Expand All @@ -9406,6 +9421,19 @@ Changes one game object's transform to follow another game object's transform.
* `OnPreRender` - Follow in the OnPreRender method. (This script doesn't have to be attached to a camera).
* `OnPreCull` - Follow in the OnPreCull method. (This script doesn't have to be attached to a camera).

### Class Methods

#### Follow/0

> `public override void Follow()`

* Parameters
* _none_
* Returns
* _none_

Follow `gameObjectToFollow` using the current settings.

---

## SDK Object Alias (VRTK_SDKObjectAlias)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ namespace VRTK
/// </summary>
public abstract class VRTK_ObjectFollow : MonoBehaviour
{
[Header("Object Settings")]

[Tooltip("The game object to follow. The followed property values will be taken from this one.")]
public GameObject gameObjectToFollow;
[Tooltip("The game object to change the property values of. If left empty the game object this script is attached to will be changed.")]
public GameObject gameObjectToChange;

[Header("Position Settings")]

[Tooltip("Whether to follow the position of the given game object.")]
public bool followsPosition = true;
[Tooltip("Whether to smooth the position when following `gameObjectToFollow`.")]
Expand All @@ -24,6 +28,8 @@ public abstract class VRTK_ObjectFollow : MonoBehaviour
/// </summary>
public Vector3 targetPosition { get; private set; }

[Header("Rotation Settings")]

[Tooltip("Whether to follow the rotation of the given game object.")]
public bool followsRotation = true;
[Tooltip("Whether to smooth the rotation when following `gameObjectToFollow`.")]
Expand All @@ -35,6 +41,8 @@ public abstract class VRTK_ObjectFollow : MonoBehaviour
/// </summary>
public Quaternion targetRotation { get; private set; }

[Header("Scale Settings")]

[Tooltip("Whether to follow the scale of the given game object.")]
public bool followsScale = true;
[Tooltip("Whether to smooth the scale when following `gameObjectToFollow`.")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace VRTK
using UnityEngine;

/// <summary>
/// Changes one game object's rigidbody to follow another game object's rigidbody.
/// Changes one GameObject's rigidbody to follow another GameObject's rigidbody.
/// </summary>
[AddComponentMenu("VRTK/Scripts/Utilities/Object Follow/VRTK_RigidbodyFollow")]
public class VRTK_RigidbodyFollow : VRTK_ObjectFollow
Expand All @@ -25,15 +25,30 @@ public enum MovementOption
/// <summary>
/// Use Rigidbody.AddForce(Vector3) and Rigidbody.AddTorque(Vector3).
/// </summary>
Add
Add,
/// <summary>
/// Use velocity and angular velocity with MoveTowards.
/// </summary>
Track
}

[Header("Follow Settings")]

[Tooltip("Specifies how to position and rotate the rigidbody.")]
public MovementOption movementOption = MovementOption.Set;

[Header("Track Movement Settings")]

[Tooltip("The maximum distance the tracked `Game Object To Change` Rigidbody can be from the `Game Object To Follow` Rigidbody before the position is forcibly set to match the position.")]
public float trackMaxDistance = 0.25f;

protected Rigidbody rigidbodyToFollow;
protected Rigidbody rigidbodyToChange;
protected float maxDistanceDelta = 10f;

/// <summary>
/// Follow `gameObjectToFollow` using the current settings.
/// </summary>
public override void Follow()
{
CacheRigidbodies();
Expand All @@ -51,9 +66,30 @@ protected virtual void FixedUpdate()
Follow();
}

protected virtual void CacheRigidbodies()
{
if (gameObjectToFollow == null || gameObjectToChange == null || (rigidbodyToFollow != null && rigidbodyToChange != null))
{
return;
}

rigidbodyToFollow = gameObjectToFollow.GetComponent<Rigidbody>();
rigidbodyToChange = gameObjectToChange.GetComponent<Rigidbody>();
}

protected override Vector3 GetPositionToFollow()
{
return rigidbodyToFollow.position;
return (rigidbodyToFollow != null ? rigidbodyToFollow.position : Vector3.zero);
}

protected override Quaternion GetRotationToFollow()
{
return (rigidbodyToFollow != null ? rigidbodyToFollow.rotation : Quaternion.identity);
}

protected override Vector3 GetScaleToFollow()
{
return rigidbodyToFollow.transform.localScale;
}

protected override void SetPositionOnGameObject(Vector3 newPosition)
Expand All @@ -70,14 +106,12 @@ protected override void SetPositionOnGameObject(Vector3 newPosition)
// TODO: Test if this is correct
rigidbodyToChange.AddForce(newPosition - rigidbodyToChange.position);
break;
case MovementOption.Track:
TrackPosition(newPosition);
break;
}
}

protected override Quaternion GetRotationToFollow()
{
return rigidbodyToFollow.rotation;
}

protected override void SetRotationOnGameObject(Quaternion newRotation)
{
switch (movementOption)
Expand All @@ -92,24 +126,61 @@ protected override void SetRotationOnGameObject(Quaternion newRotation)
// TODO: Test if this is correct
rigidbodyToChange.AddTorque(newRotation * Quaternion.Inverse(rigidbodyToChange.rotation).eulerAngles);
break;
case MovementOption.Track:
TrackRotation(newRotation);
break;
}
}

protected override Vector3 GetScaleToFollow()
protected virtual void TrackPosition(Vector3 newPosition)
{
return rigidbodyToFollow.transform.localScale;
if(rigidbodyToFollow == null)
{
return;
}

if(Vector3.Distance(rigidbodyToChange.position, rigidbodyToFollow.position) > trackMaxDistance)
{
rigidbodyToChange.position = rigidbodyToFollow.position;
rigidbodyToChange.rotation = rigidbodyToFollow.rotation;
}

float trackVelocityLimit = float.PositiveInfinity;
Vector3 positionDelta = newPosition - rigidbodyToChange.position;
Vector3 velocityTarget = positionDelta / Time.fixedDeltaTime;
Vector3 calculatedVelocity = Vector3.MoveTowards(rigidbodyToChange.velocity, velocityTarget, maxDistanceDelta);

if (trackVelocityLimit == float.PositiveInfinity || calculatedVelocity.sqrMagnitude < trackVelocityLimit)
{
rigidbodyToChange.velocity = calculatedVelocity;
}
}

protected virtual void CacheRigidbodies()
protected virtual void TrackRotation(Quaternion newRotation)
{
if (gameObjectToFollow == null || gameObjectToChange == null
|| (rigidbodyToFollow != null && rigidbodyToChange != null))
if (rigidbodyToFollow == null)
{
return;
}

rigidbodyToFollow = gameObjectToFollow.GetComponent<Rigidbody>();
rigidbodyToChange = gameObjectToChange.GetComponent<Rigidbody>();
float trackAngularVelocityLimit = float.PositiveInfinity;
Quaternion rotationDelta = newRotation * Quaternion.Inverse(rigidbodyToChange.rotation);

float angle;
Vector3 axis;
rotationDelta.ToAngleAxis(out angle, out axis);

angle = ((angle > 180) ? angle -= 360 : angle);

if (angle != 0)
{
Vector3 angularTarget = angle * axis;
Vector3 calculatedAngularVelocity = Vector3.MoveTowards(rigidbodyToChange.angularVelocity, angularTarget, maxDistanceDelta);
if (trackAngularVelocityLimit == float.PositiveInfinity || calculatedAngularVelocity.sqrMagnitude < trackAngularVelocityLimit)
{
rigidbodyToChange.angularVelocity = calculatedAngularVelocity;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace VRTK
using UnityEngine;

/// <summary>
/// Changes one game object's transform to follow another game object's transform.
/// Changes one GameObject's transform to follow another GameObject's transform.
/// </summary>
[AddComponentMenu("VRTK/Scripts/Utilities/Object Follow/VRTK_TransformFollow")]
public class VRTK_TransformFollow : VRTK_ObjectFollow
Expand Down Expand Up @@ -36,6 +36,8 @@ public enum FollowMoment
OnPreCull
}

[Header("Follow Settings")]

[Tooltip("The moment at which to follow.")]
[SerializeField]
private FollowMoment _moment = FollowMoment.OnPreRender;
Expand Down Expand Up @@ -80,6 +82,9 @@ public FollowMoment moment
protected Transform transformToFollow;
protected Transform transformToChange;

/// <summary>
/// Follow `gameObjectToFollow` using the current settings.
/// </summary>
public override void Follow()
{
CacheTransforms();
Expand Down

0 comments on commit a911bfe

Please sign in to comment.