A question about ghost control

well I tried what u said then tested further from many different angles it would seem that if the Rigid body doesn’t have a distinct “spatial connection” nothing get returned



see for yourself if you remove the if statement in collide you will only get nodes and geometry same as if the “if statement” was enabled



if you leave the if statement and change the instanceof to rigid body, collision shape whatever nothing is sent to the console only geometry and Nodes i.e. Spatials returns any info to the console



simply run ragdoll1 through ragdoll2 H,K,J,U are the keys and be aware that I have a ghost attached to an attachment node on the left foot

testcase



[java]/*

package hks.test;



import jme3test.bullet.PhysicsTestHelper;



import com.jme3.animation.AnimChannel;

import com.jme3.animation.AnimControl;

import com.jme3.animation.AnimEventListener;

import com.jme3.animation.Bone;

import com.jme3.animation.LoopMode;

import com.jme3.animation.SkeletonControl;

import com.jme3.bullet.BulletAppState;

import com.jme3.app.SimpleApplication;

import com.jme3.asset.TextureKey;

import com.jme3.bullet.PhysicsSpace;

import com.jme3.bullet.collision.PhysicsCollisionEvent;

import com.jme3.bullet.collision.PhysicsCollisionObject;

import com.jme3.bullet.collision.RagdollCollisionListener;

import com.jme3.bullet.collision.shapes.BoxCollisionShape;

import com.jme3.bullet.collision.shapes.CollisionShape;

import com.jme3.bullet.collision.shapes.HullCollisionShape;

import com.jme3.bullet.control.GhostControl;

import com.jme3.bullet.control.KinematicRagdollControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.bullet.objects.PhysicsRigidBody;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Vector2f;

import com.jme3.math.Vector3f;

import com.jme3.renderer.queue.RenderQueue.ShadowMode;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial;

import com.jme3.scene.debug.SkeletonDebugger;

import com.jme3.scene.shape.Box;

import com.jme3.texture.Texture;



/**

  • @author normenhansen

    */

    public class TestRagdollCharacter2 extends SimpleApplication implements RagdollCollisionListener, AnimEventListener, ActionListener {



    BulletAppState bulletAppState;

    Material matBullet;

    Node model;

    KinematicRagdollControl ragdoll;

    float bulletSize = 1f;

    Material mat;

    Material mat3;

    boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false,

    leftRotate = false, rightRotate = false;

    AnimControl animControl;

    AnimChannel animChannel;



    AnimControl animControl2;

    AnimChannel animChannel2;



    private Node model2;

    private KinematicRagdollControl ragdoll2;

    private GhostControl ghostControl;



    public static void main(String[] args) {

    TestRagdollCharacter2 app = new TestRagdollCharacter2();

    app.start();

    }



    public void simpleInitApp() {

    bulletAppState = new BulletAppState();

    bulletAppState.setEnabled(true);

    stateManager.attach(bulletAppState);

    initMaterial();

    setupKeys();

    //initWall(2,1,1);



    cam.setLocation(new Vector3f(-8,0,-4));

    cam.lookAt(new Vector3f(4,0,-7), Vector3f.UNIT_Y);







    bulletAppState.getPhysicsSpace().enableDebug(assetManager);

    PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());

    setupLight();



    model = (Node) assetManager.loadModel(“Models/Sinbad/Sinbad.mesh.xml”);

    model.lookAt(new Vector3f(0,0,-1), Vector3f.UNIT_Y);

    model.setLocalTranslation(4, 0, -7f);



    model2 = (Node) assetManager.loadModel(“Models/Sinbad/Sinbad.mesh.xml”);

    model2.lookAt(new Vector3f(0,0,-1), Vector3f.UNIT_Y);

    model2.setLocalTranslation(4, 0, -15f);



    // hitman.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X));



    //Note: PhysicsRagdollControl is still TODO, constructor will change

    ragdoll = new KinematicRagdollControl(0.5f);

    ragdoll2 = new KinematicRagdollControl(0.5f);



    setupSinbad(ragdoll);

    setupSinbad(ragdoll2);



    ragdoll.addCollisionListener(this);

    ragdoll2.addCollisionListener(this);





    model.addControl(ragdoll);

    model2.addControl(ragdoll2);



    float eighth_pi = FastMath.PI * 0.125f;

    ragdoll.setJointLimit(“Waist”, eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi);

    ragdoll.setJointLimit(“Chest”, eighth_pi, eighth_pi, 0, 0, eighth_pi, eighth_pi);

    ragdoll.getBoneRigidBody(“Foot.L”).setMass(10);

    ragdoll.getBoneRigidBody(“Foot.R”).setMass(10);

    ragdoll.getBoneRigidBody(“Calf.L”).setMass(20);

    ragdoll.getBoneRigidBody(“Calf.R”).setMass(20);

    ragdoll.getBoneRigidBody(“Thigh.L”).setMass(30);

    ragdoll.getBoneRigidBody(“Thigh.R”).setMass(30);

    ragdoll.getBoneRigidBody(“Waist”).setMass(20);

    ragdoll.setEventDispatchImpulseThreshold(0);



    //float eighth_pi = FastMath.PI * 0.125f;

    ragdoll2.setJointLimit(“Waist”, eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi);

    ragdoll2.setJointLimit(“Chest”, eighth_pi, eighth_pi, 0, 0, eighth_pi, eighth_pi);

    ragdoll2.getBoneRigidBody(“Foot.L”).setMass(10);

    ragdoll2.getBoneRigidBody(“Foot.R”).setMass(10);

    ragdoll2.getBoneRigidBody(“Calf.L”).setMass(20);

    ragdoll2.getBoneRigidBody(“Calf.R”).setMass(20);

    ragdoll2.getBoneRigidBody(“Thigh.L”).setMass(30);

    ragdoll2.getBoneRigidBody(“Thigh.R”).setMass(30);

    ragdoll2.getBoneRigidBody(“Waist”).setMass(20);

    ragdoll2.setEventDispatchImpulseThreshold(0);

    //Oto’s head is almost rigid

    // ragdoll.setJointLimit(“head”, 0, 0, eighth_pi, -eighth_pi, 0, 0);



    getPhysicsSpace().add(ragdoll);

    getPhysicsSpace().add(ragdoll2);

    speed = 1.3f;



    rootNode.attachChild(model);

    rootNode.attachChild(model2);



    animControl = model.getControl(AnimControl.class);

    animChannel = animControl.createChannel();

    animChannel.setAnim(“IdleTop”);

    animControl.addListener(this);

    Node n ;



    animControl2 = model2.getControl(AnimControl.class);

    animChannel2 = animControl2.createChannel();

    animChannel2.setAnim(“IdleTop”);

    animControl2.addListener(this);



    SkeletonControl skeletonControl = model2.getControl(SkeletonControl.class);

    Node g1 = skeletonControl.getAttachmentsNode(“Foot.L”);

    CollisionShape myShape = ragdoll2.getBoneRigidBody(“Foot.L”).getCollisionShape();

    ghostControl = new GhostControl(myShape);

    g1.addControl(ghostControl);

    getPhysicsSpace().add(ghostControl);

    //g1.attachChild(gun1);



    }



    private void setupLight() {

    DirectionalLight dl = new DirectionalLight();

    dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());

    dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));

    rootNode.addLight(dl);

    }



    private PhysicsSpace getPhysicsSpace() {

    return bulletAppState.getPhysicsSpace();

    }



    public void initMaterial() {



    matBullet = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

    TextureKey key2 = new TextureKey(“Textures/Terrain/Rock/Rock.PNG”);

    key2.setGenerateMips(true);

    Texture tex2 = assetManager.loadTexture(key2);

    matBullet.setTexture(“ColorMap”, tex2);

    }







    public void collide(Bone bone, PhysicsCollisionObject object, PhysicsCollisionEvent event) {



    if (/object.getUserObject() != null &&/ (object.getUserObject() instanceof Spatial))

    System.out.println("hit " + object.getUserObject().toString());



    }



    private void setupKeys() {

    inputManager.addMapping(“Rotate Left”,

    new KeyTrigger(KeyInput.KEY_H));

    inputManager.addMapping(“Rotate Right”,

    new KeyTrigger(KeyInput.KEY_K));

    inputManager.addMapping(“Walk Forward”,

    new KeyTrigger(KeyInput.KEY_U));

    inputManager.addMapping(“Walk Backward”,

    new KeyTrigger(KeyInput.KEY_J));

    inputManager.addMapping(“Slice”,

    new KeyTrigger(KeyInput.KEY_SPACE),

    new KeyTrigger(KeyInput.KEY_RETURN));

    inputManager.addListener(this, “Strafe Left”, “Strafe Right”);

    inputManager.addListener(this, “Rotate Left”, “Rotate Right”);

    inputManager.addListener(this, “Walk Forward”, “Walk Backward”);

    inputManager.addListener(this, “Slice”);

    }



    public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals(“Rotate Left”)) {

    if (value) {

    leftRotate = true;

    } else {

    leftRotate = false;

    }

    } else if (binding.equals(“Rotate Right”)) {

    if (value) {

    rightRotate = true;

    } else {

    rightRotate = false;

    }

    } else if (binding.equals(“Walk Forward”)) {

    if (value) {

    forward = true;

    } else {

    forward = false;

    }

    } else if (binding.equals(“Walk Backward”)) {

    if (value) {

    backward = true;

    } else {

    backward = false;

    }

    } else if (binding.equals(“Slice”)) {

    if (value) {

    // animChannel.setSpeed(0.3f);

    animChannel.setAnim(“SliceHorizontal”);

    animChannel.setSpeed(0.3f);

    }

    }

    }



    private void setupSinbad(KinematicRagdollControl ragdoll) {

    ragdoll.addBoneName(“Ulna.L”);

    ragdoll.addBoneName(“Ulna.R”);

    ragdoll.addBoneName(“Chest”);

    ragdoll.addBoneName(“Foot.L”);

    ragdoll.addBoneName(“Foot.R”);

    ragdoll.addBoneName(“Hand.R”);

    ragdoll.addBoneName(“Hand.L”);

    ragdoll.addBoneName(“Neck”);

    ragdoll.addBoneName(“Root”);

    ragdoll.addBoneName(“Stomach”);

    ragdoll.addBoneName(“Waist”);

    ragdoll.addBoneName(“Humerus.L”);

    ragdoll.addBoneName(“Humerus.R”);

    ragdoll.addBoneName(“Thigh.L”);

    ragdoll.addBoneName(“Thigh.R”);

    ragdoll.addBoneName(“Calf.L”);

    ragdoll.addBoneName(“Calf.R”);

    ragdoll.addBoneName(“Clavicle.L”);

    ragdoll.addBoneName(“Clavicle.R”);



    }



    @Override

    public void simpleUpdate(float tpf) {

    if(forward){

    model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).mult(10).multLocal(tpf));

    }else if(backward){

    model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(-tpf));

    }else if(leftRotate){

    model.rotate(0, tpf, 0);

    }else if(rightRotate){

    model.rotate(0, -tpf, 0);

    }

    //fpsText.setText("Overlapping objects: " + ghostControl.getOverlappingObjects().toString());

    //fpsText.setText(cam.getLocation() + “/” + cam.getRotation());

    cam.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y);



    }



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



    if (channel.getAnimationName().equals(“SliceHorizontal”)) {

    channel.setLoopMode(LoopMode.DontLoop);

    channel.setAnim(“IdleTop”, 5);

    channel.setLoopMode(LoopMode.Loop);

    }



    }



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

    }







    }

    [/java]

any word I just need to know if I can do what want to do with the ragdoll system if I have to come up with something else …I’m still think about adding a system of ghosts to the ragdoll but would rather not …if it isn’t necessary.

You should not use the collision listener of the rag doll, just register a normal one. If you look at the collision() method in KinematicRagdollControl, you see it drops most callbacks anyway. So first of all register with the physics space to get the unfiltered events. It might be that kinematic-kinematic doesn’t yield collision info but afaik thats only the case for kinematic-static.

@normen said:
You should not use the collision listener of the rag doll, just register a normal one. If you look at the collision() method in KinematicRagdollControl, you see it drops most callbacks anyway. So first of all register with the physics space to get the unfiltered events. It might be that kinematic-kinematic doesn't yield collision info but afaik thats only the case for kinematic-static.


ok thanks I'll check that out later

yeah well I have tried what suggested and didn’t get a good result I also made a copy of KinematicRagdollControl and commented the null checks in collision and made Physics bone link public as it turns out doing that produced output… the only problem with that the ragdoll starts reporting collisions with itself which I had anticipated based on the comments in the code, but it seems each bone start to report and ONLY reports collisions with its own PhysicsCollisionObjects, at least I think so, the “names” of the bonelinks aren’t very descriptive like there Spatial counterparts,… but since the two ragdolls are apart when the test start that can be the only logical answer…I think I dont understand the the correlation between ragdoll bones and there collision shapes and or rigidbodys in this instance, as I have tried alot of things to no avail



so I have some more questions to help me rap my head around this:



what is bone in [java]collide(Bone bone, PhysicsCollisionObject object,

PhysicsCollisionEvent event)[/java]

is it just a description of its attached rigidbody/collisionshape because It was implied “in not so many words” that spatials have nothing to do with physics based collisions but in the case of ragdolls I get a whole lot of “bone is colliding with itself”



are there any “abstract” ways that I can still the ragdoll to define hit zones or should I try some thing else, if so any suggestions

The normal animation bones influence on the mesh is used to define the hull shapes for the single limbs. The limbs are normal RigidBodies (not RigidBodyControls) and the control moves the bones according to the rigidbodies in ragdoll mode or the then kinematic rigidbodes according to the bone animation. Afaik the bone is the user object of the rigidbody so by that you can find out which rigidbody it is (collisionEvent.getObjectA().getUserObject()). Thats also why you get the bone. Like I said, look at the code of the RagDollControl. As the javadoc says its not done and its going pretty far and is best understood in code. You can do what you want with it easily w/o adding any “hit zones” just by using the existing rigidbodies.

yeah what you said here has helped me some I think I’m getting close to what I want :slight_smile: …except that bone doesn’t seem to be the user object of the rigidbody as u said here

@normen said:
Afaik the bone is the user object of the rigidbody


