AIController

Hi there folks



Cream's back, long time no see :slight_smile:



So i returned to my AI project starting off with Mojos Vehicle Unit to use it as a base of what i am calling a Unit

More about that later.

This Unit will be a unit steered by AI and as there must be steering forces for something which should be steered i build up a class where i can steer a vehicle.



First the Code:


package com.basics.ai.controller;

import com.jme.math.*;
import com.jme.input.action.*;

import jmetest.flagrushtut.lesson6.Vehicle;
import jmetest.flagrushtut.lesson6.actions.DriftAction;

import com.basics.ai.exception.*;
public class AIController {

    //the node to manipulate
    private Vehicle node;
    //temporary vector for the rotation
    private static final Vector3f tempVa = new Vector3f();

    /**
    * The vehicle to accelerate is supplied during construction.
    * @param vehicle the vehicle to speed up.
    */
    public AIController(Vehicle node) {
        this.node = node;
    }
    /**
    * the action calls the vehicle's accelerate command which adjusts its velocity. It
    * then translates the vehicle based on this new velocity value.
    */
    public void performAccelerateAction(InputActionEvent evt) {
        node.accelerate(evt.getTime());
        Vector3f loc = node.getLocalTranslation();
        loc.addLocal(node.getLocalRotation().getRotationColumn(2, tempVa)
                    .multLocal(node.getVelocity() * evt.getTime()));
        node.setLocalTranslation(loc);

    }

    /**
    * the action calls the vehicle's brake command which adjusts its velocity. It
    * then translates the vehicle based on this new velocity value.
    */
    public void performBrakeAction(InputActionEvent evt) {
        node.brake(evt.getTime());
        Vector3f loc = node.getLocalTranslation();
        loc.addLocal(node.getLocalRotation().getRotationColumn(2, tempVa)
                    .multLocal(node.getVelocity() * evt.getTime()));
        node.setLocalTranslation(loc);
    }

    /**
    * the action calls the vehicle's drift command which adjusts its velocity. It
    * then translates the vehicle based on this new velocity value.
    */
    public void performDriftAction(InputActionEvent evt) {
        node.drift(evt.getTime());
        Vector3f loc = node.getLocalTranslation();
        loc.addLocal(node.getLocalRotation().getRotationColumn(2, tempVa)
                    .multLocal(node.getVelocity() * evt.getTime()));
        node.setLocalTranslation(loc);
    }

    //temporary variables to handle rotation
    private static final Matrix3f incr = new Matrix3f();
    private static final Matrix3f tempMa = new Matrix3f();
    private static final Matrix3f tempMb = new Matrix3f();

