How implement 3d person tank?

I read manuals about collision and physics but don’t understand how to reach my goal. Here is code of simple scene:
[java]
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.cursors.plugins.JmeCursor;
import com.jme3.input.KeyInput;
import com.jme3.input.RawInputListener;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.event.JoyAxisEvent;
import com.jme3.input.event.JoyButtonEvent;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.input.event.TouchEvent;
import com.jme3.light.AmbientLight;
import com.jme3.light.Light;
import com.jme3.light.PointLight;
import com.jme3.material.Material;
import com.jme3.material.MaterialDef;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Quad;

/**

  • test

  • @author normenhansen
    */
    public class Main extends SimpleApplication implements ActionListener {
    private static final String ACTION_FORWARD = “Forward”;
    private static final String ACTION_BACK = “Back”;
    private static final String ACTION_LEFT = “Left”;
    private static final String ACTION_RIGHT = “Right”;
    private static final float PLAYER_MOVE_SPEED = 4f;
    private static final float PLAYER_ROTATION_SPEED = FastMath.HALF_PI;

    private BulletAppState bulletAppState;

    private Node scene;
    private Entity player;
    private RigidBodyControl playerControl;
    private boolean left = false;
    private boolean right = false;
    private boolean forward = false;
    private boolean back = false;

    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    }

    public Main() {
    super(new StatsAppState());
    }

    @Override
    public void simpleInitApp() {

     bulletAppState = new BulletAppState();
     stateManager.attach(bulletAppState);
     
     //scene = (Node)assetManager.loadModel("Scenes/scene.mesh.j3o");
     scene = initScene();
     rootNode.attachChild(scene);
     CollisionShape sceneShape = CollisionShapeFactory.createMeshShape(scene);
     RigidBodyControl sceneControl = new RigidBodyControl(sceneShape, 0);
     sceneControl.setKinematic(true);
     scene.addControl(sceneControl);
     bulletAppState.getPhysicsSpace().add(sceneControl);
     
     //Spatial playerMesh = assetManager.loadModel("Textures/units/player/player.obj");
     Spatial playerMesh = new Geometry("player", new Box(0.5f, 0.5f, 1f));
     Material playerMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     playerMaterial.setColor("Color", ColorRGBA.Blue);
     playerMesh.setMaterial(playerMaterial);
     player = new Entity("Player", playerMesh);
     player.setSpeed(PLAYER_MOVE_SPEED);
     player.setRotationSpeed(PLAYER_ROTATION_SPEED);
     player.setLocalTranslation(0, 0.1f, 0);
     scene.attachChild(player);
     CollisionShape playerShape = CollisionShapeFactory.createBoxShape(player);
     playerControl = new RigidBodyControl(playerShape, 1f);
     player.addControl(playerControl);
     bulletAppState.getPhysicsSpace().add(playerControl);
             
     
     Light light = new AmbientLight();
     rootNode.addLight(light);
     
     PointLight pointLight = new PointLight();
     pointLight.setPosition(new Vector3f(15, 10, 15));
     rootNode.addLight(pointLight);
     
     cam.setLocation(new Vector3f(0, 15, 15));
     cam.lookAt(player.getLocalTranslation(), Vector3f.UNIT_Y);
     setupKeys();
    

    }

    private Node initScene() {
    Geometry floor = new Geometry(“floor”, new Box(10, 0.1f, 10f));
    Material floorMaterial = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
    floorMaterial.setColor(“Color”, ColorRGBA.Gray);
    floor.setMaterial(floorMaterial);

     Geometry box1 = new Geometry("box1", new Box(1, 1, 1));
     box1.setLocalTranslation(2, 0.5f, 1);        
     Geometry box2 = new Geometry("box2", new Box(1, 1, 1));
     box2.setLocalTranslation(-2, 0.5f, 1);
     Material boxMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     boxMaterial.setColor("Color", ColorRGBA.Brown);
     box1.setMaterial(boxMaterial);
     box2.setMaterial(boxMaterial);
     
     Node scene = new Node("scene");
     scene.attachChild(floor);
     scene.attachChild(box1);
     scene.attachChild(box2);
     
     return scene;
    

    }

    private void setupKeys() {
    inputManager.addMapping(ACTION_FORWARD, new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping(ACTION_BACK, new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping(ACTION_LEFT, new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping(ACTION_RIGHT, new KeyTrigger(KeyInput.KEY_D));

     inputManager.addListener(this, ACTION_FORWARD);
     inputManager.addListener(this, ACTION_BACK);
     inputManager.addListener(this, ACTION_LEFT);
     inputManager.addListener(this, ACTION_RIGHT);
    
     mouseInput.setCursorVisible(true);
    

    }

    @Override
    public void simpleUpdate(float tpf) {
    if (left) {
    Quaternion rotation = new Quaternion().fromAngleAxis(
    player.getRotationSpeed() * tpf, Vector3f.UNIT_Y);
    player.setDirection(rotation.mult(player.getDirection()));
    player.rotate(rotation);
    } else if (right) {
    Quaternion rotation = new Quaternion().fromAngleAxis(
    -player.getRotationSpeed() * tpf, Vector3f.UNIT_Y);
    player.setDirection(rotation.mult(player.getDirection()));
    player.rotate(rotation);
    }

    player.setMoveDirection(Vector3f.ZERO);
    if (forward) {
        player.setMoveDirection(player.getDirection().mult(player.getSpeed()));
    } else if (back) {
        player.setMoveDirection(player.getDirection().negate().multLocal(player.getSpeed()));
    }
    
    playerControl.setLinearVelocity(player.getMoveDirection());
    //player.move(player.getMoveDirection().mult(tpf));
    
    cam.lookAt(player.getLocalTranslation(), Vector3f.UNIT_Y);
    

    }

    @Override
    public void simpleRender(RenderManager rm) {
    //TODO: add render code
    }

    @Override
    public void onAction(String name, boolean isPressed, float tpf) {
    if (ACTION_FORWARD.equals(name)) {
    if (isPressed) {
    forward = true;
    } else {
    forward = false;
    }
    } else if (ACTION_BACK.equals(name)) {
    if (isPressed) {
    back = true;
    } else {
    back = false;
    }
    } else if (ACTION_LEFT.equals(name)) {
    if (isPressed) {
    left = true;
    } else {
    left = false;
    }
    } else if (ACTION_RIGHT.equals(name)) {
    if (isPressed) {
    right = true;
    } else {
    right = false;
    }
    }
    }

}

[/java]

Say we have something like a tank (can rotate and move). Move by W&S and rotate by A&D.

  1. Why my character is not rotated? If I remove RigidBodyControl from it I can rotate model by A&D.
  2. Why it sometimes rotates when I move it forward or backward?
  3. How make next behaviour - when characters hit with obstacle it just stops and not begins rotation?
    I tried implement collision detection via Spatial.collideWith but I found that in JME3 collisions between spaitals are not supported.

Entity is simple subclass of Node.
[java]
public class Entity extends Node {

private static final String SPATIAL_GROUP_MODEL = "model";

private Vector3f direction = Vector3f.UNIT_Z.negate();

private Vector3f moveDirection = Vector3f.ZERO;

private float speed;

private float rotationSpeed;

private EntityAction moveAction;

public Entity(String name, Spatial model) {
    setName(name);
    model.setName(SPATIAL_GROUP_MODEL);
    attachChild(model);
}

[/java]