Move vehicle towards a point

I would like to move a vehicle towards a point. Right now the code below which I took from monkeyzone makes the vehicle move towards the point but not in a straight line. It makes a zig-zag movement towards the point instead. What am I doing wrong?

I don’t understand why it doesn’t work. In the code below is everything monkeyzone uses, and the monkeyzone project works as intended, so why is the code below not working?

Moreover, I’ve been working on this for several weeks. I’ve looked at the monkeyzone project entirely but since it is divided into client an and server application it is very difficult to put together the entire behavior into one simple control, or even understand all of its parts. I guess @normen is a genius because the monkeyzone code is huge!

[java]public class AutonomousVehicleControl extends AbstractControl {

private float speed = 800f;
private Vector3f targetLocation = new Vector3f();
private Vector3f vector1 = new Vector3f();
private Vector3f vector2 = new Vector3f();
private Vector3f vector3 = new Vector3f();
private Vector3f vector4 = new Vector3f();
private VehicleControl vehicle;
private Plane plane = new Plane();

// private Plane plane2 = new Plane();
static final Quaternion ROTATE_RIGHT = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);

public void doMoveTo(Vector3f location) {
    targetLocation.set(location);
}


@Override
public void setSpatial(Spatial spatial) {
    this.spatial = spatial;
    if (spatial == null) {
        return;
    }


    Float spatialSpeed = (Float) spatial.getUserData("Speed");
    if (spatialSpeed != null) {
        speed = spatialSpeed;
    }
    vehicle = spatial.getControl(VehicleControl.class);
}



public void render(RenderManager rm, ViewPort vp) {
}

@Override
protected void controlUpdate(float tpf) 
{

    vehicle.getPhysicsLocation(vector1);
    vector2.set(targetLocation);
    vector2.subtractLocal(vector1);

    vector2.normalizeLocal();
    vehicle.getForwardVector(vector3).normalizeLocal();
    vector4.set(vector3);
    ROTATE_RIGHT.multLocal(vector4);
    plane.setOriginNormal(spatial.getWorldTranslation(), vector4);

    float dot = 1 - vector3.dot(vector2);
    float angle = vector3.angleBetween(vector2);

    float anglemult = 1;//FastMath.PI / 4.0f;
    float speedmult = 0.3f;//0.3f;

    if (angle > FastMath.QUARTER_PI) {
        angle = FastMath.QUARTER_PI;
    }
    //left or right
    if (plane.whichSide(targetLocation) == Plane.Side.Negative) {
        anglemult *= -1;
    }
    //backwards
    if (dot > 1) {
        speedmult *= -1;
        anglemult *= -1;
    }
    vehicle.steer(angle * anglemult);
    vehicle.accelerate(speed * speedmult);
    vehicle.brake(0);

}

protected void controlRender(RenderManager rm, ViewPort vp) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

}[/java]

As games go, MonkeyZone is pretty small, I think.

My guess from a quick look at the code is that the zig-zagging is because turning speed is not scaled by the result of the dot. Thus it’s always turning at maximum speed.

It might be sufficient to just set the anglemult to the dot value. I’m not sure as I would not have written steering this way.

And actually, I’m wrong. It’s just hard to read.

I’m not sure why it behaves as you say.

Do you require that your vehicle drives backwards?

It just drives backwards because of the examples are written that way. So no, it is not required.

Here is steering psuedo-code that should steer accurately towards a target:
[java]
Vector3f pos = …vehicle position…
Vector3f up = …vehicle ‘up’ direction…
Vector3f dir = …vehicle forward dir…
Vector3f targetPos = …where you want to go…

Vector3f left = up.cross(dir); // might be dir.cross(up)

Vector3f targetRelative = targetPos.subtract(pos).normalizeLocal();

float steer = left.dot(targetRelative);
float forward = dir.dot(targetRelative);

if( forward < 0 ) steer *= -1;

vehicle.steer(steeringSpeed * steer);
vehicle.accelerate(drivingSpeed * forward);

[/java]

Something like that.

Here is the code you suggest. But it never steers. It just goes forth without steering. Feel free to use the code in the car example in the jmonkey samples.

[java]public class AutonomousVehicleControl extends AbstractControl {

private float speed = 800f;
private Vector3f targetLocation = new Vector3f();
private Vector3f vector1 = new Vector3f();
private Vector3f vector2 = new Vector3f();
private Vector3f vector3 = new Vector3f();
private Vector3f vector4 = new Vector3f();
private VehicleControl vehicle;
private Plane plane = new Plane();

// private Plane plane2 = new Plane();
static final Quaternion ROTATE_RIGHT = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);