    //we are using +Y as our up
    private Vector3f upAxis = new Vector3f(0, 1, 0);
    private Vector3f rightAxis = new Vector3f(1, 0, 0);
    private Vector3f depthAxis = new Vector3f(0, 0, 1);
    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performRotateLeftAction(InputActionEvent evt) {
    upAxis = node.getLocalRotation().getRotationColumn(1);
        //we want to turn differently depending on which direction we are traveling in.
        if (node.getVelocity() < 0) {
            incr.fromAxisAngle(upAxis, -(node.getTurnSpeed() / 2) * evt.getTime());
        } else {
            incr.fromAxisAngle(upAxis, (node.getTurnSpeed() / 2) * evt.getTime());
        }
        node.getLocalRotation().fromRotationMatrix(
                incr.mult(node.getLocalRotation().toRotationMatrix(tempMa),
                          tempMb));
        node.getLocalRotation().normalize();
    }

    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performRotateRightAction(InputActionEvent evt) {
    upAxis = node.getLocalRotation().getRotationColumn(1);
        if (node.getVelocity() < 0) {
            incr.fromAxisAngle(upAxis, node.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(upAxis, -node.getTurnSpeed() * evt.getTime());
        }
        node.getLocalRotation().fromRotationMatrix(
                incr.mult(node.getLocalRotation().toRotationMatrix(tempMa),
                          tempMb));
        node.getLocalRotation().normalize();
    }

    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performRollLeftAction(InputActionEvent evt) {
    depthAxis = node.getLocalRotation().getRotationColumn(2);
        //we want to turn differently depending on which direction we are traveling in.
        if(node.getVelocity() < 0) {
            incr.fromAxisAngle(depthAxis, -node.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(depthAxis, node.getTurnSpeed() * evt.getTime());
        }
        node.getLocalRotation().fromRotationMatrix(
                incr.mult(node.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        node.getLocalRotation().normalize();
    }
   
    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performRollRightAction(InputActionEvent evt) {
    depthAxis = node.getLocalRotation().getRotationColumn(2);
        if (node.getVelocity() < 0) {
            incr.fromAxisAngle(depthAxis, node.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(depthAxis, -node.getTurnSpeed() * evt.getTime());
        }
        node.getLocalRotation().fromRotationMatrix(
                incr.mult(node.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        node.getLocalRotation().normalize();
    }
   
    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performRotateDownAction(InputActionEvent evt) {
    rightAxis = node.getLocalRotation().getRotationColumn(0);
    //we want to turn differently depending on which direction we are traveling in.
        if(node.getVelocity() < 0) {
            incr.fromAxisAngle(rightAxis, -node.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(rightAxis, node.getTurnSpeed() * evt.getTime());
        }
        node.getLocalRotation().fromRotationMatrix(
                incr.mult(node.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        node.getLocalRotation().normalize();
    }
   
    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performRotateUpAction(InputActionEvent evt) {
    rightAxis = node.getLocalRotation().getRotationColumn(0);
        if (node.getVelocity() < 0) {
            incr.fromAxisAngle(rightAxis, node.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(rightAxis, -node.getTurnSpeed() * evt.getTime());
        }
        node.getLocalRotation().fromRotationMatrix(
                incr.mult(node.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        node.getLocalRotation().normalize();
    }
   
}


As u can see theres not that much new in it.
The last methods came up when i moved on from the car sample to an aircraft sample where i also wanted to steer up and down or make a roll to the left or the right.
While testing this out i found out that if you leave the 2D Area of a Car Sample you have to readjust the Axis of Movement (upAxis, depthAxis, rightAxis).

I also made up 4 Controller to make my Vehicle capable of the same movement.

package com.jme.input.action;

import jmetest.flagrushtut.lesson6.Vehicle;

import com.jme.input.action.InputActionEvent;
import com.jme.input.action.KeyInputAction;
import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;

/**
* VehicleRotateLeftAction turns the vehicle to the left (while
* traveling forward).
* @author Mark Powell
*
*/
public class VehicleRollLeftAction  extends KeyInputAction {
    //temporary variables to handle rotation
    private static final Matrix3f incr = new Matrix3f();
    private static final Matrix3f tempMa = new Matrix3f();
    private static final Matrix3f tempMb = new Matrix3f();

    //we are using +Z as our up
    private Vector3f upAxis = new Vector3f(0,0,1);
    //the node to manipulate
    private Vehicle vehicle;
 
    /**
    * create a new action with the vehicle to turn.
    * @param vehicle the vehicle to turn
    */
    public VehicleRollLeftAction(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performAction(InputActionEvent evt) {
    upAxis = vehicle.getLocalRotation().getRotationColumn(2);
        //we want to turn differently depending on which direction we are traveling in.
        if(vehicle.getVelocity() < 0) {
            incr.fromAxisAngle(upAxis, -vehicle.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(upAxis, vehicle.getTurnSpeed() * evt.getTime());
        }
        vehicle.getLocalRotation().fromRotationMatrix(
                incr.mult(vehicle.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        vehicle.getLocalRotation().normalize();
    }
}


package com.jme.input.action;

import jmetest.flagrushtut.lesson6.Vehicle;

import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;

public class VehicleRollRightAction extends KeyInputAction {
    // temporary variables to handle rotation
    private static final Matrix3f incr = new Matrix3f();
    private static final Matrix3f tempMa = new Matrix3f();
    private static final Matrix3f tempMb = new Matrix3f();

    // the node to manipulate
    private Vehicle vehicle;

    private Vector3f upAxis = new Vector3f(0, 0, 1);

    /**
    * create a new action with the vehicle to turn.
    *
    * @param vehicle
    *            the vehicle to turn
    */
    public VehicleRollRightAction(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performAction(InputActionEvent evt) {
    upAxis = vehicle.getLocalRotation().getRotationColumn(2);
        if (vehicle.getVelocity() < 0) {
            incr.fromAxisAngle(upAxis, vehicle.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(upAxis, -vehicle.getTurnSpeed() * evt.getTime());
        }
        vehicle.getLocalRotation().fromRotationMatrix(
                incr.mult(vehicle.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        vehicle.getLocalRotation().normalize();
    }
}


package com.jme.input.action;

import jmetest.flagrushtut.lesson6.Vehicle;

import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;

public class VehicleRotateRightAction extends KeyInputAction {
    // temporary variables to handle rotation
    private static final Matrix3f incr = new Matrix3f();
    private static final Matrix3f tempMa = new Matrix3f();
    private static final Matrix3f tempMb = new Matrix3f();

    // the node to manipulate
    private Vehicle vehicle;

    private Vector3f upAxis = new Vector3f(0, 1, 0);

    /**
    * create a new action with the vehicle to turn.
    *
    * @param vehicle
    *            the vehicle to turn
    */
    public VehicleRotateRightAction(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performAction(InputActionEvent evt) {
    upAxis = vehicle.getLocalRotation().getRotationColumn(1);
        if (vehicle.getVelocity() < 0) {
            incr.fromAxisAngle(upAxis, vehicle.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(upAxis, -vehicle.getTurnSpeed() * evt.getTime());
        }
        vehicle.getLocalRotation().fromRotationMatrix(
                incr.mult(vehicle.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        vehicle.getLocalRotation().normalize();
    }
}


package com.jme.input.action;

import jmetest.flagrushtut.lesson6.Vehicle;

import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;

public class VehicleRotateUpAction extends KeyInputAction {
    // temporary variables to handle rotation
    private static final Matrix3f incr = new Matrix3f();
    private static final Matrix3f tempMa = new Matrix3f();
    private static final Matrix3f tempMb = new Matrix3f();

    // the node to manipulate
    private Vehicle vehicle;

    private Vector3f upAxis = new Vector3f(1, 0, 0);

    /**
    * create a new action with the vehicle to turn.
    *
    * @param vehicle
    *            the vehicle to turn
    */
    public VehicleRotateUpAction(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    /**
    * turn the vehicle by its turning speed. If the vehicle is traveling
    * backwards, swap direction.
    */
    public void performAction(InputActionEvent evt) {
    upAxis = vehicle.getLocalRotation().getRotationColumn(0);
        if (vehicle.getVelocity() < 0) {
            incr.fromAxisAngle(upAxis, vehicle.getTurnSpeed() * evt.getTime());
        } else {
            incr.fromAxisAngle(upAxis, -vehicle.getTurnSpeed() * evt.getTime());
        }
        vehicle.getLocalRotation().fromRotationMatrix(
                incr.mult(vehicle.getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        vehicle.getLocalRotation().normalize();
    }
}


Similar the other two missing .

I am trying to get a paper where i can read something about steering techniques cause i am no pilot and i would like to get some feeling on where i want to steer in a dogfight related on the opponents location and heading.

aircarrier.dev.java.net has steering code for target seeking, distance maintenance, target prediction (not technically steering but works with target seeking), predictive collision avoidance of moving targets, and avoidance of terrain (height maps). There is some general code for tracks (to predict collisions of spheres moving with given velocities), some little utility methods for converting to a yaw-pitch-roll-throttle steering model, and a kind of steering framework to put the steering behaviours together. Everything apart from the last bit is pretty much complete, but there are some more behaviours to add - avoidance of static objects (you can use the general dynamic avoidance for this, but it’s not as efficient), fleeing, and hopefully some fancier stuff like hiding behind terrain features. I also want to extend the steering framework to support “mixers” that will mix between steering behaviours according to sensors (for example the avoidance (terrain and collision) steerers also provide a sensor output scaling from 0 meaning “nothing much in front” to 1 meaning “Chewing on mountainside”).



Aircarrier should run if you check out jme, jmephysics and aircarrier projects (all on CVS). Running net.java.dev.aircarrier.CarrierSimpleLevelManagers will give you a little playable demo where you can fly around and shoot at the enemy planes, which use AI to avoid collisions and terrain, and shoot each other.



A few people have talked about doing some steering behaviours, but I don’t think anyone has used the aircarrier stuff, let me know if you give it a go or if you find any other code. I think a general purpose steering library for jME (or just written in Java!) would be nice to have :slight_smile: