Switch between cameras and move what to follow

Hi, I just got in JM3 since a week and facing a simple problem, I guess.



I have 2 players and each of them has a camera attached as a child (within a CameraNode), but I don’t know how I switch between those cameras

and I don’t know what I need to move to follow those cameras. The idea is to switch between those players after each shot.

I worked with one camera yet and move its location, but that didn’t worked out that well in some cases.



  1. I created 2 players (CharacterControl + Models)

  2. I created 2 CameraNode and attached to each of them Cameras

  3. I attached the 2 CameraNodes to the player



As far as I understand, now the cameras should move automatically with the players node, but what do I need to move and how do I
switch the focus between those 2 cameras?

I would appreciate any help. Here's a hacked example code:

[java]
class {
private BulletAppState bulletAppState;
private CharacterControl player, player2;
private Node modelPlayer1, modelPlayer2, currentPlayer;
private Camera cam1, cam2;
private CameraNode camNode1, camNode2;
private boolean left = false, right = false, up = false, down = false;

...

public void simpleInitApp() {
...
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
...
// creating floors and so forth...
...
this.initCameras();
this.addTwoTestPlayers();
...
}

private void initCameras() {
this.camNode1 = new CameraNode("cam1", cam);
this.camNode2 = new CameraNode("cam2", cam);
camNode1.setControlDir(ControlDirection.SpatialToCamera);
camNode2.setControlDir(ControlDirection.SpatialToCamera);
}

private void addTwoTestPlayers() {
// Add 1st player
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);

player = new CharacterControl(capsuleShape, .01f);
player.setJumpSpeed(20);
player.setFallSpeed(60);
player.setGravity(100);

DirectionalLight sun = new DirectionalLight();
sun.setDirection(<startpoint player 1>);
this.getRootNode().addLight(sun);

this.modelPlayer1 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
this.modelPlayer1.scale(0.05f, 0.05f, 0.05f);
this.modelPlayer1.setName("Model_1");
this.modelPlayer1.addControl(player);
this.modelPlayer1.attachChild(this.camNode1);

this.getRootNode().attachChild(modelPlayer1);
this.getPhysicsSpace().add(modelPlayer1);

this.modelPlayer1.setLocalTranslation(<startpoint player 1>);

// Add 2nd player
capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);

player2 = new CharacterControl(capsuleShape, .01f);
player2.setJumpSpeed(20);
player2.setFallSpeed(60);
player2.setGravity(100);

sun = new DirectionalLight();
sun.setDirection(<startpoint player 2>);
this.getRootNode().addLight(sun);

this.modelPlayer2 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
this.modelPlayer2.scale(0.05f, 0.05f, 0.05f);
this.modelPlayer2.setName("Model_2");
this.modelPlayer2.addControl(player2);
this.modelPlayer2.attachChild(this.camNode2);

this.getRootNode().attachChild(modelPlayer2);
this.getPhysicsSpace().add(modelPlayer2);

this.modelPlayer2.setLocalTranslation(<startpoint player 2>);
}

@Override
public Camera getCamera() {
return <which camera shall be currently focused>;
}

@Override
public void simpleUpdate(float tpf) {
Vector3f camDir = this.getCamera().getDirection().clone()
.multLocal(0.3f);
Vector3f camLeft = this.getCamera().getLeft().clone().multLocal(0.2f);

Vector3f walkDirection = new Vector3f(Vector3f.ZERO);
if (left) {
walkDirection.addLocal(camLeft);
}
if (right) {
walkDirection.addLocal(camLeft.negate());
}
if (up) {
walkDirection.addLocal(camDir);
}
if (down) {
walkDirection.addLocal(camDir.negate());
}
// So I can now move modelPlayer1/2 and the camera will follow right?
// And how do I focus the one of those cameras?

// With one camera I do currently this: (but that doesn't work out that well in some cases:
// this.currentPlayer.setWalkDirection(walkDirection);
// this.currentPlayer.setViewDirection(cam.getDirection());
// cam.setLocation(this.currentPlayer.getPhysicsLocation());
}
}
[/java]

The question is what do I move in SimpleUpdate? And how do I switch the focus between those cameras?

You should not have 2 cameras, just have one camera (the one created for you in simpleApplication) and create your 2 camera nodes with the same camera.



when you create your CameraNodes, disable the CamreaControl



CameraNode camNode1= new CameraNode(“cam1”, cam);

camNode1.getControl(CameraControl.class).setEnabled(false);



and do the same for camNode2.



then when you want to activate one camera just do



camNode1.getControl(CameraControl.class).setEnabled(false);

camNode2.getControl(CameraControl.class).setEnabled(true);



this will deactivate camNode1’s control and activate camNode2’s.

1 Like