private Vector3f pos = new Vector3f();
private Vector3f up = new Vector3f();
private Vector3f dir = new Vector3f();
private Vector3f targetPos = new Vector3f();

public void doMoveTo(Vector3f location) {
    targetLocation.set(location);
}


@Override
public void setSpatial(Spatial spatial) {
    this.spatial = spatial;
    if (spatial == null) {
        return;
    }


    Float spatialSpeed = (Float) spatial.getUserData("Speed");
    if (spatialSpeed != null) {
        speed = spatialSpeed;
    }
    vehicle = spatial.getControl(VehicleControl.class);
}



public void render(RenderManager rm, ViewPort vp) {
}

@Override
protected void controlUpdate(float tpf) 
{

    vehicle.getPhysicsLocation(vector1);
    vector2.set(targetLocation);
    vector2.subtractLocal(vector1);
    

    vector2.normalizeLocal();
    
    pos.set(vehicle.getPhysicsLocation());
    up.set(new Vector3f(0,1,0));
    dir.set(vector2);
    targetPos.set(targetLocation);

    
    
    Vector3f left = up.cross(dir);  // might be dir.cross(up)

    Vector3f targetRelative = targetPos.subtract(pos).normalizeLocal();

    float steer = left.dot(targetRelative);
    float forward = dir.dot(targetRelative);

    if( forward &lt; 0 ) steer *= -1;

    vehicle.steer(-200 * steer);
    vehicle.accelerate(-200 * forward);

    /**
    vehicle.getForwardVector(vector3).normalizeLocal();
    vector4.set(vector3);
    ROTATE_RIGHT.multLocal(vector4);
    plane.setOriginNormal(spatial.getWorldTranslation(), vector4);

    float dot = 1 - vector3.dot(vector2);
    float angle = vector3.angleBetween(vector2);

    float anglemult = 1;//FastMath.PI / 4.0f;
    float speedmult = 0.3f;//0.3f;

    if (angle &gt; FastMath.QUARTER_PI) {
        angle = FastMath.QUARTER_PI;
    }
    //left or right
    if (plane.whichSide(targetLocation) == Plane.Side.Negative) {
        anglemult *= -1;
    }
    //backwards
    if (dot &gt; 1) {
        speedmult *= -1;
        anglemult *= -1;
    }
    vehicle.steer(angle * anglemult);
    vehicle.accelerate(speed * speedmult);
    vehicle.brake(0);
    */

}

protected void controlRender(RenderManager rm, ViewPort vp) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

}[/java]

I’m preparing a test case right now, please wait.

Well, this:
vehicle.steer(-200 * steer);

…means that the max turn speed is 63 times around the circle per second. Pretty excessive I think. Anything more than FastMath.HALF_PI is going to cause very strange behavior I think.

…and the only reason - would be needed is if the left vector is backwards, I think… ie: the command about up.cross(dir) potentially being backwards.

Oh, wow. I found the solution! While preparing the test case I changed the speed from 800 to -800. And it works. The explanation is that my vehicle is driving backwards as the examples on jmonkeyengine.org tell you to do it, but @normen 's code is using forward driving which explains the positive 800.

Right now it works like a charm… but with the X axis flipped so if you tell him to go to newVector(500,0,0) the car will go toward the point newVector(-500,0,0) which is no big deal, I can fix that.

Wow, it feel so great. I had been working on this for a while. ^.^

Thanks for the help @pspeed . This pretty much completes my latest game. ^.^

You know what… I’m not sure how vehicle control works exactly and the javadoc is strange:
public void steer(float value)

Set the given steering value to all front wheels (0 = forward)

Parameters:
    value - the steering angle of the front wheels (Pi = 360deg)

I’m not sure what universe Pi = 360deg so it’s either an error in the javadoc or there is some funny math going on.

Either way, the key will be to debug the values. Log the various things to see what they are.

I didn’t know about the pi thing either. But I had to keep coding.

@Pixelapp said: Oh, wow. I found the solution! While preparing the test case I changed the speed from 800 to -800. And it works. The explanation is that my vehicle is driving backwards as the examples on jmonkeyengine.org tell you to do it, but @normen 's code is using forward driving which explains the positive 800.

Right now it works like a charm… but with the X axis flipped so if you tell him to go to newVector(500,0,0) the car will go toward the point newVector(-500,0,0) which is no big deal, I can fix that.

Wow, it feel so great. I had been working on this for a while. ^.^

Thanks for the help @pspeed . This pretty much completes my latest game. ^.^

No example tells you to drive your vehicles backwards. The Ferrari example does that because the Ferrari is backwards and notes that it does so as to not confuse people. Apparently it still does.

Edit: Btw, MonkeyZone has code that steers a car towards a given point.