Character animation, character control, camera control

I ask forgiveness for spelling, use a translator

questions:
_ Control character

  • The problem with running
    I want to make it so that the character would be running at the promptness of shift keys W.
    tell me how to do it.

_ Character animation

  • The problem is that when you go ahead and press the jump animation is changed to “JumpStart”, but after returning to the “Idle” though the character continues to move forward.

and I would want that after the jump animation to object to the “Walk”

pray tell how to fix it, or what a way to animate the character better.

_ Camera control

  • I wanted to do that would be when you press the “A” and “D” character model turned in the direction of where it’s going

  • Still want that to after pressing of keys that can rotate the camera around the character

as he wrote, there was still one question:
how to implement the interaction with other subjects?

for example: I go up to the door and when you click on a button which opens the door.

my code:
Main.java
[java]
package li.pack;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;

public class Main extends SimpleApplication implements ActionListener{

private AnimChannel channelAnim;
private AnimControl controlAnim;
private BulletAppState bulletAppState;
private BetterCharacterControl physicsCharacter;
private Node characterNode;
private Node model;
private CameraNode camNode;
boolean rotate = false;
private Vector3f walkDirection = new Vector3f(0,0,0);
private Vector3f viewDirection = new Vector3f(0,0,0);
boolean leftStrafe = false, rightStrafe = false,
forward = false, backward = false,
run = false, duck = false;

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

}

private void setupKeys() {
    inputManager.addMapping("Strafe Left", 
            new KeyTrigger(KeyInput.KEY_A), 
            new KeyTrigger(KeyInput.KEY_LEFT));
    inputManager.addMapping("Strafe Right", 
            new KeyTrigger(KeyInput.KEY_D),
            new KeyTrigger(KeyInput.KEY_RIGHT));
    inputManager.addMapping("Walk Forward", 
            new KeyTrigger(KeyInput.KEY_W), 
            new KeyTrigger(KeyInput.KEY_UP));
    inputManager.addMapping("Walk Backward", 
            new KeyTrigger(KeyInput.KEY_S),
            new KeyTrigger(KeyInput.KEY_DOWN));
    inputManager.addMapping("Jump", 
            new KeyTrigger(KeyInput.KEY_SPACE)); 
    inputManager.addMapping("Duck", 
            new KeyTrigger(KeyInput.KEY_LCONTROL));
    inputManager.addMapping("Run",
            new KeyTrigger(KeyInput.KEY_LSHIFT));
    inputManager.addListener(this, "Strafe Left", "Strafe Right");
    inputManager.addListener(this, "Walk Forward", "Walk Backward");
    inputManager.addListener(this, "Jump");
    inputManager.addListener(this, "Run", "Duck");
}

@Override
public void simpleInitApp() {
// добавляем физику
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.setDebugEnabled(true);

// добавляем сцену
Scene.CreateScene(rootNode, assetManager, bulletAppState.getPhysicsSpace());

setupKeys();

    // создаем node для модели персонажа
    characterNode = new Node("character node");
    characterNode.setLocalTranslation(new Vector3f(4, 5, 2));

    // Add a character control to the node so we can add other things and
    // control the model rotation
    physicsCharacter = new BetterCharacterControl(0.5f, 1.5f, 4f);
    characterNode.addControl(physicsCharacter);
    getPhysicsSpace().add(physicsCharacter);

    // загружаем модель и присоеденяем к Node чара
    model = (Node) assetManager.loadModel("Models/Jaime/Jaime.j3o");
    model.setLocalScale(1f);
    characterNode.attachChild(model);

    // добавляем Node чара на карту
    rootNode.attachChild(characterNode);

//добавляем анимацию
   controlAnim = model.getControl(AnimControl.class);
   channelAnim = controlAnim.createChannel();
   channelAnim.setAnim("Idle");

// set forward camera node that follows the character
camNode = new CameraNode("CamNode", cam);
camNode.setControlDir(ControlDirection.SpatialToCamera);
camNode.setLocalTranslation(new Vector3f(0, 3, -8));
camNode.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y);

characterNode.attachChild(camNode);

// при true можно вращать
flyCam.setEnabled(true);
}

