Bad walking oto character

Hallo, I’ve a problem with my oto character : I 'm not able to move it very good in a space, becouse it just turn around itself :frowning:
Someone can halp me or know a similar test with BETTERCHARACTERCONTROL ?
thanks in advances :slight_smile:
[java]
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.GhostControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;

public class TotalControlChar extends SimpleApplication implements ActionListener, AnimEventListener {

private BulletAppState bulletAppState;

//for character
//private CharacterControl character;
//private Node model;

//other character
Node model_2;
BetterCharacterControl character_2 ;

//animation
private AnimControl animationControl;
private AnimChannel  animationChannel;
private AnimChannel  attackChannelRight;
private AnimChannel  attackChannelLeft;
private AnimChannel   footChannelRight;


//direction walk
private boolean left = false, right = false, up = false, down = false;
private Vector3f walkDirection = new Vector3f(0,0,0);
private float airTime = 0;

public static void main(String[] args) {
    TotalControlChar app = new TotalControlChar();
    app.start();
}

@Override
public void simpleInitApp(){
  //activation phisycs in the scene by addyng a bulletUpState
	    activatPhisycs();
  //initialize the scene and give it the meshCollisionShape
  //in this sample, helper class creates a flat floor and drops some cubes and spheres on it. 
	    initializeScene();
  //turn on the light    
	    lightOn();
  //load  character
		//Create several AnimC1hannels, one for each animation that can happen simultaneously   	
	    load_AnotherCharacter();
	    
	    initChannel();
  //mapping the keys for moving/attack
        mappingKeys();
 	}

public void activatPhisycs(){
   bulletAppState = new BulletAppState();
   stateManager.attach(bulletAppState);
}

public void initializeScene(){
	PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
}

public void lightOn(){
	AmbientLight light = new AmbientLight();
	  light.setColor(ColorRGBA.White.mult(2));
	  rootNode.addLight(light);
}

public void PhysicsControl(){
	 CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
}

//-----------------------------------------------------------------

public void load_AnotherCharacter(){
	  character_2 = new BetterCharacterControl(0,0,0);
	  model_2 = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
      model_2.addControl(character_2);
      character_2.setApplyPhysicsLocal(true);
      character_2.warp(new Vector3f(0, 0,0));
      bulletAppState.getPhysicsSpace().add(character_2);
      rootNode.attachChild(model_2);
}

public void initChannel(){
  //ANIMATION CONTROL
	  animationControl = model_2.getControl(AnimControl.class);
	  animationControl.addListener(this);
//with an animationControl I can create a channel for each animation character, that be happens simultaneously 
	  animationChannel = animationControl.createChannel();
                                                                                               
	  attackChannelRight = animationControl.createChannel();
	  attackChannelRight.addBone(animationControl.getSkeleton().getBone("uparm.right"));
	  attackChannelRight.addBone(animationControl.getSkeleton().getBone("arm.right"));
	  attackChannelRight.addBone(animationControl.getSkeleton().getBone("hand.right"));

	  attackChannelLeft = animationControl.createChannel();
	  attackChannelLeft.addBone(animationControl.getSkeleton().getBone("uparm.left"));
	  attackChannelLeft.addBone(animationControl.getSkeleton().getBone("arm.left"));
	  attackChannelLeft.addBone(animationControl.getSkeleton().getBone("hand.left"));
}


public void mappingKeys(){
	  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.addMapping("CharAttackRight", new KeyTrigger(KeyInput.KEY_F));
	      inputManager.addMapping("CharAttackLeft", new KeyTrigger(KeyInput.KEY_G));
	      inputManager.addMapping("lower", new KeyTrigger(KeyInput.KEY_V));
	      
	  inputManager.addListener(this, "CharLeft", "CharRight");
	  inputManager.addListener(this, "CharForward", "CharBackward");
	  inputManager.addListener(this,  "CharRight","CharLeft");
 	  inputManager.addListener(this, "CharBackWard", "CharForward");
 	      inputManager.addListener(this, "CharJump", "CharJump");
 	      inputManager.addListener(this, "CharAttackRight", "CharAttackRight");
     	  inputManager.addListener(this, "CharAttackLeft", "CharAttackLeft");
     	  inputManager.addListener(this, "footRight");
}


@Override
public void onAction(String binding, boolean value, float tpf) {
	if (binding.equals("CharLeft")) {
      if (value) left = true;
      else left = false;
  } else if (binding.equals("CharRight")) {
      if (value) right = true;
      else right = false;
  } else if (binding.equals("CharForward")) {
      if (value) up = true;
      else up = false;
  } else if (binding.equals("CharBackward")) {
      if (value) down = true;
      else down = false;
  } else if (binding.equals("CharJump"))
      character_2.jump();
  else if (binding.equals("CharAttackRight")){
       attack();
    } else if(binding.equals("CharAttackLeft"))
    	attackLeft();
    else if (binding.equals("lower")){
      if (!animationChannel.getAnimationName().equals("Dodge")){
          animationChannel.setAnim("Dodge", 1f);
       //     animationChannel.setLoopMode(LoopMode.Cycle);
       //   animationChannel.setSpeed(0.10f);
      }
    }
 }


public void simpleUpdate(float tpf) {
  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);
 
