Handy Tag VR
.png)
Handy Tag is a concept game inspired from Gorilla Tag, A VR Game. It utilizes the Hand movements as exercise and helps to improve motor skills of a person affected by Hemiplegia. This game has been designed under supervision of Research Fellow at New Zealand College of Chiropractic, Dr. Imran Amjad.
Physics implemented in this game contains the PID and Hooke's Law formulas for position and rotations.
Here's some code for Physics of Hand Movement for gorilla Tag Movement.
public class PhysicsHand : MonoBehaviour
{
HandyTagManager HandyTagManagerScript;
[SerializeField] AudioSource aud;
[Header("PID")]
[SerializeField] float frequency = 50f;
[SerializeField] float damping = 1f;
[SerializeField] float rotFrequency = 100f;
[SerializeField] float rotDamping = 0.9f;
[SerializeField] Transform target;
[SerializeField] Rigidbody playerRigidbody;
Rigidbody _rigidbody;
[Space]
[Header("Springs")]
[SerializeField] float climbForce = 1000f;
[SerializeField] float climbDrag = 500f;
Vector3 _previousPosition;
bool isCollion;
void Start()
{
GameObject scoreManager = GameObject.Find("HandyTagManager");
HandyTagManagerScript = scoreManager.GetComponent<HandyTagManager>();
transform.position = target.position;
transform.rotation = target.rotation;
_rigidbody = GetComponent<Rigidbody>();
_rigidbody.maxAngularVelocity = float.PositiveInfinity;
_previousPosition = transform.position;
}
void FixedUpdate()
{
PIDMovement();
PIDRotation();
if (isCollion) HookesLaw();
}
void PIDMovement()
{
float kp = (6f * frequency) * (6f * frequency) * 0.25f;
float kd = 4.5f * frequency * damping;
float g = 1 / (1 + kd * Time.fixedDeltaTime + kp * Time.fixedDeltaTime * Time.fixedDeltaTime);
float ksg = kp * g;
float kdg = (kd + kp * Time.fixedDeltaTime) * g;
Vector3 force = (target.position - transform.position) * ksg + (playerRigidbody.velocity - _rigidbody.velocity) * kdg;
_rigidbody.AddForce(force, ForceMode.Acceleration);
}
void PIDRotation()
{
float kp = (6f * rotFrequency) * (6f * rotFrequency) * 0.25f;
float kd = 4.5f * rotFrequency * rotDamping;
float g = 1 / (1 + kd * Time.fixedDeltaTime + kp * Time.fixedDeltaTime * Time.fixedDeltaTime);
float ksg = kp * g;
float kdg = (kd + kp * Time.fixedDeltaTime) * g;
Quaternion q = target.rotation * Quaternion.Inverse(transform.rotation);
if (q.w < 0)
{
q.x = -q.x;
q.y = -q.y;
q.z = -q.z;
q.w = -q.w;
}
q.ToAngleAxis(out float angle, out Vector3 axis);
axis.Normalize();
axis *= Mathf.Deg2Rad;
Vector3 torque = ksg * axis * angle + -_rigidbody.angularVelocity * kdg;
_rigidbody.AddTorque(torque, ForceMode.Acceleration);
}
void HookesLaw()
{
Vector3 displacementFromResting = transform.position - target.position;
Vector3 force = displacementFromResting * climbForce;
float drag = GetDrag();
playerRigidbody.AddForce(force, ForceMode.Acceleration);
playerRigidbody.AddForce(drag * -playerRigidbody.velocity * climbDrag, ForceMode.Acceleration);
}
float GetDrag()
{
Vector3 handVelocity = (target.localPosition - _previousPosition) / Time.fixedDeltaTime;
float drag = 1/handVelocity.magnitude + 0.01f;
drag = drag > 1? 1 : drag;
drag = drag < 0.03f ? 0.03f : drag;
_previousPosition = transform.position;
return drag;
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Chicken"))
{
HandyTagManagerScript.score++;
aud.Play();
Destroy(other.gameObject);
}
isCollion = true;
}
void OnCollisionExit(Collision other)
{
isCollion = false;
}
}