Physics and walking character

I want to create scene by using Oto and town with Physics support. Oto needes to walk. But, I cant find Oto in the scene. When Chase cam is configured I can see it is getting sinked in.

“I want Oto to walk towards the cityboy character and stop near him.”

I have pasted the code I am using for this task. Can some one please advice on me where I have gone wrong in this small exercise.



[java]

public class Location extends SimpleApplication implements AnimEventListener{



static final Quaternion ROTATE_LEFT = new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);

private BulletAppState bulletAppState;

private CharacterControl characterControl;

private AnimControl animationControl;

private AnimChannel animationChannel;

private Vector3f walkDirection = new Vector3f();



public static void main(String[] args) {

Location app = new Location();

app.start();

}





@Override

public void simpleInitApp() {

setupBase();

setupLights();

loadHalt();

createStaticCharacter();

createWalkingCharacter();

}



private void setupBase() {

bulletAppState = new BulletAppState();

bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);

stateManager.attach(bulletAppState);



Spatial town = assetManager.loadModel(“Scenes/town/main.j3o”);

town.setLocalTranslation(0, -6, 0);

town.setLocalScale(2);



CollisionShape townShape = CollisionShapeFactory.createMeshShape(town);

RigidBodyControl townPhysicsNode = new RigidBodyControl(townShape, 0);

town.addControl(townPhysicsNode);

bulletAppState.getPhysicsSpace().add(townPhysicsNode);



rootNode.attachChild(town);

System.out.println("Camera Direction : " + cam.getDirection());

cam.setDirection(new Vector3f(1, 0, 1));

}



@Override

public void simpleUpdate(float tpf) {



if(!“Walk”.equals(animationChannel.getAnimationName())){

animationChannel.setAnim(“Walk”,0);



Vector3f camDir = cam.getDirection().clone().multLocal(0.2f);

camDir.y = 0;

walkDirection.set(0, 0, 0);

walkDirection.addLocal(camDir);

characterControl.setWalkDirection(walkDirection);

animationChannel.setLoopMode(LoopMode.Loop);

}



}



@Override

public void simpleRender(RenderManager rm) {

//TODO: add render code

}



private void setupLights() {



DirectionalLight dl1 = new DirectionalLight();

dl1.setDirection(new Vector3f(-5, -0.5f, 0));



DirectionalLight dl2 = new DirectionalLight();

dl2.setDirection(new Vector3f(5, -0.5f, 0));



DirectionalLight dl3 = new DirectionalLight();

dl3.setDirection(new Vector3f(0, -0.5f, 5));



DirectionalLight dl4 = new DirectionalLight();

dl4.setDirection(new Vector3f(0, -0.5f, -5));



rootNode.addLight(dl1);

rootNode.addLight(dl2);

rootNode.addLight(dl3);

rootNode.addLight(dl4);

}



private void loadHalt() {

Node halt = (Node) assetManager.loadModel(“Models/busstop/busstop.mesh.xml”);

halt.setLocalScale(3);

halt.setLocalTranslation(35, -6, 70);

halt.setLocalRotation(ROTATE_LEFT);

rootNode.attachChild(halt);



}



private void createStaticCharacter() {

Node cityBoy = (Node) assetManager.loadModel(“Models/cityboy/cityboy.mesh.xml”);

cityBoy.setLocalTranslation(20, -4, 40);

cityBoy.rotate(0, FastMath.PI, 0);

rootNode.attachChild(cityBoy);

}



private void createWalkingCharacter() {

Node oto = (Node) assetManager.loadModel(“Models/Oto/Oto.mesh.xml”);

oto.setLocalScale(0.5f);

oto.setLocalTranslation(20, -2, 10);



CapsuleCollisionShape colisionShape = new CapsuleCollisionShape(1, 1.5f);

characterControl = new CharacterControl(colisionShape, 0.01f);

oto.addControl(characterControl);



animationControl = oto.getControl(AnimControl.class);

animationChannel = animationControl.createChannel();

animationChannel.setAnim(“stand”);

bulletAppState.getPhysicsSpace().add(characterControl);



flyCam.setEnabled(false);

ChaseCamera chaseCamera = new ChaseCamera(cam, oto);



rootNode.attachChild(oto);

}



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



if (!“stand”.equals(animationChannel.getAnimationName())) {

animationChannel.setAnim(“stand”);

}

}



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



}

}

[/java]

Theres an example in the tests called TestWalkingChar, another user just posted this in the forum:

http://hub.jmonkeyengine.org/groups/user-code-projects/forum/topic/basic-third-person-framework-with-model-animations-and-jump-freezing/

Thanks Normen !!!

Hi Normen,