Wow, thanks, that works great. :slight_smile:



Another wired problem I encountered is when I am using now these two cameras and play with the “Hello Physics” tutorial to shoot a ball from the current cameras view direction, the first camera always fires in the direction which the camera currently shows,

but when I switch to the seconds camera, then it shoots in a completely different direction - although I am exactly focusing a certain object, and I’m just using the method from the Wiki:



[java]

public void makeCannonBall() {

/** Create a cannon ball geometry and attach to scene graph. /

Geometry ball_geo = new Geometry(“cannon ball”, sphere);

ball_geo.setMaterial(stone_mat);

rootNode.attachChild(ball_geo);

/
* Position the cannon ball /

ball_geo.setLocalTranslation(this.getCamera().getLocation());

/
* Make the ball physcial with a mass > 0.0f /

ball_phy = new RigidBodyControl(1f);

/
* Add physical ball to physics space. /

ball_geo.addControl(ball_phy);

this.getPhysicsSpace().add(ball_phy);

/
* Accelerate the physcial ball to shoot it. */

ball_phy.setPhysicsLocation(this.getCamera().getLocation());

ball_phy.setLinearVelocity(this.getCamera().getDirection().mult(50));

}

[/java]



So when I switch now to the second camera the “this.getCamera().getDirection()” is focusing another direction, do I need to do something additional to correct the direction?

it’s hard to tell…maybe try to output the this.getCamera().getLocation() to see if it’s correct.

I don’t find the bug, the second player still shoots in the wrong direction and the camera data matches with the player2 data, that doesn’t make sense.



I basically just:


  1. Select a first player and mark it as “currentPlayer”
  2. When the player shoots I fire a ball with the method above
  3. And then switch the cameras



    Can anybody see the bug?



    [java]

    public void simpleInitApp() {



    this.initCameras();

    this.addPlayers();

    this.currentPlayer = this.player;

    this.focusPlayer(this.currentPlayer);

    }



    public void simpleUpdate(float tpf) {



    this.movePlayer();

    }



    private void movePlayer() {

    Vector3f camDir = this.getCamera().getDirection().clone().multLocal(0.3f);

    Vector3f camLeft = this.getCamera().getLeft().clone().multLocal(0.2f);



    Vector3f walkDirection = new Vector3f(Vector3f.ZERO);

    if (left) {

    walkDirection.addLocal(camLeft);

    }

    if (right) {

    walkDirection.addLocal(camLeft.negate());

    }

    if (up) {

    walkDirection.addLocal(camDir);

    }

    if (down) {

    walkDirection.addLocal(camDir.negate());

    }

    this.currentPlayer.setWalkDirection(walkDirection);

    this.getCamera().setLocation(this.currentPlayer.getPhysicsLocation());

    }



    private ActionListener actionListener = new ActionListener() {

    public void onAction(String name, boolean keyPressed, float tpf) {

    if (name.equals("shoot") && !keyPressed) {

    makeCannonBall();

    switchPlayer();

    }

    }

    };



    private void switchPlayer() {

    this.currentPlayer.setWalkDirection(Vector3f.ZERO);



    if (this.currentPlayer.equals(this.player)) {

    this.currentPlayer = this.player2;

    } else if (this.currentPlayer.equals(this.player2)) {

    this.currentPlayer = this.player;

    }

    this.focusPlayer(this.currentPlayer);

    }



    private void focusPlayer(CharacterControl selectPlayer) {

    if (selectPlayer.equals(this.player)) {

    camNode1.getControl(CameraControl.class).setEnabled(false);

    camNode2.getControl(CameraControl.class).setEnabled(true);

    } else if (selectPlayer.equals(this.player2)) {

    camNode1.getControl(CameraControl.class).setEnabled(true);

    camNode2.getControl(CameraControl.class).setEnabled(false);

    }

    this.getCamera().setLocation(selectPlayer.getPhysicsLocation());

    this.getCamera().lookAtDirection(selectPlayer.getViewDirection(),

    Vector3f.UNIT_Y);

    }

    [/java]
@openjonny said:
I basically just:

1. Select a first player and mark it as "currentPlayer"
2. When the player shoots I fire a ball with the method above
3. And then switch the cameras

well...you should switch cam before shooting the ball...the shooting ball takes the camera location as original position..
@nehon said:
well...you should switch cam before shooting the ball...the shooting ball takes the camera location as original position..


I don't get it. I want to shoot the ball from the position and the direction right now that I am facing with the camera and then switch and not switch to the other player without aiming and shooting immediately.

It seems that there's something wrong with the angle from which the ball is shot from the player2, but I don't get what kind of sense that makes when I see on the camera an object and calling the same method for both players and always and get only for player2 a wrong angle. The location seems to be correct.