  if (left)  walkDirection.addLocal(camLeft);
  if (right) walkDirection.addLocal(camLeft.negate());
  if (up) walkDirection.addLocal(camDir);
  if (down) walkDirection.addLocal(camDir.negate());
 
  if (!character_2.isOnGround()) {
      airTime = airTime + tpf;
  } else {
      airTime = 0;
  }
 
  if (walkDirection.length() == 0) {
      if (!"stand".equals(animationChannel.getAnimationName())) {
        animationChannel.setAnim("stand", 1f);
      }
  } else {
      character_2.setViewDirection(walkDirection);
      if (airTime > .3f) {
        if (!"stand".equals(animationChannel.getAnimationName())) {
          animationChannel.setAnim("stand");
        }
      } else if (!"Walk".equals(animationChannel.getAnimationName())) {
        animationChannel.setAnim("Walk", 0.7f);
      } 
    }
  character_2.setWalkDirection(walkDirection); // THIS IS WHERE THE WALKING HAPPENS
}

	public void attack() {
	   attackChannelRight.setAnim("push", 1f);
	   attackChannelRight.setLoopMode(LoopMode.DontLoop);
    }
	
	public void attackLeft(){
	   attackChannelLeft.setAnim("push",1f);		
       attackChannelRight.setLoopMode(LoopMode.DontLoop);
	}

@Override
public void onAnimChange(AnimControl arg0, AnimChannel arg1, String arg2){
	// TODO Auto-generated method stub
}

@Override
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName){
     if (channel == attackChannelRight)
    	channel.setAnim("stand");
     if (channel == attackChannelLeft)
     	channel.setAnim("stand");
}

}

[/java]

I’m no expert here, but I do notice some things. First off, it looks like you set a lot of double references in your input mapping: everything from line 127 to 134 can be replaced by a single line: [java]inputManager.addListener(this, “CharLeft”, “CharRight”, “CharForward”, “CharBackward”, “CharJump”, “CharAttackRight”, “CharAttackLeft”, “footRight”);[/java]

Now, as far as rotation is concerned, you say your character is simply rotating around itself. With some debugging, try and find out if this is the animation or the walkdirection. For instance, debug walkDirection after line 176 to see if it’s no longer a zero vector.

I think the problem is here :

character_2 = new BetterCharacterControl(0,0,0);

the character has a height of 0 (which is a problem, but it’s an other topic) but also a MASS of 0, and for bullet a mass of zero means that the object doesn’t move. change this and try again.

btw, i don’t understand this method:

[java]
ublic void PhysicsControl(){
CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
}[/java]

The method that you show me ,I forget to delete :slight_smile:

I’ve already tried , now I change in this way

[java]
character_2 = new BetterCharacterControl(3.5f,0.8f,0 );
[/java]

But doesn’t work, if I change 0 the character jump on the sky. :frowning:

if you have 0, it will never work, keep this in mind. A mass of zero is used, for exemple, to create the ground, which doesn’t fall to the infinite void behind it.

about the “jump on the sky”, it depends of the force of the jump. Actually, i always thought that normen should have a method like “setJumpHeight” instead of anything related to “setJumpForce”.

Try with a with of 75 kg for exemple. But keep in mind that as long as you have a mass of zero, as the “bettercharactercontrol” is not a kinematic one, it won’t move at all. This is from the physics engine “jbullet” (and behind it “bullet”), not really about the “jmonkey” stuff.

And if by “jump on the sky” you mean that your character bounce when you walk even on a perfectly flat ground, this is a bug in the bettercharactercontrol, you will not be able to go through this easily. I tried to dampen this effect (and add the stepheight and stepdown stuff that allow you to go upstairs or downstairs without blocking of flying) but it’s way too complicate for me.

and … 3,5 for the radius ? Really ? This mean a diameter of 7 meter ! A realllly fat man :slight_smile:
and the height of 0.8 means that the “character” is 0.8 meter high. A veryyy fat dwarf ?

OK I understand,I’m not able to use it for my objective but there are an alternative method at BetterCharacterControl for characters collision ? I wanna that an automatic player can attack main player. can you advice me for this ? there is a test that does this ?

if you planned to do a collision check to detect if the character attack touch something or not, you are doing it wrong. Even in modern games (like skyrim) you don’t have such thing.

Instead of that, when the character attack, you should try to detect if there a something in front of it (and you can have a very simple shape to do that) and handle the attack yourself.

If you objective is to DETECT collisions (and NOT have a “standard physic” reaction) you can use a ghostcontrol. It doesn’t interract with the rest of the physicworld (it just go through everything) but it registers every object it collides with.

So, you can use a charactercontrol + a ghost control for attacks. But, you should rely on the animation of the attack to register the real attack, it’s an ugly mix between the appearance and the model. It’s hard to do (as you’ll need to update the collision shape every frame of the attack …) and very slow and, again, unnecessary most of time.

However, i don’t know what you are trying to do precisely. And i am not an expert in jme ^^.

1 Like

ok first of all, thanks. Just for explain you speficlly, watch this game video, I wanna a similar test: in this case a skeleton or a spider attack the main player :slight_smile: Before to using, do you think that ghostControl is good to do a similar scene ?