SimpleApplication question

Hi, jme/java newbie here working on a little project of my own…this project looks really powerful once you learn the ropes of it all.



I’m creating a simple simulation that will control a six-wheeled vehicle across a user-generated map. I’ve read through/played with the tutorials to get something that allows me to control my vehicle on the terrain, but now I’m looking to separate out each of the methods into separate classes. Something to the effect of:



class that runs simulation (contains main method)

class that builds map

class that builds vehicle/robot

class that builds camera/controls



I’m only trying these one at a time, for now I’m just trying to make a separate class that will build my vehicle and return it back to the main method. I’m getting a NullPointerException when trying to generate the materials used my vehicle (Code attached)…



[java]package Robo_Sim;



import jme3tools.converters.ImageToAwt;



import com.jme3.app.SimpleApplication;

import com.jme3.app.SimpleBulletApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.PhysicsSpace;

import com.jme3.bullet.collision.shapes.BoxCollisionShape;

import com.jme3.bullet.collision.shapes.CompoundCollisionShape;

import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;

import com.jme3.bullet.control.PhysicsControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.bullet.control.VehicleControl;

import com.jme3.bullet.nodes.PhysicsNode;

import com.jme3.input.ChaseCamera;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Matrix3f;

import com.jme3.math.Vector3f;

import com.jme3.renderer.Camera;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Cylinder;

import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.terrain.heightmap.AbstractHeightMap;

import com.jme3.terrain.heightmap.HillHeightMap;

import com.jme3.terrain.heightmap.ImageBasedHeightMap;

import com.jme3.terrain.geomipmap.TerrainQuad;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import java.util.ArrayList;

import java.util.List;



public class RunSim extends SimpleApplication implements ActionListener{



private TerrainQuad terrain;



private BulletAppState bulletAppState;

Spatial camSpatial;

//Spatial car;

public VehicleControl vehicle;

private final float accelerationForce = 1000.0f;

private final float brakeForce = 100.0f;

private float steeringValue1 = 0;

private float steeringValue2 = 0;

private float accelerationValue = 0;

private Vector3f jumpForce = new Vector3f(0, 3000, 0);





public static void main(String[] args) {

RunSim app = new RunSim();

app.setShowSettings(false);

app.start();

}



@Override

public void simpleInitApp() {



setupKeys();



/
Setup physics /

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);

bulletAppState.getPhysicsSpace().enableDebug(assetManager);

CreateRobot robot = new CreateRobot();

vehicle = robot.buildPlayer(bulletAppState,camSpatial);

buildMap();

createChaseCamera();

}



@Override

public void simpleUpdate(float tpf) {

//cam.lookAt(vehicle.getPhysicsLocation(), Vector3f.UNIT_Y);

}



private void createChaseCamera() {

flyCam.setEnabled(false);

ChaseCamera chaseCam = new ChaseCamera(cam,camSpatial,inputManager);

chaseCam.setSmoothMotion(true);

}



public void buildMap() {



Material terrain_mat;

PhysicsNode landscape;



/
1. Create terrain material and load four textures into it. /

terrain_mat = new Material(assetManager, “Common/MatDefs/Terrain/Terrain.j3md”);



/
1.1) Add ALPHA map (for red-blue-green coded splat textures) /

terrain_mat.setTexture(“m_Alpha”, assetManager.loadTexture(“Textures/Terrain/splat/alphamap.png”));



/
1.2) Add GRASS texture into the red layer (m_Tex1). /

Texture grass = assetManager.loadTexture(“Textures/Terrain/splat/grass.jpg”);

grass.setWrap(WrapMode.Repeat);

terrain_mat.setTexture(“m_Tex1”, grass);

terrain_mat.setFloat(“m_Tex1Scale”, 64f);



/
* 1.3) Add DIRT texture into the green layer (m_Tex2) /

Texture dirt = assetManager.loadTexture(“Textures/Terrain/splat/dirt.jpg”);

dirt.setWrap(WrapMode.Repeat);

terrain_mat.setTexture(“m_Tex2”, dirt);

terrain_mat.setFloat(“m_Tex2Scale”, 32f);



/
* 1.4) Add ROAD texture into the blue layer (m_Tex3) /

Texture rock = assetManager.loadTexture(“Textures/Terrain/splat/road.jpg”);

rock.setWrap(WrapMode.Repeat);

terrain_mat.setTexture(“m_Tex3”, rock);

terrain_mat.setFloat(“m_Tex3Scale”, 128f);



/
* 2. Create the height map /