I want Ninja to walk towards the halt node. So I modified the code by pointing the walkdirection to halts’ local translation. Seems it is not working. Ninja is going out from the scene when I do that. Where I have gone wrong here ? Can you please advice me to reach my objective ?



Realy appreciate your help.

Thanks.



[java]

@Override

public void simpleUpdate(float tpf) {



float movementAmount = 0.3f;



// Gets forward direction and moves it forward

Vector3f direction = cam.getDirection().clone().multLocal(movementAmount);

// Gets left direction and moves it to the left

Vector3f leftDirection = cam.getLeft().clone().multLocal(movementAmount * 0.75f);



// We don’t want to fly or go underground

direction.y = 0;

leftDirection.y = 0;



walkDirection.set(0, 0, 0); // The walk direction is initially null





walkDirection.addLocal(halt.getLocalTranslation());









// If we’re not walking, set standing animation if not jumping

if (walkDirection.length() == 0) {

ach.setLoopMode(LoopMode.Loop);

if (!ach.getAnimationName().equals(“Idle2”)) {

ach.setAnim(“Idle2”, 0f);

ach.setSpeed(1f);

}

} else {

// … otherwise, set the walking animation

ach.setLoopMode(LoopMode.Loop);

if(!ach.getAnimationName().equals(“Walk”)){

ach.setAnim(“Walk”, 0.5f);

}



ach.setSpeed(1f);

}





player.setWalkDirection(walkDirection);





// Rotate model to point walk direction if moving

if(walkDirection.length() != 0)

player.setViewDirection(walkDirection.negate());

// negating cause the model is flipped







}



private void loadHalt() {

halt = (Node) assetManager.loadModel(“Models/busstop/busstop.mesh.xml”);

halt.setLocalScale(3);

halt.setLocalTranslation(35, 0, 70);

halt.setLocalRotation(ROTATE_LEFT);

rootNode.attachChild(halt);



}

[/java]

to compute a direction from one point to another you have to compute the difference between them

you need to do something like that :



walkDirection.set(halt.getWorldTranslation()).subtractLocal(ninja.getWorldTranslation()).normalizeLocal();





And you earned a link to the math tuto :smiley:

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:math_for_dummies

Thanks Nehon, Oh god, seems I have totally gone out of maths !!!

Hi,

As previously mentioned, now I want to stop my Ninja when he comes near to the City Boy. I though I could do that by checking the collision of those two objects. But I failed. It gives me a exception.



Please elaborate me on this mistake as well. How should I stop the my Ninja near the City Boy ?

PS: After completing this task successfully. I will surely put this exercise step by step to the forum.



[java]

@Override

public void simpleUpdate(float tpf) {



float movementAmount = 0.3f;



// Gets forward direction and moves it forward

Vector3f direction = cam.getDirection().clone().multLocal(movementAmount);

// Gets left direction and moves it to the left

Vector3f leftDirection = cam.getLeft().clone().multLocal(movementAmount * 0.75f);



// We don’t want to fly or go underground

direction.y = 0;

leftDirection.y = 0;



walkDirection.set(0, 0, 0); // The walk direction is initially null



walkDirection.set(halt.getWorldTranslation()).subtractLocal(playerModel.getWorldTranslation()).normalizeLocal();



CollisionResults collisionResults = new CollisionResults();

playerModel.collideWith(cityBoy, collisionResults);



if (collisionResults.size() == 0) {

// If we’re not walking, set standing animation if not jumping

if (walkDirection.length() == 0) {

ach.setLoopMode(LoopMode.Loop);

if (!ach.getAnimationName().equals(“Idle2”)) {

ach.setAnim(“Idle2”, 0f);

ach.setSpeed(0.1f);

}

} else {

// … otherwise, set the walking animation

ach.setLoopMode(LoopMode.Loop);

if (!ach.getAnimationName().equals(“Walk”)) {

ach.setAnim(“Walk”, 0.5f);

}



ach.setSpeed(0.1f);

}





player.setWalkDirection(walkDirection);





// Rotate model to point walk direction if moving

if (walkDirection.length() != 0) {

player.setViewDirection(walkDirection.negate());

}

// negating cause the model is flipped

}



private void createStaticCharacter() {

cityBoy = (Node) assetManager.loadModel(“Models/cityboy/cityboy.mesh.xml”);

cityBoy.setLocalTranslation(20, 0, 40);

cityBoy.rotate(0, FastMath.PI, 0);

rootNode.attachChild(cityBoy);

}



}

[/java]