I tested with yes/no output like:
[java]if(ragdoll.getBoneRigidBody(boneA.getName()).getUserObject() instanceof blah)[/java]
and got "no" from all objects except for PhysicsBoneLink which I exposed by making it public along with the rigidbody and bone variables therein .....in a working copy of the ragdoll class.....I also so had to disable the discarding of the "null" checks.........the testing code below is where I'm at now, I say I think I'm getting close because I am getting data from certain bones only if the 2 ragdolls intersect.....

any advice you can add?...........although I think I know what I have to do next


[java]public void collide(Bone bone, PhysicsCollisionObject object, PhysicsCollisionEvent event) {

if (object.getUserObject() != null && (object.getUserObject() instanceof KinematicRagdollControl.PhysicsBoneLink)){

KinematicRagdollControl.PhysicsBoneLink link /*= (PhysicsBoneLink) object.getUserObject()*/;
KinematicRagdollControl.PhysicsBoneLink link2 /*= (PhysicsBoneLink) object.getUserObject()*/;

Bone boneA = animControl.getSkeleton().getBone(bone.getName());
Bone boneB = animControl2.getSkeleton().getBone(bone.getName());


if(ragdoll.getBoneRigidBody(boneA.getName()).getUserObject() instanceof PhysicsBoneLink){
link = (PhysicsBoneLink)ragdoll.getBoneRigidBody(boneA.getName()).getUserObject();
String temp = link.toString();
String pbo = "Rag1_"+boneA.getName()+"_Physics_Object";
temp=pbo;
System.out.println(temp+ " is to " +link.bone.getName());

}
else {
System.out.println("no");
}

if(ragdoll2.getBoneRigidBody(boneB.getName()).getUserObject() instanceof PhysicsBoneLink){
link2 = (PhysicsBoneLink)ragdoll2.getBoneRigidBody(boneB.getName()).getUserObject();
String temp2 = link2.toString();
String pbo2 = "Rag2_"+boneB.getName()+"_Physics_Object";
temp2=pbo2;
System.out.println(temp2+ " is to " +link2.bone.getName());
}
else {
System.out.println("no2");

}[/java]