- Home /
Need help with limiting rotation.
I'm brand new to unity and scripting and I'm working on a vehicle in unity that will be able to avoid anything in it's way. It's going to be pretty simple. I want it to drive forward, stop if it gets too close to a wall, then decide if it should turn right or left. It uses ray-casting to check for obstacles. The car body is a simple object I made in Blender and it is connected to cylinders with hinge joints for the wheels. Both the body and the wheels are rigidbodys. At the moment it drives forward just like I want it to, then it stops when it comes to a wall, then it sends rays out the sides to see if there is a wall on the right or left. If there is, it will start rotating away from the wall. My problem is I want to make it stop rotating when it was turn X amount of degrees. Anyone that knows how to do this please help. Below is a youtube link for a video showing what the vehicle does at the moment.
Here is the script below for those that need to see it. By the way, it's a JavaScript.
var mode : String = "nothing";
var force : float = 10;
var turnpower : float = 10;
function Start()
{
yield(WaitForSeconds(3));
mode = "gofwd";
}
function Update()
{
var fwd = transform.TransformDirection(Vector3.forward);
Debug.DrawRay(transform.position, fwd *15, Color.yellow);
if(mode == "gofwd")
{
rigidbody.AddForce(0,0,force);
}
if(Physics.Raycast(transform.position, fwd, 15) && mode == "gofwd")
{
mode = "stop";
}
if(mode == "stop")
{
Turn();
}
if(mode == "rightorleft")
{
var left = transform.TransformDirection(Vector3.left);
var right = transform.TransformDirection(Vector3.right);
Debug.DrawRay(transform.position, left *40, Color.red);
Debug.DrawRay(transform.position, right *40, Color.green);
if(Physics.Raycast(transform.position, left, 40))
{
rigidbody.AddTorque (0, turnpower, 0);
}
}
}
function Turn()
{
yield(WaitForSeconds(3));
mode = "rightorleft";
}
Answer by robertbu · Mar 15, 2013 at 02:31 AM
There are a couple of ways to approach this problem. The simplest is probably to just use an absolute angle;
var destAngle : float; // At the top of the file;
This calcualtes a 45 degree right turn
destAngle = Atan2(transform.forward.z, transform.forward.x) * Mathf.Rad2Deg;
destAngle = destAngle - 45.0;
And this is how you might check it in Update()
var currAngle = Atan2(transform.forward.z, transform.forward.x) * Mathf.Rad2Deg);
if (Mathf.Abs(Mathf.DeltaAngle(currAngle, destAngle) < threshold)) {
; // Code here to stop the turn;
}
Note, looking at your code, just because you are not still applying torque, doesn't mean the car will straighten out. You will have to counteract the torque somehow...friction, drag, counter force...
Also you have to be careful about how you set threshold. It needs to be big enough so that a fps drop will not allow the car to skip on by and keep rotation another 360 degrees. As an alternative, you could save the previous angle from the previous frame and check to make sure it is decreasing. You would bail out of turning when the angle started climbing again. Note this might also cause the car to stop turning if it collided with something that effected his angular velocity.
I had a couple of typos. Corrected code below. You need to define a variable called 'threshold' with a meaningful threshold for your situation (or hard code a value). You want it small enough to do the job but large enough so that if the frame rate drops, the calculation won't skip on by the check.
var currAngle = $$anonymous$$athf.Atan2(transform.forward.z, transform.forward.x) * $$anonymous$$athf.Rad2Deg;
if ($$anonymous$$athf.Abs($$anonymous$$athf.DeltaAngle(currAngle, destAngle)) < threshold) {
; // Code here to stop the turn;
}
Okay I've been experimenting with the code because there are no errors anymore but I'm not getting the desired result. Here is the code so you can look over in just to make sure I have everything in the right place. I've made a print command where I will code later to stop the turn to make sure it's working right. If I set the threshold to a positive number it gives me the print message as soon as it starts turning, or as soon as it goes to "rightorleft" mode. If I set the threshold to a negative number it does not give me the message at all.
var mode : String = "nothing";
var force : float = 10;
var turnpower : float = 10;
var destAngle : float;
function Start()
{
yield(WaitForSeconds(3));
mode = "gofwd";
}
function Update()
{
var fwd = transform.TransformDirection(Vector3.forward);
Debug.DrawRay(transform.position, fwd *15, Color.yellow);
if(mode == "gofwd")
{
rigidbody.AddForce(0,0,force);
}
if(Physics.Raycast(transform.position, fwd, 15) && mode == "gofwd")
{
mode = "stop";
}
if(mode == "stop")
{
Turn();
}
if(mode == "rightorleft")
{
var left = transform.TransformDirection(Vector3.left);
var right = transform.TransformDirection(Vector3.right);
Debug.DrawRay(transform.position, left *40, Color.red);
Debug.DrawRay(transform.position, right *40, Color.green);
if(Physics.Raycast(transform.position, left, 40))
{
var currAngle = $$anonymous$$athf.Atan2(transform.forward.z, transform.forward.x) * $$anonymous$$athf.Rad2Deg;
destAngle = destAngle - 45.0;
rigidbody.AddTorque (0, turnpower, 0);
var threshold : float = -1000;
if ($$anonymous$$athf.Abs($$anonymous$$athf.DeltaAngle(currAngle, destAngle)) < threshold)
{
print("Okay. Stop turning now.");
}
}
}
}
function Turn()
{
yield(WaitForSeconds(2));
mode = "rightorleft";
}
As a start on line 45, you need to assign to destAngle, not currAngle. Or you could rewrite the next line to be:
destAngle = currAngle - 45;
'threshold' will be a positive number.