@Override
public void simpleUpdate(float tpf) {

    Vector3f modelForwardDir = characterNode.getWorldRotation().mult(Vector3f.UNIT_Z);
    Vector3f modelLeftDir = characterNode.getWorldRotation().mult(Vector3f.UNIT_X);
    
    Vector3f camDir = cam.getDirection().mult(0.2f);
    Vector3f camLeft = cam.getLeft().clone().mult(0.2f);
    camDir.y = 0;
    camLeft.y = 0;
    viewDirection.set(camDir);
    walkDirection.set(0, 0, 0);
    if (leftStrafe) {
        walkDirection.addLocal(modelLeftDir.mult(3));
    } 
    if (rightStrafe) {
        walkDirection.addLocal(modelLeftDir.mult(3).negate());
    }
    if (forward) {
        walkDirection.addLocal(modelForwardDir.mult(3));
    }  
    if (backward) {
        walkDirection.addLocal(modelForwardDir.mult(2).negate());
    } 
    if (run) {
        walkDirection.addLocal(modelForwardDir.mult(6));
    }           
    
    physicsCharacter.setWalkDirection(walkDirection);
    physicsCharacter.setViewDirection(viewDirection);
}

public void onAction(String binding, boolean value, float tpf) {
    
        if (binding.equals("Strafe Left")) {
        if (value) {
                leftStrafe = true;
        } else {
                leftStrafe = false;

onAnimChange(controlAnim, channelAnim, binding);
}
} else if (binding.equals(“Strafe Right”)) {
if (value) {
rightStrafe = true;
} else {
rightStrafe = false;
onAnimChange(controlAnim, channelAnim, binding);
}
} else if (binding.equals(“Walk Forward”)) {
if (value) {
forward = true;
channelAnim.setAnim(“Walk”);
} else {
forward = false;
onAnimChange(controlAnim, channelAnim, binding);
}
} else if (binding.equals(“Walk Backward”)) {
if (value) {
backward = true;
channelAnim.setAnim(“Walk”);
} else {
backward = false;
onAnimChange(controlAnim, channelAnim, binding);
}
} else if (binding.equals(“Jump”) && value) {
physicsCharacter.jump();
channelAnim.setAnim(“JumpStart”);
} else {
onAnimChange(controlAnim, channelAnim, binding);
} if (binding.equals(“Duck”)) {
if (value) {
physicsCharacter.setDucked(true);
} else {
physicsCharacter.setDucked(false);
onAnimChange(controlAnim, channelAnim, binding);
}
} else if (binding.equals(“Run”)) {
if (value) {
run = true;
channelAnim.setAnim(“Run”);
} else {
run = false;
onAnimChange(controlAnim, channelAnim, binding);
}

    }
}
public void onAnimChange(AnimControl controlAnim, AnimChannel channelAnim, String animName) {
    if (!channelAnim.getAnimationName().equals("Idle")){
                channelAnim.setAnim("Idle");}
}

private PhysicsSpace getPhysicsSpace() {
return bulletAppState.getPhysicsSpace();
}

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

}
[/java]

Scene.java
[java]

package li.pack;

import com.jme3.asset.AssetManager;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;

/**
*

  • @author Markov_aa
    */
    public class Scene {

    public static void CreateScene(Node rootNode, AssetManager assetManager, PhysicsSpace space) {

     //добавляем освещение
    

    /** A white ambient light source. */
    AmbientLight ambient = new AmbientLight();
    ambient.setColor(ColorRGBA.White);
    rootNode.addLight(ambient);

    //загружаем и добавляем саму сцену
    Spatial Scene = assetManager.loadModel(“Scenes/Scene.j3o”);
    Scene.setLocalTranslation(0, -0.9f, 0);
    Scene.addControl(new RigidBodyControl(0));
    rootNode.attachChild(Scene);
    space.add(Scene);

     Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
     material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
     
     //movable spheres
     for (int i = 0; i < 5; i++) {
         Sphere sphere = new Sphere(16, 16, .5f);
         Geometry ballGeometry = new Geometry("Soccer ball", sphere);
         ballGeometry.setMaterial(material);
         ballGeometry.setLocalTranslation(i, 2, -3);
         //RigidBodyControl automatically uses Sphere collision shapes when attached to single geometry with sphere mesh
         ballGeometry.addControl(new RigidBodyControl(.001f));
         ballGeometry.getControl(RigidBodyControl.class).setRestitution(1);
         rootNode.attachChild(ballGeometry);
         space.add(ballGeometry);
     }
    

    }
    }
    [/java]

This is the general idea of how to have a “running” function in your code.

[java]
if (leftStrafe) {
walkDirection.addLocal(modelLeftDir));
}
if (rightStrafe) {
walkDirection.addLocal(modelLeftDir.negate());
}
if (forward) {
walkDirection.addLocal(modelForwardDir);
}
if (backward) {
walkDirection.addLocal(modelForwardDir.negate());
}

if (run) {
walkDirection.multLocal(6);
} else{
walkDIrection.multLocal(3);
}

[/java]

btw you should really look at the control and appstate specific tutorials in the tutorial section. Your game seems to be getting to a point where if you don’t start getting organized you’ll end up with a very confusing mess.

