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
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.
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]