INFO: Child (cityboy-ogremesh) attached to this node (Root Node)
Apr 1, 2011 11:18:50 AM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
com.jme3.collision.UnsupportedCollisionException
at com.jme3.collision.bih.BIHTree.collideWith(BIHTree.java:479)
at com.jme3.scene.Mesh.collideWith(Mesh.java:501)
at com.jme3.scene.Geometry.collideWith(Geometry.java:255)
at com.jme3.scene.Node.collideWith(Node.java:505)
at jkd.dilvi.LocationTemp.simpleUpdate(LocationTemp.java:102)

you can only collide geometries with geometries … node vs node collision is not supported



i really suggest you read https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:collision_and_intersection and check out the test classes

Since you are already using bullet physics, you can do more advanced collision checks with it than with the geometry-based collision system

Hi Norman,


  • Thanks for your advice. Can you please point me to sample code to get a help to do my work done. I am bit lost here. This time I tried with PhysicsCollisionListener.


  • But still no success. Even it is not coming in to the implemented collision method.


  • I just want to walk Ninja towards the halt and stop him when he comes near that. I have pasted the whole code which I am using.



    Thanks.


[java]
public class LocationTemp extends SimpleApplication implements AnimEventListener, PhysicsCollisionListener {

static final Quaternion ROTATE_LEFT = new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);
private BulletAppState bulletAppState;
private Vector3f walkDirection = new Vector3f();
private Node playerNode;
private Node playerModel;
private Spatial townModel;
private RigidBodyControl townPhysicsControl;
private RigidBodyControl haltPhysicsControl;
private CharacterControl playerPhysicsControl;
private ChaseCamera chaseCam;
private AnimControl act;
private AnimChannel ach;
private int airTime;
private Node halt;

public static void main(String[] args) {
LocationTemp app = new LocationTemp();
AppSettings settings = new AppSettings(true);
settings.setTitle("MCS 3070 Assignment 2 - Kasun Dilunika.");
settings.setSettingsDialogImage("/Textures/neko_nagato.jpg");
app.setSettings(settings);
app.start();
}
private Node cityBoy;

@Override
public void simpleInitApp() {
setupLights();
setupModels();
addPhysics();
setupCameras();
initializeAnimations();

}

private void setupLights() {

AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f)); // mult makes it brighter
rootNode.addLight(al);

DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
rootNode.addLight(sun);
}

private void setupModels() {

loadCity();
loadNinja();
loadCity();
loadHalt();
loadCityBoy();
}

private void addPhysics() {
// Initialize physics engine
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);

// Our rigid scene
CollisionShape townShape =
CollisionShapeFactory.createMeshShape((Node) townModel);
townPhysicsControl = new RigidBodyControl(townShape, 0); // Static physics node with mass 0
townModel.addControl(townPhysicsControl);

// Rigid halt
CollisionShape haltShape =
CollisionShapeFactory.createMeshShape((Node) halt);
haltPhysicsControl = new RigidBodyControl(haltShape, 0); // Static physics node with mass 0
halt.addControl(haltPhysicsControl);

// Third parameter of CapsuleCollisionShape is the axis, 1 = Y
CapsuleCollisionShape capsuleShape =
new CapsuleCollisionShape(2.3f, 2.6f, 1);
playerPhysicsControl = new CharacterControl(capsuleShape, 0.05f);
// 0.05f is the highest step you can climb without jumping
playerPhysicsControl.setJumpSpeed(30);
playerPhysicsControl.setFallSpeed(60);
playerPhysicsControl.setGravity(70);
playerNode.addControl(playerPhysicsControl);
playerPhysicsControl.setPhysicsLocation(new Vector3f(0, 10, 0));
playerNode.setLocalTranslation(new Vector3f(0, 10, 0));

rootNode.attachChild(playerNode);
rootNode.attachChild(townModel);

// Physic nodes are attached to the physics space
// instead of the root node
bulletAppState.getPhysicsSpace().add(townPhysicsControl);
bulletAppState.getPhysicsSpace().add(haltPhysicsControl);
bulletAppState.getPhysicsSpace().add(playerPhysicsControl);
}

private void setupCameras() {
viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1));
flyCam.setEnabled(false);
chaseCam = new ChaseCamera(cam, playerModel, inputManager);
chaseCam.setDragToRotate(false);
chaseCam.setInvertVerticalAxis(true);
chaseCam.setLookAtOffset(new Vector3f(0, 2f, 0));
}

private void initializeAnimations() {
act = playerModel.getControl(AnimControl.class);
act.addListener(this);
ach = act.createChannel();
ach.setAnim("Idle2");
}

private void loadCity() {
townModel = assetManager.loadModel("Scenes/town/main.j3o");
townModel.setLocalScale(2f);
townModel.setName("town");
}