If you want to play an animation when one finishes, look at the AnimEventListener

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:beginner:hello_animation#responding_to_animation_events

learning materials have come to such a form of code.
[java]
package li.pack;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
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.Vector3f;
import com.jme3.scene.Node;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Sphere;
import com.jme3.shadow.PssmShadowRenderer;
import java.util.Random;

public class Main extends SimpleApplication implements ActionListener, AnimEventListener{

private BulletAppState bulletAppState;
private BetterCharacterControl charControl;
ChaseCamera chaseCam;
private Node model;
private Node monet;
PhysicsSpace space;
AnimChannel animationChannel;
AnimControl animationControl;
private PssmShadowRenderer pssmRenderer;
private static Random random = new Random();
float airTime = 0;
float speed = 1f;
String move;
Geometry geom1;
boolean left = false, right = false, up = false, down = false, jump = false,
run = false;
Vector3f walkDirection = new Vector3f();

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


@Override
public void simpleInitApp() {
    //физика
       bulletAppState = new BulletAppState();
       stateManager.attach(bulletAppState);
       bulletAppState.setDebugEnabled(true);
       
    //загружаем сцену
    Scene.CreateScene(rootNode, assetManager, PhysicsSpace.getPhysicsSpace());
    
    setupKeys();
    createCharacter();
    createMonet();
    createBall(PhysicsSpace.getPhysicsSpace());
    createShadow(); 
    setupAnimationController();
       }

private void createShadow(){
/** Advanced shadows for uneven surfaces */ 

pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 5);
pssmRenderer.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal());
viewPort.addProcessor(pssmRenderer);
}

private void createCharacter(){
    charControl = new BetterCharacterControl(0.5f, 1.5f, 20f);
    getPhysicsSpace().add(charControl);
    // загружаем модель
    model = (Node) assetManager.loadModel("Models/Jaime/Jaime.j3o");
    model.setLocalScale(1f);  // размер модели
    model.addControl(charControl);
    model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
    // добавляем Node чара на карту
    rootNode.attachChild(model);
    //камера
    flyCam.setEnabled(false);
    chaseCam = new ChaseCamera(cam, model, inputManager);
    }

private void setupKeys() {
    inputManager.addMapping("run", new KeyTrigger(KeyInput.KEY_LSHIFT));
    inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("CharJump", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, "run");
    inputManager.addListener(this, "CharLeft");
    inputManager.addListener(this, "CharRight");
    inputManager.addListener(this, "CharUp");
    inputManager.addListener(this, "CharDown");
    inputManager.addListener(this, "CharJump");
    }

public void onAction(String binding, boolean value, float tpf) {
    if (binding.equals("CharLeft")) {
        if (value) {
            left = true;
        } else {
            left = false;
        }
    } else if (binding.equals("CharRight")) {
        if (value) {
            right = true;
        } else {
            right = false;
        }
    } else if (binding.equals("CharUp")) {
        if (value) {
            up = true;
        } else {
            up = false;
        }
    } else if (binding.equals("CharDown")) {
        if (value) {
            down = true;
        } else {
            down = false;
        }
    } else if (binding.equals("run")) {
        if (value) {
            run = true;
        } else {
            run = false;
        }
    } else if (binding.equals("CharJump")) {
        charControl.jump();
    }
     else if (binding.equals("1")) {
        rootNode.detachChild(monet);
    }
    }

@Override
public void simpleUpdate(float tpf) {
Vector3f camDir = cam.getDirection().clone().multLocal(speed);
Vector3f camLeft = cam.getLeft().clone().multLocal(speed);
camDir.y = 0;
camLeft.y = 0;
walkDirection.set(0, 0, 0);
if (left) {
walkDirection.addLocal(camLeft);
}
if (right) {
walkDirection.addLocal(camLeft.negate());
}
if (up) {
walkDirection.addLocal(camDir);
}
if (down) {
walkDirection.addLocal(camDir.negate());
}
if (!charControl.isOnGround()) {
airTime = airTime + tpf;
} else {
airTime = 0;
}
if (run){
speed = 3f;
move = “Run”;
} else {
speed = 1f;
move = “Walk”;
}
if (walkDirection.length() == 0) {
if (!“Idle”.equals(animationChannel.getAnimationName())) {
animationChannel.setAnim(“Idle”, 1f);
}
} else {
charControl.setViewDirection(walkDirection);
if (airTime > 5.8f) {
if (!“Jumping”.equals(animationChannel.getAnimationName())) {
animationChannel.setAnim(“Jumping”);
}
} else if (!move.equals(animationChannel.getAnimationName())) {
animationChannel.setAnim(move, 0.1f);
}
}
charControl.setWalkDirection(walkDirection);
gameLogic();
}

