Skip to content

Instantly share code, notes, and snippets.

@nanodeath
Created July 9, 2018 01:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanodeath/46089e944d1984f4e9f6ecd47022b977 to your computer and use it in GitHub Desktop.
Save nanodeath/46089e944d1984f4e9f6ecd47022b977 to your computer and use it in GitHub Desktop.
Unity: Rotating a RigidBody2D to face the cursor, smoothly
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FaceCursor : MonoBehaviour {
// 100 seems to work fine on an object with mass around 1kg.
[Tooltip("Amount of torque to apply when turning")]
public float turnSpeed;
private Rigidbody2D body;
void Start() {
body = GetComponent<Rigidbody2D>();
}
void FixedUpdate() {
var gameObjectToMouse = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
var targetAngle = wrapAngleAroundZero(Mathf.Atan2(gameObjectToMouse.y, gameObjectToMouse.x) * Mathf.Rad2Deg);
var currentAngle = wrapAngleAroundZero(transform.eulerAngles.z);
var torque = turnSpeed * Time.fixedDeltaTime;
// I have no idea what this actually is or what to call it, but it works...
var angularDelta = torque / body.inertia;
// How long would it take us to stop? We need this in case we should actually be slamming on the brakes.
var timeRequiredToStop = Mathf.Abs(body.angularVelocity / angularDelta * Time.fixedDeltaTime);
// Which direction should we go? Depends on which way is faster.
// This doesn't factor in current speed or direction, but eh, close enough.
var timeUntilDestinationReachedCCW = (targetAngle - currentAngle) / Mathf.Abs(body.angularVelocity);
var timeUntilDestinationReachedCW = -timeUntilDestinationReachedCCW;
// This is best explained with an example.
// If you're at -135°, travelling at -45°/s, and trying to reach -90°, how long will that take?
// Since you're going counterclockwise, that's (-90 - -135) / -45 = -1 second, which doesn't make any
// sense, except indicates that you overshot it. So you have to go all the way around, which takes
// 360 / 45 = 8 seconds. So if you add 8 to -1, you get 7 seconds, which makes sense.
var circleRotationTime = 360 / Mathf.Abs(body.angularVelocity);
if (timeUntilDestinationReachedCCW < 0) timeUntilDestinationReachedCCW += circleRotationTime;
if (timeUntilDestinationReachedCW < 0) timeUntilDestinationReachedCW += circleRotationTime;
var timeUntilDestination = Mathf.Min(timeUntilDestinationReachedCCW, timeUntilDestinationReachedCW);
if (timeRequiredToStop > timeUntilDestination) {
// If we're close, slam on the brakes!
// If it takes us 2.5 seconds to stop, but 2.3 seconds until we arrive, well we better try to stop.
body.AddTorque(-1 * Mathf.Sign(body.angularVelocity) * torque);
} else if (timeUntilDestinationReachedCW < timeUntilDestinationReachedCCW) {
body.AddTorque(-torque);
} else {
body.AddTorque(torque);
}
}
// Clamps to [-180, 180]
private static float wrapAngleAroundZero(float a) {
if (a >= 0) {
float rotation = a % 360;
if (rotation > 180) rotation -= 360;
return rotation;
} else {
float rotation = -a % 360;
if (rotation > 180) rotation -= 360;
return -rotation;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment