# I need to add simple waypoint AI to the car tutorial alternate physics.

I need to add simple waypoint AI to the CarController script of the Alternate physics model of the car tutorial. Can someone help me? I mean, I’ve used waypoint scripts before, but for this, i need to tie it in with the steering and all that jazz and am completely clueless as to how to do it.
For reference, here’s the carcontroller.js script.

``````using UnityEngine;
using System.Collections;

// This class is repsonsible for controlling inputs to the car.
// Change this code to implement other input types, such as support for analogue input, or AI cars.
[RequireComponent (typeof (Drivetrain))]
public class CarController : MonoBehaviour {

// Add all wheels of the car here, so brake and steering forces can be applied to them.
public Wheel[] wheels;

// A transform object which marks the car's center of gravity.
// Cars with a higher CoG tend to tilt more in corners.
// The further the CoG is towards the rear of the car, the more the car tends to oversteer.
// If this is not set, the center of mass is calculated from the colliders.
public Transform centerOfMass;

// A factor applied to the car's inertia tensor.
// Unity calculates the inertia tensor based on the car's collider shape.
// This factor lets you scale the tensor, in order to make the car more or less dynamic.
// A higher inertia makes the car change direction slower, which can make it easier to respond to.
public float inertiaFactor = 1.5f;

// current input state
float brake;
float throttle;
float throttleInput;
float steering;
float lastShiftTime = -1;
float handbrake;

// cached Drivetrain reference
Drivetrain drivetrain;

// How long the car takes to shift gears
public float shiftSpeed = 0.8f;

// These values determine how fast throttle value is changed when the accelerate keys are pressed or released.
// Getting these right is important to make the car controllable, as keyboard input does not allow analogue input.
// There are different values for when the wheels have full traction and when there are spinning, to implement
// traction control schemes.

// How long it takes to fully engage the throttle
public float throttleTime = 1.0f;
// How long it takes to fully engage the throttle
// when the wheels are spinning (and traction control is disabled)
public float throttleTimeTraction = 10.0f;
// How long it takes to fully release the throttle
public float throttleReleaseTime = 0.5f;
// How long it takes to fully release the throttle
// when the wheels are spinning.
public float throttleReleaseTimeTraction = 0.1f;

// Turn traction control on or off
public bool tractionControl = true;

// These values determine how fast steering value is changed when the steering keys are pressed or released.
// Getting these right is important to make the car controllable, as keyboard input does not allow analogue input.

// How long it takes to fully turn the steering wheel from center to full lock
public float steerTime = 1.2f;
// This is added to steerTime per m/s of velocity, so steering is slower when the car is moving faster.
public float veloSteerTime = 0.1f;

// How long it takes to fully turn the steering wheel from full lock to center
public float steerReleaseTime = 0.6f;
// This is added to steerReleaseTime per m/s of velocity, so steering is slower when the car is moving faster.
public float veloSteerReleaseTime = 0f;
// When detecting a situation where the player tries to counter steer to correct an oversteer situation,
// steering speed will be multiplied by the difference between optimal and current steering times this
// factor, to make the correction easier.
public float steerCorrectionFactor = 4.0f;

// Used by SoundController to get average slip velo of all wheels for skid sounds.
public float slipVelo {
get {
float val = 0.0f;
foreach(Wheel w in wheels)
val += w.slipVelo / wheels.Length;
return val;
}
}

// Initialize
void Start ()
{
if (centerOfMass != null)
rigidbody.centerOfMass = centerOfMass.localPosition;
rigidbody.inertiaTensor *= inertiaFactor;
drivetrain = GetComponent (typeof (Drivetrain)) as Drivetrain;
}

void Update ()
{
// Steering
Vector3 carDir = transform.forward;
float fVelo = rigidbody.velocity.magnitude;
Vector3 veloDir = rigidbody.velocity * (1/fVelo);
float angle = -Mathf.Asin(Mathf.Clamp( Vector3.Cross(veloDir, carDir).y, -1, 1));
float optimalSteering = angle / (wheels[0].maxSteeringAngle * Mathf.Deg2Rad);
if (fVelo < 1)
optimalSteering = 0;

float steerInput = 0;

steerInput = Input.GetAxis("steer");

if (steerInput < steering)
{
float steerSpeed = (steering>0)?(1/(steerReleaseTime+veloSteerReleaseTime*fVelo)) :(1/(steerTime+veloSteerTime*fVelo));
if (steering > optimalSteering)
steerSpeed *= 1 + (steering-optimalSteering) * steerCorrectionFactor;
steering -= steerSpeed * Time.deltaTime;
if (steerInput > steering)
steering = steerInput;
}
else if (steerInput > steering)
{
float steerSpeed = (steering<0)?(1/(steerReleaseTime+veloSteerReleaseTime*fVelo)) :(1/(steerTime+veloSteerTime*fVelo));
if (steering < optimalSteering)
steerSpeed *= 1 + (optimalSteering-steering) * steerCorrectionFactor;
steering += steerSpeed * Time.deltaTime;
if (steerInput < steering)
steering = steerInput;
}

// Throttle/Brake

float accel = 0;
accel = Input.GetAxis("drive");

if (drivetrain.automatic  drivetrain.gear == 0)
{
accel = -accel;
}

if (Input.GetKey (KeyCode.LeftShift))
{
throttle += Time.deltaTime / throttleTime;
throttleInput += Time.deltaTime / throttleTime;
}
else if (accel > 0)
{
if (drivetrain.slipRatio < 0.10f)
throttle += Time.deltaTime / throttleTime;
else if (!tractionControl)
throttle += Time.deltaTime / throttleTimeTraction;
else
throttle -= Time.deltaTime / throttleReleaseTime;

if (throttleInput < 0)
throttleInput = 0;
throttleInput += Time.deltaTime / throttleTime;
brake = 0;
}
else
{
if (drivetrain.slipRatio < 0.2f)
throttle -= Time.deltaTime / throttleReleaseTime;
else
throttle -= Time.deltaTime / throttleReleaseTimeTraction;
}
throttle = Mathf.Clamp01 (throttle);

if (accel < 0)
{
if (drivetrain.slipRatio < 0.2f)
brake += Time.deltaTime / throttleTime;
else
brake += Time.deltaTime / throttleTimeTraction;
throttle = 0;
throttleInput -= Time.deltaTime / throttleTime;
}
else
{
if (drivetrain.slipRatio < 0.2f)
brake -= Time.deltaTime / throttleReleaseTime;
else
brake -= Time.deltaTime / throttleReleaseTimeTraction;
}
brake = Mathf.Clamp01 (brake);
throttleInput = Mathf.Clamp (throttleInput, -1, 1);

// Handbrake
handbrake = Mathf.Clamp01 ( handbrake + (Input.GetButton ("HandBrake")? Time.deltaTime: -Time.deltaTime) );

// Gear shifting
float shiftThrottleFactor = Mathf.Clamp01((Time.time - lastShiftTime)/shiftSpeed);
drivetrain.throttle = throttle * shiftThrottleFactor;
drivetrain.throttleInput = throttleInput;

if(Input.GetKeyDown(KeyCode.Mouse0))
{
lastShiftTime = Time.time;
drivetrain.ShiftUp ();
}
if(Input.GetKeyDown(KeyCode.Mouse1))
{
lastShiftTime = Time.time;
drivetrain.ShiftDown ();
}
// Apply inputs
foreach(Wheel w in wheels)
{
w.brake = brake;
w.handbrake = handbrake;
w.steering = steering;
}
}

// Debug GUI. Disable when not needed.
/*	void OnGUI ()
{
GUI.Label (new Rect(0,60,100,200),"mph: "+rigidbody.velocity.magnitude * 2.719f);
tractionControl = GUI.Toggle(new Rect(0,80,300,20), tractionControl, "Traction Control (bypassed by shift key)");
}*/
}
``````

I really need some help here. Someone?!

Please, I have posted this before and nobody seems to want to answer. Can someone please give some guidance?

the ‘simplest’ way to create waypoint AI with Unity’s physics system is to ask your AI where he needs to go, and turn/accelerate accordingly (but staying within set limitations)

Basically, turn your AI (staying at a low speed so you don’t overshoot) until he is looking straight at the waypoint, and then full speed ahead.

Factor in collision detection accordingly.

Another way is to generate a list of actions and figure out the best sequence to reach your destination.

ok, so how about look at next way point, try to match the rotation, accelerate towards it, then repeat? Ok. So how would i get a list of waypoints in the c# script?

Sorry I can’t help you here. (I’m a Javascript Person) But maybe you could find some references of way point scripts to help you.

You would need to use some form of A*

I posted one of mine a little while ago here. You should be able to use it, or make your own.

So with that, if i removed the click to move code, and just made it move instead, it should do what i need?

And also, could you show me how to set it up?

I’m assuming you have some sort of logic that determines where the bike wants to go. You would replace the click to move code with that.

The sample scene shows everything. I also made a brief introduction on the page I linked you to.

Rereading this, I think I should make sure of something. A* is for if you want pathfinding. If you want your AI to go around in a set pattern, you will not need A*.

ah, well i just need waypoints… grr. Back to square 1!

They patrol with waypoints in the FPS tutorial here.

i know, as i said in the OP, I just need to make the car/bike turn with its wheels and accelerate towards each point. Alos, the script in the fps tut is in JS. I specifically asked for C#, because of this script.

This might sound like a really stupid answer, so sorry for my inexperience!

Now let’s say that you attached a script to the wheels (that you want to look at the waypoint) that uses LookAt() to face the variable named “nextWaypoint”. Then in a different script you calculated what the next waypoint is, and assigned that waypoint the the variable “nextWaypoint”. Then maybe the wheels might look at the next waypoint, and then go to that next waypoint.

Let me know if it works, and I’m sorry if it’s a “stupid answer”!

I agree with Rush-Rage. I think the simplest way to do it without A Star guiding you (wink), would be to set up a trigger at the curve, then use some form of LookAt() to turn the car(wheels), and Mathf.Clamp to set the boundaries for the car so it doesn’t go outside the boundaries of the track curve. For more realism, you could change that Mathf.Clamp variable depending on the speed of the car (building on what Dman suggested).

You would alter the direction of the vehicle the same way that the player would, but using automated functions instead of input. One thing you need to make sure of, is that you don’t overshoot (turn too far, causing the vehicle to turn back, turns slightly less too far, so on and so forth).

There are many ways to generate a list of waypoints. You can generate them manually by creating another script, filling out an array of Transform objects (the waypoints), and give it a method such as Transform GetNextWaypoint() which would return the next waypoint to move to (Just as Rush-Rage-Games pointed out). After the last waypoint, you can decide whether you want it to go back to the first, or reverse the order and start again.