private void setupAnimationController() {
    animationControl = model.getControl(AnimControl.class);
    animationControl.addListener(this);
    animationChannel = animationControl.createChannel();
     }

public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
}

public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
}

private PhysicsSpace getPhysicsSpace() {
return PhysicsSpace.getPhysicsSpace();
}

private void gameLogic(){
    //еще не разобрался что к чему
}        

        
private void createMonet() {
    //movable monet
    for (int i = 0; i < 5; i++) {
        monet = (Node) assetManager.loadModel("Models/moneta/Moneda.j3o");
        monet.scale(0.25f);
      //monet.setLocalTranslation(Math.abs(random.nextInt(30)), 1, Math.abs(random.nextInt(50)));
        monet.setLocalTranslation(i, 0, i);
        monet.setShadowMode(RenderQueue.ShadowMode.Cast);
        rootNode.attachChild(monet);
    }
}

private void createBall(PhysicsSpace space) {
    //материал и текстура для сфер   
    Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
//movable spheres
    for (int i = 0; i < 5; i++) {
        Sphere sphere = new Sphere(16, 16, .5f);
        Geometry ballGeometry = new Geometry("Soccer ball", sphere);
        ballGeometry.setMaterial(material);
        ballGeometry.setLocalTranslation(i, 2, -3);
        //RigidBodyControl automatically uses Sphere collision shapes when attached to single geometry with sphere mesh
        ballGeometry.addControl(new RigidBodyControl(.001f));
        ballGeometry.getControl(RigidBodyControl.class).setRestitution(1);
        ballGeometry.setShadowMode(RenderQueue.ShadowMode.Cast);
        rootNode.attachChild(ballGeometry);
        space.add(ballGeometry);
    }
}

}
[/java]

it is impossible to deal with
1 - animation jump (JumpStart, Jumping, JumpEnd) - that there was a sequence without repetitions while holding the button
Jumping - only if you will fall down from the mountain like

2 - just want to add a field to the stage where there will be other parameters (speed, gravity)

3 - the interaction of the player models with other models
! such as a coin, that would be at the touch of it was removed from the scene
! also provided that the character is at a certain distance, and pressing action takes place, such as a coin disappears.

partly on the work of the interface (it I have not delved)
4 - When you press the left mouse button the object was in Target, and further actions took place in his direction

5 - switching between models (management)
for example I come up to the car, and then click E has already run a car (which has its own controlCharapter)

if help is not difficult to deal with these paragraphs

and if someone does not wish, tell your skype or icq for communication and helping me

оригинал текста без translate.google.com.ua :
изучая материалы пришел к такой вот форме кода.

не получается разобраться с
1- анимацией прыжка (JumpStart, Jumping, JumpEnd ) - что бы была последовательность и без повторов при зажатой кнопке
Jumping - только если будет падать с горы например

2- так же хочу добавить области на сцене в которых будут другие параметры ( скорость, гравитация )

3- взаимодействие модели игрока с другими моделями,
!например монета, что бы при касании она убиралась с сцены
!так же, при условии что персонаж стоит на определенном расстоянии и нажатии клавиши происходило действие, например монета пропадала.

далее частично работа с интерфейсом (в нее я еще не вникал)
4- при нажатии левой кнопки мыши предмет был в таргете и далее действия происходили по направлению к нему

5- переключение между моделями (управление)
например я подхожу к автомобилю, нажимаю E и далее управляю уже автомобилем (у которого свой controlCharapter)

если не сложно помогите разобраться с этими пунктами

и если кому не жаль, сообщите свой скайп или icq для связи и помощи мне

up

I suggest posting videos of your game running in the current state and posting about a specific time, like “00:24 how to make collision here?”
For video try using camstudio, free recording and put it up on youtube.

Also, in addition to the code perhaps you could make a download pack of your project so that it can be run locally, that way it may be easier to try it than just seeing the code here.

tutorials studied, but not all clear to me there.

you heard me right.
when the character model hits the other object.
example

  • When the model of the character hits a ball of fire model.
  • When the character model hits the model nut (nut collect to complete the level (for example you need to collect 10 pieces)).

in my project:
the idea of this piece of the game is that in the world there is a certain amount of models “monet”, to be collected.

the world itself is now quite empty, so I’m trying to understand the physics of what is happening in it.

I think I have not correctly added model “monet”, on this and it is impossible to make what character are struck with a coin, it was destroyed

I understand you want to create collisionShape for coins, and in contact with this area was removed object “monet”.

my project -