- Home /
Using rigidbody.AddTorque to have character look at cursor
I'm attempting to build a 2.5D arcade style free roaming space shooter. I've modified the ShipControls.js found here. In the original script the player controlled the ship with the keyboard only. I've modified the script with a mouselook, so the ship will now always point towards my cursor.
The original script used some code that read the objects angularVelocity amount and used that to bank the ship in the direction of the turn. It actually looked great on my ship, but I've lost that ability with mouselook.
I've been trying to work out a solution for a couple days, but my brain is fried. This stuff is keeping me awake at night.
I've tried to find a way to use torque to match the ships orientation to the point returned from a raycast, but have been unsuccessful. I've also tried to think of some value produced by the transform.rotation of the mouselook that I could use to initiate the banking effect, but no dice.
I'm at the point to where I'm thinking of rewriting the code entirely without a rigidbody, but I'm not sure how to get the banking effect with mouselook in any case.
So, to get to the point, I'm looking for a way to do the following:
Code a physics based "object look at mouse" script, or;
Find a way to use the transform.rotation in the current script to bank the ship during a turn;
It could be something incredibly simple that I'm missing... I've been struggling with this for far too long and my brain is mush.
I'll attach my code here. I've tried to write most of it longhand, as I am a beginner, and I apologize for the number of notes; I wrote them for my own benefit. Note also that it still contains some of the code for the original key-press turning control that I have yet to remove.
@script RequireComponent (Rigidbody)
//Inspector variables
var hoverHeight : float = 3; //Height ship will hover
var hoverHeightStrictness : float = 1.0; //Strictness to hover height
var forwardThrust : float = 20000.0; //Player thrust
var backwardThrust : float = 10000.0; //Player backwards thrust
var strafeThrust : float = 10000.0; //Player strafing thrust
var bankAmount : float = 0.1; //Amount for ship to bank when turning
var bankSpeed : float = 0.2; //Speed ship will bank when turning
var bankAxis : Vector3 = new Vector3(0.0, 0.0, -1.0); //Axis ship will bank towards
var turnSpeed : float = 8.0; //Speed at which ship will turn
var boostSpeed : float = 1.5; //Amount that booster will increase speed
var forwardDirection : Vector3 = new Vector3(0.0, 0.0, 1.0); //Forward directional Axis of the ship
var strafeDirection : Vector3 = new Vector3(1.0, 0.0, 0.0); //Side to side directional Axis of the ship
var mass : float = 5.0; //Mass of the ship
var sqrdSpeedThresholdForDrag : float = 25.0; //Positional drag
var superDrag : float = 2.0; //Positional drag
var fastDrag : float = 0.5; //Positional drag
var slowDrag : float = 0.01; //Positional drag
var sqrdAngularSpeedThresholdForDrag : float = 5.0; //Angular drag
var superADrag : float = 32.0; //Angular drag
var fastADrag : float = 16.0; //Angular drag
var slowADrag : float = 0.1; //Angular drag
var playerControl : boolean = true; //Variable to set whether ship is player controlled or not
//Private variables
private var bank : float = 0.0; //Used to calculate banking
private var thrust : float = 0; //Thrust rate controller
private var turn : float = 0; //Turn rate controller
private var strafe : float = 0; //Strafe rate controller
private var thrustGlowOn : boolean = false; //Sets the thrustGlowOn private variable to be false
private var boostGlowOn : boolean = false; //Sets the boostGlowOn private variable to be false
private var leftThrustGlowOn : boolean = false; //Sets the leftThrustGlowOn private variable to be false
private var rightThrustGlowOn : boolean = false; //Sets the rightThrustGlowOn private variable to be false
function SetPlayerControl(control : boolean) //Calling the playercontrol inspector variable for control functions
{
playerControl = control;
}
function Start()
{
gameObject.rigidbody.mass = mass; //Sets the rigidbody mass to be equal to the mass inspector variable
}
function FixedUpdate()
{
if (Mathf.Abs(thrust) > 0.01) //Sets the rididbody drag to equal inspector variables based on velocity
{
if (rigidbody.velocity.sqrMagnitude > sqrdSpeedThresholdForDrag)
rigidbody.drag = fastDrag;
else
rigidbody.drag = slowDrag;
}
else
rigidbody.drag = superDrag;
if (Mathf.Abs(turn) > 0.01) //Sets the rigidbody angular drag to equal inspector variables based on angular velocity
{
if (rigidbody.angularVelocity.sqrMagnitude > sqrdAngularSpeedThresholdForDrag)
rigidbody.angularDrag = fastADrag;
else
rigidbody.angularDrag = slowADrag;
}
else
rigidbody.angularDrag = superADrag;
if (Mathf.Abs(strafe) > 0.01) //Sets the rigidbody angular drag to equal inspector variables based on angular velocity
{
if (rigidbody.velocity.sqrMagnitude > sqrdSpeedThresholdForDrag)
rigidbody.drag = fastDrag;
else
rigidbody.drag = slowDrag;
}
else
rigidbody.drag = superDrag;
if (Mathf.Abs(strafe) > 0.01 && Mathf.Abs(thrust) > 0.01) //Sets the rigidbody angular drag to equal inspector variables based on angular velocity
{
if (rigidbody.velocity.sqrMagnitude > sqrdSpeedThresholdForDrag)
rigidbody.drag = fastDrag;
else
rigidbody.drag = slowDrag;
}
else
rigidbody.drag = superDrag;
transform.position = Vector3.Lerp(transform.position, new Vector3(transform.position.x, hoverHeight, transform.position.z), hoverHeightStrictness); //Hovers the ship
//Ship banking based on angularVelocity
var amountToBank : float = rigidbody.angularVelocity.y * bankAmount; //Sets the amountToBank variable to be equal to the angular velocity multiplied by the bankAmount inspector variable
bank = Mathf.Lerp(bank, amountToBank, bankSpeed); //Sets the bank private variable to be between the current bank angle and the amountToBank inspector variable
//at the speed defined in the bankSpeed inspector variable
var rotation : Vector3 = transform.rotation.eulerAngles; //Sets the rotation variable to be equal to rotation in eularangles (x, y, z)
rotation = rotation * Mathf.Deg2Rad; //Converts the rotation variable from degrees to radians
rotation.x = 0; //Sets the x axis rotation value
rotation.z = 0; //Sets the z axis rotation value
rotation = rotation + bankAxis * bank; //Adds the value of the rotation variable to the product of the bankAxis and bank variables
rotation = rotation * Mathf.Rad2Deg; //Converts the rotation variable from radians to degrees
transform.rotation = Quaternion.Euler(rotation); //Banks the ship based on the above information
}
//Thrust Controls
function Thrust (item : float) //Sets the thrust variable to return a value between 1.0 and -1.0
{
thrust = Mathf.Clamp(item, -1.0, 1.0 );
}
function Turn (item : float) //Sets the turn variable to return a value between 1.0 and -1.0 and multiplies it by the turnSpeed inspector variable
{
turn = Mathf.Clamp(item, -1.0, 1.0 ) * turnSpeed;
}
function Strafe (item : float) //Sets the strafe variable to return a value between 1.0 and -1.0
{
strafe = Mathf.Clamp(item, -1.0, 1.0);
}
//Game Loop
function Update ()
{
//Game loop variables
var theThrust : float = thrust; //Sets theThrust variable to be equal to the value of the thrust variable
var theStrafeThrust : float = strafe; //Sets theStrafeThrust variable to be equal to the value of the strafe variable
if (playerControl) //Checks to see if this ship is controllable
{
thrust = Input.GetAxis("Vertical"); //Sets the thrust variable to be equal to Input.GetAxis("Vertical")
boost = Input.GetAxis("Boost") * boostSpeed; //Sets the boost variable to be equal to Input.GetAxis("Boost") multiplied by the boostSpeed inspector variable value
strafe = Input.GetAxis("Horizontal"); //Sets the strafe variable to be equal to Input.GetAxis("Horizontal")
}
//Thrust movement
if (thrust > 0.0 && boost < 0.0) //If Input.GetAxis("Vertical") is pressed and Input.GetAxis("Boost") isn't pressed
{
theThrust *= forwardThrust; //Multiplies theThrust variable with the forwardThrust inspector variable
if (thrustGlowOn == false) //If the thrustGlowOn variable is set to false
{
thrustGlowOn = false; //Sets the thrustGlowOn variable to false and broadcasts thrustGlowOn
BroadcastMessage("SetThrustGlow", thrustGlowOn, SendMessageOptions.DontRequireReceiver);
}
}
else if (thrust > 0.0 && boost > 0.0) //If Input.GetAxis("Vertical") and Input.GetAxis("Boost") are both pressed
{
theThrust = theThrust * forwardThrust * boost; //Multiplies theThrust variable with the value of the forwardThrust and boostSpeed inspector variables
if (boostGlowOn == false) //If the boostGlowOn variable is set to false
{
boostGlowOn = false; //Sets the boostGlowOn variable to false and broadcasts boostGlowOn
BroadcastMessage("SetBoostGlow", boostGlowOn, SendMessageOptions.DontRequireReceiver);
}
}
else
{
theThrust *= backwardThrust; //Multiplies theThrust variable with the backwardThrust inspector variable
if (thrustGlowOn == true) //If the thrustGlowOn variable is set to true
{
thrustGlowOn = false; //Sets the thrustGlowOn variable to false and broadcasts thrustGlowOn
BroadcastMessage("SetThrustGlow", thrustGlowOn, SendMessageOptions.DontRequireReceiver);
}
}
if (strafe >= 0.1) //If the positive Input.GetAxis("Horizontal") key is pressed
{
theStrafeThrust *= strafeThrust; //Multiplies theStrafeThrust variable with the strafeThrust inspector variable
if (leftThrustGlowOn == false) //If the leftThrustGlowOn variable is set to false
{
leftThrustGlowOn = false; //Sets the leftThrustGlow variable to false and broadcasts leftThrustGlowOn
BroadcastMessage("SetThrustGlow", leftThrustGlowOn, SendMessageOptions.DontRequireReceiver);
}
}
else if (strafe <= 0.1) //If the negative (Input.GetAxis("Horizontal") key is pressed
{
theStrafeThrust *= strafeThrust; //Multiplies theStrafeThrust variable with the strafeThrust inspector variable
if (rightThrustGlowOn == false) //If the rightThrustGlowOn variable = false
{
rightThrustGlowOn = false; //Sets the rightThrustGlowOn variable to false and broadcasts rightThrustGlowOn
BroadcastMessage("SetThrustGlow", rightThrustGlowOn, SendMessageOptions.DontRequireReceiver);
}
}
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist))
{
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
}
rigidbody.AddRelativeTorque(Vector3(0, 1, 0) * turn * Time.deltaTime); //Applies angular torque to the ship on the y axis multiplied by the turn variable by actual time
rigidbody.AddRelativeForce(forwardDirection * theThrust * Time.deltaTime); //Applies force in the axis direction set in the forwardDirection inspector variable, multiplied by
//theThrust variable by actual time
rigidbody.AddRelativeForce(strafeDirection * theStrafeThrust * Time.deltaTime); //Applies force in the axis direction set in th sideDirection inspector variable, multiplied by
//theStrafeThrust variable by actual time
}
I've gotten the ship to try to follow my mouse, but in the following script it seems to be using the angle as if my ship were always facing forward, so that if I have the mouse to the left of the object it spins left, right it spins right etc.
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist))
{
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
var targetAngle = targetRotation.eulerAngles.y;
if (targetAngle < 180.0)
{
rigidbody.AddTorque(Vector3(0, 1, 0) * turnSpeed * Time.deltaTime);
}
else if (targetAngle > 180.0)
{
rigidbody.AddTorque(Vector3(0, -1, 0) * turnSpeed * Time.deltaTime);
}
}
print("Target Angle " + targetAngle);
Ok, this is working, but I need to find a way to make the rotation take the shortest path. For example, if the currentRotation of the ship is 10 degrees, and the targetRotation is anything greater the ship will turn to the right to reach the targetRotation, ins$$anonymous$$d of turning left and vice-versa.
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist))
{
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
var targetAngle = targetRotation.eulerAngles.y;
var currentAngle = transform.eulerAngles.y;
if (targetAngle > currentAngle)
{
rigidbody.AddTorque(Vector3(0, 1, 0) * turnSpeed * Time.deltaTime);
}
else if (targetAngle < currentAngle)
{
rigidbody.AddTorque(Vector3(0, -1, 0) * turnSpeed * Time.deltaTime);
}
}
print("Target Angle " + targetAngle);
Answer by Thronin · Feb 14, 2013 at 12:13 AM
Got it working perfectly. Is there any reason why I wouldn't want to use this? Will this adversely affect performance or develop issues later on down the line? Thanks!
var turnSpeed : float = 15000.0;
var turnSmooth : float = 2.0;
var playerPlane = new Plane(Vector3.up, transform.position);
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hitdist = 0.0;
if (playerPlane.Raycast (ray, hitdist))
{
var targetPoint = ray.GetPoint(hitdist);
var targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
var targetAngle = targetRotation.eulerAngles.y;
var currentAngle = transform.eulerAngles.y;
var upAngleSmooth = currentAngle + turnSmooth;
var downAngleSmooth = currentAngle - turnSmooth;
//Turn coditions
if (targetAngle > upAngleSmooth)
{
if (targetAngle - currentAngle > 180.0)
{
rigidbody.AddTorque(Vector3(0, -1, 0) * turnSpeed * Time.deltaTime);
}
else if (targetAngle - currentAngle < 180.0)
{
rigidbody.AddTorque(Vector3(0, 1, 0) * turnSpeed * Time.deltaTime);
}
}
else if (targetAngle < downAngleSmooth)
{
if (currentAngle - targetAngle > 180.0)
{
rigidbody.AddTorque(Vector3(0, 1, 0) * turnSpeed * Time.deltaTime);
}
else if (currentAngle - targetAngle < 180.0)
{
rigidbody.AddTorque(Vector3(0, -1, 0) * turnSpeed * Time.deltaTime);
}
}
}