Hi,
I’m making sokoban-like game, and I’m stucked on collisions. So far I have scene (RigidBodyControl), player as CharacterControl and box (RigidBodyControl). I need to make player be able to hold box in hands and move it in same direction as player (attach box+rigidBody to playerNode). In same time (while player is walking) I need to check for all collisions between player+box against scene+allOtherObjects.
Which type of controls, collisions/physics should I use for player and boxes?
[java]package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.asset.TextureKey;
import com.jme3.bounding.BoundingVolume;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.collision.CollisionResults;
import com.jme3.input.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.controls.TouchListener;
import com.jme3.input.controls.TouchTrigger;
import com.jme3.input.event.TouchEvent;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Transform;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.texture.Texture;
public class Main extends SimpleApplication implements ActionListener, TouchListener {
public Main(){
super(new StatsAppState());
}
private CharacterControl character;
private CameraNode camNode;
private Spatial sceneModel;
private CapsuleCollisionShape capsuleShape;
private RigidBodyControl rbc;
private Spatial model;
private Geometry reBoxg;
private Node playerNode;
private BulletAppState bulletAppState;
private ChaseCamera chaseCam;
private boolean left = false, right = false, up = false, down = false, picked = false, colide = false;
private Vector3f walkDirection = new Vector3f(0, 0, 0); // stop
private float airTime = 0;
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
//Set up physics
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
// Load j3o SCENE
sceneModel = assetManager.loadModel(“Scenes/town/main.scene”);
sceneModel.setLocalTranslation(-20, 0, 20);
//sceneModel.setLocalScale(0.10f);
sceneModel.addControl(new RigidBodyControl(0));
rootNode.attachChild(sceneModel);
bulletAppState.getPhysicsSpace().addAll(sceneModel);
// Create player model
capsuleShape = new CapsuleCollisionShape(0.5f, 2f);
character = new CharacterControl(capsuleShape, 0.05f);
character.setJumpSpeed(20f);
model = assetManager.loadModel(“Models/robot/robot.j3o”);
model.scale(0.02f);
playerNode = new Node(“player”);
playerNode.setLocalTranslation(0, 10, 0);
playerNode.attachChild(model);
model.getLocalTranslation().subtractLocal(0, 2f, 0);
playerNode.addControl(character);
rootNode.attachChild(playerNode);
bulletAppState.getPhysicsSpace().add(character);
// Create box
Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
TextureKey key = new TextureKey(“Textures/Terrain/BrickWall/BrickWall.jpg”);
key.setGenerateMips(true);
Texture tex = assetManager.loadTexture(key);
mat.setTexture(“ColorMap”, tex);
Box brick = new Box(Vector3f.ZERO, 1, 1, 4);
brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
reBoxg = new Geometry(“brick”, brick);
reBoxg.setMaterial(mat);
reBoxg.setLocalTranslation(new Vector3f(0, 1, 0));
//for geometry with sphere mesh the physics system automatically uses a sphere collision shape
rbc = new RigidBodyControl(0);
reBoxg.addControl(rbc);
reBoxg.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
reBoxg.getControl(RigidBodyControl.class).setFriction(1.0f);
bulletAppState.getPhysicsSpace().add(reBoxg);
rootNode.attachChild(reBoxg);
// Add Light
AmbientLight light = new AmbientLight();
light.setColor(ColorRGBA.White.mult(2));
rootNode.addLight(light);
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
rootNode.addLight(dl);
// ********* CHASE CAMERA **********
chaseCam = new ChaseCamera(cam, model, inputManager);
chaseCam.setInvertVerticalAxis(true);
chaseCam.setDragToRotate(false);
// chaseCam.setMinDistance(0.001f);
// chaseCam.setMaxDistance(0.001f);
chaseCam.setDownRotateOnCloseViewOnly(false);
chaseCam.setDefaultVerticalRotation(0.0f);
chaseCam.setMaxVerticalRotation((float)Math.PI/4);
chaseCam.setMinVerticalRotation(-(float)Math.PI/4);
inputManager.setCursorVisible(false);
// ********* CHASE CAMERA **********
// configure mappings, eg. the WASD keys
inputManager.addMapping(“CharLeft”, new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping(“CharRight”, new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping(“CharForward”, new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping(“CharBackward”, new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping(“CharJump”, new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(this, new String[]{“Touch”});
inputManager.addMapping(“Touch”, new TouchTrigger(0));
inputManager.addMapping(“Click”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(this, “CharLeft”, “CharRight”);
inputManager.addListener(this, “CharForward”, “CharBackward”);
inputManager.addListener(this, “CharJump”, “Click”);
}
@Override
public void simpleUpdate(float tpf) {
CollisionResults results = new CollisionResults();
BoundingVolume bv = reBoxg.getWorldBound();
model.collideWith(bv, results);
Vector3f camDir = cam.getDirection().clone().multLocal(0.25f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.25f);
camDir.y = 0;
camLeft.y = 0;
walkDirection.set(0, 0, 0);
character.setViewDirection(camDir);
if (left) {
walkDirection.addLocal(camLeft);
}
if (right) {
walkDirection.addLocal(camLeft.negate());
}
if (up) {
walkDirection.addLocal(camDir);
}
if (down) {
walkDirection.addLocal(camDir.negate());
}
if (!character.onGround()) {
airTime = airTime + tpf;
} else {
airTime = 0;
}
if(results.size() > 0){
colide = true;
}else{
colide = false;
}
character.setWalkDirection(walkDirection);
}
public void onAction(String binding, boolean pressed, float tpf) {
if (binding.equals(“CharLeft”)) {
if (pressed) {
left = true;
} else {
left = false;
}
} else if (binding.equals(“CharRight”)) {
if (pressed) {
right = true;
} else {
right = false;
}
} else if (binding.equals(“CharForward”)) {
if (pressed) {
up = true;
} else {
up = false;
}
} else if (binding.equals(“CharBackward”)) {
if (pressed) {
down = true;
} else {
down = false;
}
} else if (binding.equals(“CharJump”)) {
character.jump();
} else if (binding.equals(“Click”) && colide && !pressed){
if(picked){
picked = false;
rootNode.attachChild(reBoxg);
}else{
picked = true;
playerNode.attachChild(reBoxg);
}
}
}
public void onTouch(String name, TouchEvent evt, float tpf) {
}
}
[/java]
well the CharacterControl cannot exert a force, so you will have to use applyforce/impluse on the box yourself in a physics tick listener. I suggest applying the force in the opposite direction to the boxes surface normal which you collide with, this way the box shouldn’t move to its side