AbstractHeightMap heightmap = null;

// EITHER pre-load heightmap from png image (Use MATLAB?)…



//Texture heightMapImage = assetManager.loadTexture(“Textures/Terrain/splat/mountains512.png”);

//heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, true, 0));



// OR used automatically generated heightmaps…

try { heightmap = new HillHeightMap(512,100,50,100,(byte) 3);

} catch (Exception ex) { ex.printStackTrace(); }

heightmap.load();



/
* 3. We have prepared material and heightmap. Now we create the actual terrain:

  • 3.1) We create a TerrainQuad and name it "my terrain".
  • 3.2) A good value for terrain tiles is 64x64 – so we supply 64+1=65.
  • 3.3) We prepared a heightmap of size 512x512 – so we supply 512+1=513.
  • 3.4) At last, we supply the prepared heightmap itself.*/

    terrain = new TerrainQuad(“my terrain”, 65, 513, heightmap.getHeightMap());



    HeightfieldCollisionShape sceneShape = new HeightfieldCollisionShape(heightmap.getHeightMap());

    landscape = new PhysicsNode(terrain, sceneShape, 0);

    /** 4. The LOD (level of detail) depends on where the camera is: /

    List<Camera> cameras = new ArrayList<Camera>();

    cameras.add(getCamera());

    TerrainLodControl control = new TerrainLodControl(terrain, cameras);

    terrain.addControl(control);



    /
    * 5. We give the terrain its material, position & scale it, and attach it. /

    terrain.setMaterial(terrain_mat);

    landscape.setLocalTranslation(0, -50, 0);

    rootNode.attachChild(landscape);

    bulletAppState.getPhysicsSpace().add(landscape);

    }



    /
    * public VehicleControl buildPlayer() {

    Material mat1 = new Material(getAssetManager(), “Common/MatDefs/Misc/WireColor.j3md”);

    Material mat2 = new Material(getAssetManager(), “Common/MatDefs/Misc/WireColor.j3md”);

    mat1.setColor(“Color”, ColorRGBA.Cyan);

    mat2.setColor(“Color”, ColorRGBA.Orange);



    //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0

    //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0

    CompoundCollisionShape compoundShape = new CompoundCollisionShape();

    BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.2f, 2.0f));

    compoundShape.addChildShape(box, new Vector3f(0, 1, 0));



    Box myBox = new Box(Vector3f.ZERO, 0, 0, 0);

    Spatial car = new Geometry(“my Box”, myBox);

    car.setMaterial(mat1);

    //create vehicle node

    Node vehicleNode=new Node(“vehicleNode”);

    vehicle = new VehicleControl(compoundShape, 400);

    vehicleNode.addControl(vehicle);

    vehicleNode.attachChild(car);

    camSpatial = car.center();



    //setting suspension values for wheels, this can be a bit tricky

    //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en

    float stiffness = 30f;//200=f1 car

    float compValue = .3f; //(should be lower than damp)

    float dampValue = .4f;

    vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));

    vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));

    vehicle.setSuspensionStiffness(stiffness);

    vehicle.setMaxSuspensionForce(10000.0f);





    //Create four wheels and add them at their locations

    Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0

    Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0



    // Positive: x -> robot left, y -> robot down, z -> robot front



    float radius = 0.5f;

    float restLength = 0.3f;

    float yOff = 0.5f;

    float xOff = 1.25f;

    float zOff = 1.5f;



    Cylinder wheelMesh = new Cylinder(16, 16, radius, radius, true);



    Node node1 = new Node(“wheel 1 node”);

    Geometry wheels1 = new Geometry(“wheel 1”, wheelMesh);

    node1.attachChild(wheels1);

    wheels1.rotate(0, FastMath.HALF_PI, 0);

    wheels1.setMaterial(mat1);

    vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    Node node2 = new Node(“wheel 2 node”);

    Geometry wheels2 = new Geometry(“wheel 2”, wheelMesh);

    node2.attachChild(wheels2);

    wheels2.rotate(0, FastMath.HALF_PI, 0);

    wheels2.setMaterial(mat1);

    vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    Node node3 = new Node(“wheel 3 node”);

    Geometry wheels3 = new Geometry(“wheel 3”, wheelMesh);

    node3.attachChild(wheels3);

    wheels3.rotate(0, FastMath.HALF_PI, 0);

    wheels3.setMaterial(mat1);

    vehicle.addWheel(node3, new Vector3f(-xOff, yOff, 0f),

    wheelDirection, wheelAxle, restLength, radius, false);



    Node node4 = new Node(“wheel 4 node”);

    Geometry wheels4 = new Geometry(“wheel 4”, wheelMesh);

    node4.attachChild(wheels4);

    wheels4.rotate(0, FastMath.HALF_PI, 0);

    wheels4.setMaterial(mat2);

    vehicle.addWheel(node4, new Vector3f(xOff, yOff, 0f),

    wheelDirection, wheelAxle, restLength, radius, false);



    Node node5 = new Node(“wheel 5 node”);

    Geometry wheels5 = new Geometry(“wheel 5”, wheelMesh);

    node5.attachChild(wheels5);

    wheels5.rotate(0, FastMath.HALF_PI, 0);

    wheels5.setMaterial(mat1);

    vehicle.addWheel(node5, new Vector3f(-xOff, yOff, -zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    Node node6 = new Node(“wheel 6 node”);

    Geometry wheels6 = new Geometry(“wheel 6”, wheelMesh);

    node6.attachChild(wheels6);

    wheels6.rotate(0, FastMath.HALF_PI, 0);

    wheels6.setMaterial(mat1);

    vehicle.addWheel(node6, new Vector3f(xOff, yOff, -zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    vehicleNode.attachChild(node1);

    vehicleNode.attachChild(node2);

    vehicleNode.attachChild(node3);

    vehicleNode.attachChild(node4);

    vehicleNode.attachChild(node5);

    vehicleNode.attachChild(node6);



    rootNode.attachChild(vehicleNode);

    bulletAppState.getPhysicsSpace().add(vehicle);



    return vehicle;

    }

    */





    private void setupKeys() {

    inputManager.addMapping(“Lefts”, new KeyTrigger(KeyInput.KEY_H));

    inputManager.addMapping(“Rights”, new KeyTrigger(KeyInput.KEY_K));

    inputManager.addMapping(“Ups”, new KeyTrigger(KeyInput.KEY_U));

    inputManager.addMapping(“Downs”, new KeyTrigger(KeyInput.KEY_J));

    inputManager.addMapping(“Brakes”, new KeyTrigger(KeyInput.KEY_Y));

    inputManager.addMapping(“Space”, new KeyTrigger(KeyInput.KEY_SPACE));

    inputManager.addMapping(“Reset”, new KeyTrigger(KeyInput.KEY_RETURN));

    inputManager.addListener(this, “Lefts”);

    inputManager.addListener(this, “Rights”);

    inputManager.addListener(this, “Ups”);

    inputManager.addListener(this, “Downs”);

    inputManager.addListener(this, “Brakes”);

    inputManager.addListener(this, “Space”);

    inputManager.addListener(this, “Reset”);

    }



    public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals(“Lefts”)) {

    if (value) {

    steeringValue1 += .5f;

    steeringValue2 += -.5f;

    } else {

    steeringValue1 += -.5f;

    steeringValue2 += .5f;

    }

    vehicle.steer(0,steeringValue1);

    vehicle.steer(1,steeringValue1);

    vehicle.steer(4,steeringValue2);

    vehicle.steer(5,steeringValue2);

    } else if (binding.equals(“Rights”)) {

    if (value) {

    steeringValue1 += -.5f;

    steeringValue2 += .5f;

    } else {

    steeringValue1 += +.5f;

    steeringValue2 += -.5f;

    }

    vehicle.steer(0,steeringValue1);

    vehicle.steer(1,steeringValue1);

    vehicle.steer(4,steeringValue2);

    vehicle.steer(5,steeringValue2);

    } else if (binding.equals(“Ups”)) {

    if (value) {

    accelerationValue += accelerationForce;

    } else {

    accelerationValue = 0;

    }

    vehicle.accelerate(accelerationValue);

    } else if (binding.equals(“Downs”)) {

    if (value) {

    accelerationValue = -accelerationForce;

    } else {

    accelerationValue = 0;

    }

    vehicle.accelerate(accelerationValue);

    } else if (binding.equals(“Brakes”)) {

    if (value) {

    vehicle.brake(brakeForce);

    } else {

    vehicle.brake(0f);

    }

    } else if (binding.equals(“Space”)) {

    if (value) {

    vehicle.applyImpulse(jumpForce, Vector3f.ZERO);

    }

    } else if (binding.equals(“Reset”)) {

    if (value) {

    System.out.println(“Reset”);

    vehicle.setPhysicsLocation(Vector3f.ZERO);

    vehicle.setPhysicsRotation(new Matrix3f());

    vehicle.setLinearVelocity(Vector3f.ZERO);

    vehicle.setAngularVelocity(Vector3f.ZERO);

    vehicle.resetSuspension();

    } else {

    }

    }

    }



    public void prePhysicsTick(PhysicsSpace arg0, float arg1) {

    // TODO Auto-generated method stub



    }

    }



    [/java]



    Here’s the separate class I tried creating…

    [java]package Robo_Sim;



    import com.jme3.bullet.BulletAppState;

    import com.jme3.app.SimpleApplication;

    import com.jme3.bullet.collision.shapes.BoxCollisionShape;

    import com.jme3.bullet.collision.shapes.CompoundCollisionShape;

    import com.jme3.bullet.control.VehicleControl;

    import com.jme3.material.Material;

    import com.jme3.math.ColorRGBA;

    import com.jme3.math.FastMath;

    import com.jme3.math.Vector3f;

    import com.jme3.scene.Geometry;

    import com.jme3.scene.Node;

    import com.jme3.scene.Spatial;

    import com.jme3.scene.shape.Box;

    import com.jme3.scene.shape.Cylinder;



    public class CreateRobot extends SimpleApplication{



    Spatial car;

    VehicleControl vehicle;



    public VehicleControl buildPlayer(BulletAppState bulletAppState, Spatial camSpatial) {



    Material mat1 = new Material(getAssetManager(), “Common/MatDefs/Misc/WireColor.j3md”);

    Material mat2 = new Material(getAssetManager(), “Common/MatDefs/Misc/WireColor.j3md”);

    mat1.setColor(“Color”, ColorRGBA.Cyan);

    mat2.setColor(“Color”, ColorRGBA.Orange);



    //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0

    //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0

    CompoundCollisionShape compoundShape = new CompoundCollisionShape();

    BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.2f, 2.0f));

    compoundShape.addChildShape(box, new Vector3f(0, 1, 0));



    Box myBox = new Box(Vector3f.ZERO, 0, 0, 0);

    Spatial car = new Geometry(“my Box”, myBox);

    car.setMaterial(mat1);

    //create vehicle node

    Node vehicleNode=new Node(“vehicleNode”);

    vehicle = new VehicleControl(compoundShape, 400);

    vehicleNode.addControl(vehicle);

    vehicleNode.attachChild(car);

    camSpatial = car.center();



    //setting suspension values for wheels, this can be a bit tricky

    //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en

    float stiffness = 30f;//200=f1 car

    float compValue = .3f; //(should be lower than damp)

    float dampValue = .4f;

    vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));

    vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));

    vehicle.setSuspensionStiffness(stiffness);

    vehicle.setMaxSuspensionForce(10000.0f);





    //Create four wheels and add them at their locations

    Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0

    Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0



    /
    Positive: x -> robot left

    y -> robot down

    z -> robot front */

    float radius = 0.5f;

    float restLength = 0.3f;

    float yOff = 0.5f;

    float xOff = 1.25f;

    float zOff = 1.5f;



    Cylinder wheelMesh = new Cylinder(16, 16, radius, radius, true);



    Node node1 = new Node(“wheel 1 node”);

    Geometry wheels1 = new Geometry(“wheel 1”, wheelMesh);

    node1.attachChild(wheels1);

    wheels1.rotate(0, FastMath.HALF_PI, 0);

    wheels1.setMaterial(mat1);

    vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    Node node2 = new Node(“wheel 2 node”);

    Geometry wheels2 = new Geometry(“wheel 2”, wheelMesh);

    node2.attachChild(wheels2);

    wheels2.rotate(0, FastMath.HALF_PI, 0);

    wheels2.setMaterial(mat1);

    vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    Node node3 = new Node(“wheel 3 node”);

    Geometry wheels3 = new Geometry(“wheel 3”, wheelMesh);

    node3.attachChild(wheels3);

    wheels3.rotate(0, FastMath.HALF_PI, 0);

    wheels3.setMaterial(mat1);

    vehicle.addWheel(node3, new Vector3f(-xOff, yOff, 0f),

    wheelDirection, wheelAxle, restLength, radius, false);



    Node node4 = new Node(“wheel 4 node”);

    Geometry wheels4 = new Geometry(“wheel 4”, wheelMesh);

    node4.attachChild(wheels4);

    wheels4.rotate(0, FastMath.HALF_PI, 0);

    wheels4.setMaterial(mat2);

    vehicle.addWheel(node4, new Vector3f(xOff, yOff, 0f),

    wheelDirection, wheelAxle, restLength, radius, false);



    Node node5 = new Node(“wheel 5 node”);

    Geometry wheels5 = new Geometry(“wheel 5”, wheelMesh);

    node5.attachChild(wheels5);

    wheels5.rotate(0, FastMath.HALF_PI, 0);

    wheels5.setMaterial(mat1);

    vehicle.addWheel(node5, new Vector3f(-xOff, yOff, -zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    Node node6 = new Node(“wheel 6 node”);

    Geometry wheels6 = new Geometry(“wheel 6”, wheelMesh);

    node6.attachChild(wheels6);

    wheels6.rotate(0, FastMath.HALF_PI, 0);

    wheels6.setMaterial(mat1);

    vehicle.addWheel(node6, new Vector3f(xOff, yOff, -zOff),

    wheelDirection, wheelAxle, restLength, radius, true);



    vehicleNode.attachChild(node1);

    vehicleNode.attachChild(node2);

    vehicleNode.attachChild(node3);

    vehicleNode.attachChild(node4);

    vehicleNode.attachChild(node5);

    vehicleNode.attachChild(node6);



    rootNode.attachChild(vehicleNode);

    bulletAppState.getPhysicsSpace().add(vehicle);



    return vehicle;

    }



    @Override

    public void simpleInitApp() {

    // TODO Auto-generated method stub



    }



    }



    [/java]



    Here’s the error that pops up in eclipse:



    SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

    java.lang.NullPointerException

    at com.jme3.material.Material.(Material.java:167)

    at Robo_Sim.CreateRobot.buildPlayer(CreateRobot.java:25)

    at Robo_Sim.RunSim.simpleInitApp(RunSim.java:73)

    at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:218)

    at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:138)

    at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:206)

    at java.lang.Thread.run(Thread.java:662)






    I apologize for the long post AND the n00bish question…Just trying to clean some of my stuff up here. I’m not completely adept at debugging with eclipse but something obviously isn’t loading correctly here for me :frowning:



    If there some documentation available that would explain in further detail the best recommendations for splitting this up into smaller classes for something like this, where should I start looking?



    Thanks in advance! Seriously, much appreciated. :slight_smile:

So apparently I’m bad at copying code into a forum, the methods simpleInitApp(), simpleUpdate(), buildMap(), and createChaseCam() are NOT meant to be commented out :frowning:

in simpleInitApp()

[java]

CreateRobot robot = new CreateRobot(getAssetManager());

[/java]



in CreateRobot class

[java]

private AssetManager assetManager=null;



public CreateRobot (AssetManager assetManager) {

this.assetManager=assetManager;

}



protected AssetManager getAssetManager() {

return this.assetManager;

}

[/java]



hope that helps, also dont extend SimpleApplication with Robot class, imo

→ you need to pass the rootNode from RunSim to CreateRobot, add it in a constructor



and whats with camSpatial = car.center()?

Ok, added your stuff in and have a few other quick problems popping up…thanks for your help with this!



I’ll copy in smaller snippets of the code this time :smiley:



Ecplipse isn’t throwing up errors with anything in my main sim file, now it just states that rootNode cannot be resolved from my CreateRobot class. I’m guessing this is because I I’ve removed the “extend SimpleApplication” from CreateRobot (I’d rather not use it if I don’t have to) Do I need to attach the vehicle in the main file once it’s been returned from the CreateRobot class?



Here’s the class changes I added in:



[java]public class CreateRobot {



private AssetManager assetManager = null;

public CreateRobot (AssetManager assetManager) {

this.assetManager=assetManager;

}



protected AssetManager getAssetManager() {

return this.assetManager;

}



Spatial car;

VehicleControl vehicle;



public VehicleControl buildPlayer(BulletAppState bulletAppState, Spatial camSpatial) {



Material mat1 = new Material(getAssetManager(), “Common/MatDefs/Misc/WireColor.j3md”);

Material mat2 = new Material(getAssetManager(), “Common/MatDefs/Misc/WireColor.j3md”);

.

.

.

.



rootNode.attachChild(vehicleNode);

bulletAppState.getPhysicsSpace().add(vehicle);



return vehicle;



[/java]



BTW…car.center() was used so that I can get a camera that follows the vehicle around as it drives…I read somwhere that it had to follow a spatial…

You need to pass the rootNode from your RunSim class to CreateRobot clas



[java]

private Node rootNode= null;

public CreateRobot (AssetManager assetManager, Node rootNode) {

this.assetManager=assetManager;

this.rootNode=rootNode;

}

[/java]

Yep, figured that out myself last night, although I just fed my rootNode directly into the CreateRobot() method…



Thanks again!