private void loadNinja() {
playerNode = new Node("ninja");
playerModel = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
playerModel.setLocalScale(0.035f);
playerModel.getLocalTranslation().addLocal(7, -3.6f, 7); // model offset fix
playerNode.attachChild(playerModel);

}

private void loadHalt() {
halt = (Node) assetManager.loadModel("Models/busstop/busstop.mesh.xml");
halt.setName("halt");
halt.setLocalScale(3);
halt.setLocalTranslation(35, 0, 70);
halt.setLocalRotation(ROTATE_LEFT);
rootNode.attachChild(halt);

}

private void loadCityBoy() {
cityBoy = (Node) assetManager.loadModel("Models/cityboy/cityboy.mesh.xml");
cityBoy.setLocalTranslation(20, 0, 40);
cityBoy.rotate(0, FastMath.PI, 0);
rootNode.attachChild(cityBoy);
}

@Override
public void simpleUpdate(float tpf) {
updateNormal();
}

private void updateNormal() {
float movementAmount = 0.3f;

// Gets forward direction and moves it forward
Vector3f direction = cam.getDirection().clone().multLocal(movementAmount);
// Gets left direction and moves it to the left
Vector3f leftDirection = cam.getLeft().clone().multLocal(movementAmount * 0.75f);

// We don't want to fly or go underground
direction.y = 0;
leftDirection.y = 0;

walkDirection.set(0, 0, 0); // The walk direction is initially null

walkDirection.set(halt.getWorldTranslation()).subtractLocal(playerModel.getWorldTranslation()).normalizeLocal();


// If we're not walking, set standing animation if not jumping
if (walkDirection.length() == 0) {
ach.setLoopMode(LoopMode.Loop);
if (!ach.getAnimationName().equals("Idle2")) {
ach.setAnim("Idle2", 0f);
ach.setSpeed(0.1f);
}
} else {
// ... otherwise, set the walking animation
ach.setLoopMode(LoopMode.Loop);
if (!ach.getAnimationName().equals("Walk")) {
ach.setAnim("Walk", 0.5f);
}

ach.setSpeed(0.1f);
}


playerPhysicsControl.setWalkDirection(walkDirection);


// Rotate model to point walk direction if moving
if (walkDirection.length() != 0) {
playerPhysicsControl.setViewDirection(walkDirection.negate());
}
// negating cause the model is flipped

}



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

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

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

public void collision(PhysicsCollisionEvent event) {
System.out.println("Node A = " + event.getNodeA().getName());
System.out.println("Node B = " + event.getNodeB().getName());

if ((event.getNodeA().getName().equals("ninja") && event.getNodeB().getName().equals("halt")) ||
(event.getNodeA().getName().equals("halt") && event.getNodeB().getName().equals("ninja"))) {
stopNinja();
}
}

private void stopNinja() {
System.out.println("Going stop ninja");
}
}

[/java]

Hi,



I found the problem for not calling the collision method. I haven’t add collision listener to the PhysicsSpace. But still it is not identifying the halt as either node A or node B although the ninja hits on the halt and rotating around it. :frowning:



Thanks.

Put a GhostObject with some radius in the middle and check its overlapping objects list for the ninja each frame.

Can you please elaborate on this Norman ? I am not clear enough on what you are saying. And what would be the reason for not identifying the halt as colliding object when the town is identified ?

I dont know what you mean by “halt” or “city boy”, sorry.

[java]

GhostObject gObj=new GhostObject(new SphereCollisioShape(10));

gObj.setPhysicsLocation(haltLocation);



//in update:

List objects=gObj.getOverlappingObjects();

if(objects.contains(ninja)){

System.out.println(“Ninja is near! Everybody hide!!!”);

}

[/java]

Ok, I ll try this Norman. Sorry for making you confuse. I was referring the variable names which I was using in the previously pasted code sample.

Thanks Norman,



I tried what you have suggested. it is working fine for me. Actually I used GhostControler instead of GhostObject.



[java]

GhostControl gc = new GhostControl(new SphereCollisionShape(5));

gc.setPhysicsLocation(haltPhysicsControl.getPhysicsLocation());



//in update

List<PhysicsCollisionObject> overlappingObjects = gc.getOverlappingObjects();

System.out.println("OverlappingObjects SIZE = " + overlappingObjects.size());

System.out.println("OverlappingObjects = " + overlappingObjects);

if(overlappingObjects.contains(playerPhysicsControl)){

System.out.println("Please some one stop this Ninja.");

}else{

walkDirection.set(halt.getWorldTranslation()).subtractLocal(playerModel.getWorldTranslation()).normalizeLocal();

}

[/java]