# I am using: #

Libgdx and Box2d.

-------------

# what I am trying to do: #

I want enemy to move right and left. if enemy hits the wall than move the over way.

----

# My plan: #

I have two senors set up on the enemy. one on enemy left side and other on enemy right side. so if wall hit enemy right senor than move enmey left. and if wall hit enemy left senor than move enmey right.

I am creating 3 enemies and I am storeing them in arraylist.

--------

# Problem: #

if I create 1 enemy it works fine. enemy hits the wall and switch direction. I am doing collision stuff in contectListener also called (beginContact & endContact methods).

problem is when i create 2 or more enemies and store in arraylist. so for some reason if a enemy switch direction than all of enemies switch directions together.

I know why this is happening. its bc in contectListener I have one variable called "wallSwitch" which checks, if enemy hit a wall and enemy need to switch. so that is why it works for one enmey fine. that 'wallSwitch' variable is changing every enemies direction. I need to come up way so so every enemy is different.

-----

here is I am building enemy. It was two sensors. on enemy left side & other on enemy right side.

private void createEnemies() {
...
    for (MapObject mo : layer.getObjects()) {
        bdef.type = BodyType.DynamicBody;
            ....
        bdef.position.set(x, y);
        body = world.createBody(bdef);

        /*** 1st fixture - enemy ***/
        pshape.setAsBox(10f/PPM, 10f/PPM);
        fdef.shape = pshape;
        fdef.isSensor = false;
        fdef.filter.categoryBits = Constants.BIT_ENEMY;
        fdef.filter.maskBits = Constants.BIT_PLAYER;
        body.createFixture(fdef).setUserData("enemy");

        /*** 2nd fixture - left ***/
        pshape.setAsBox(10f/PPM, 10f/PPM, new Vector2(-10f / PPM,
                0f/PPM), 0);
        fdef.shape = pshape;
        fdef.isSensor = true;
        fdef.filter.categoryBits = Constants.BIT_ENEMY; // id
        fdef.filter.maskBits = Constants.BIT_GROUND;// collied with
        body.createFixture(fdef).setUserData("enemyLeft");

        /*** 3rd fixture - right ***/
        pshape.setAsBox(10f / PPM, 10f / PPM, new Vector2(10f / PPM,
                0f / PPM), 0);
        fdef.shape = pshape;
        fdef.isSensor = true;
        fdef.filter.categoryBits = Constants.BIT_ENEMY; // id
        fdef.filter.maskBits = Constants.BIT_GROUND;// collied with
        body.createFixture(fdef).setUserData("enemyRight");// myContactListener


        // create & store in array list
        Enemies e1 = new Enemy1(body);
                    Enemies e2 = new Enemy1(body);  //problem here
        enemiesStore.add(e1);
                     enemiesStore.add(e2);
    }
}
Sub-Heading Here
Problem is here I think

here is collision stuff. when enemy sensor touching a wall than switch direction.

 boolean wallSwitch;

 public void beginContact(Contact contact) {
    Fixture fa = contact.getFixtureA();
    Fixture fb = contact.getFixtureB();

    // Enemy switch direction
    if (fa.getUserData() != null && fa.getUserData().equals("enemyLeft")) {
        wallSwitch = true;
    }
    if (fb.getUserData() != null && fb.getUserData().equals("enemyLeft")) {
        wallSwitch = true;
    }
    if (fa.getUserData() != null && fa.getUserData().equals("enemyRight")) {
        wallSwitch = true;
    }
    if (fb.getUserData() != null && fb.getUserData().equals("enemyRight")) {
        wallSwitch = true;
    }

}

// called when two fixtures no longer collide - run it onces

 public void endContact(Contact contact) {
    Fixture fa = contact.getFixtureA();
    Fixture fb = contact.getFixtureB();

    // Enemy switch direction
    if (fa.getUserData() != null && fa.getUserData().equals("enemyLeft")) {
        wallSwitch = false;
    }
    if (fb.getUserData() != null && fb.getUserData().equals("enemyLeft")) {
        wallSwitch = false;
    }
    if (fa.getUserData() != null && fa.getUserData().equals("enemyRight")) {
        wallSwitch = false;
    }
    if (fb.getUserData() != null && fb.getUserData().equals("enemyRight")) {
        wallSwitch = false;
    }
}

Dani AI

Generated

Root cause: every enemy is sharing state. In your snippets you both use a single/shared flag for “hit wall” and you construct multiple Enemy objects that point at the same Box2D Body — so when one sensor fires every Enemy sees the same event. was right to suggest per-instance state and a reverseDirection() call, but you also need to stop creating duplicate Enemy wrappers for the same Body and route sensor contacts to the owning Enemy instance.

Fix checklist (practical):

  • Make per-enemy fields non-static (e.g. private boolean facingLeft, private float speed). Do not use a class/static boolean for switching.
  • Create exactly one Enemy instance per Body. Do not do new Enemy(body) twice for the same Body.
  • Attach the Enemy to its Body: body.setUserData(this); so the Body knows its owner.
  • Tag sensor fixtures with an object that references the owner and side, not a shared string. In the ContactListener, look for that tag and call the owner’s method.

Example tag + contact routing (illustrative; not the same code posted earlier):

class SensorTag {
  public final Enemy owner;
  public final boolean left;
  public SensorTag(Enemy owner, boolean left) { this.owner = owner; this.left = left; }
}

// when creating sensor fixture:
// fixture.setUserData(new SensorTag(enemyInstance, true));

public void beginContact(Contact c) {
  Object a = c.getFixtureA().getUserData();
  Object b = c.getFixtureB().getUserData();
  SensorTag tag = (a instanceof SensorTag) ? (SensorTag)a
                 : (b instanceof SensorTag) ? (SensorTag)b : null;
  if (tag != null) tag.owner.reverseDirection();
}

Enemy.reverseDirection() example:

public void reverseDirection() {
  facingLeft = !facingLeft;
  float vx = facingLeft ? -speed : speed;
  body.setLinearVelocity(vx, body.getLinearVelocity().y);
}

Debug tips: log an enemy id or body hash when sensors fire so you see which instance was hit. Verify fixture userData types at runtime (avoid comparing plain strings). These changes route a sensor hit to only its owner and stop the global flip behaviour.

Recommended Answers

All 4 Replies

Maybe wallSwitch needs to be an attribute (instance variable) of the Enemy class, so each Enemy has it's own value for that variable?

order which i am create them.

.. = new contectListern(); // has begincontect() & endcontect() 
....
.. new enemy(); //create enmeies

contectListener class

 class contectListener{
    public void beginContact(Contact contact) {
    ...
    // Enemy switch direction
    if (fa.getUserData() != null && fa.getUserData().equals("enemyLeft")) {
        Enemy.wallSwitch = true;
    }
    ...

 }

I have changed 'wallSwitch' to attribute. so that every enemy has it own 'wallSwitch' variable.

 class Enemy1{
    boolean static wallSwitch = false;
    ....
 }

but I am still getting same problem. every thing look fine to me. unless I am missing some thing

cb639e8559f1930831c55d1aaee2aaa3

I have upload a image to show. what is the problem. on left side of image, tell what is going on and on last frame both enemy stop. on right side of image, explian those thing are.

the enemy(1) is not switching direction.


  • -
    -
    -
    -
    -
-

-
-
-
-
-

in enemy class - logic for switching direction

 public void move() {
        // collion - enemy collsion with wall so switch dir
        if (wallSwitch) {
            if (faceLeft) {
                //move right
                //face right
            } else {
                //move left
                //face left
            }
            wallSwitch = false;
        }
    }

It's hard to see what's going on from those fragments, especially because you seem to have reversed the Java conventions for capitalising names.
So in line 6
Enemy.wallSwitch = true;
what exactly is Enemy and where is it set? It looks like a class name, but the class seems to be named enemy (as if it's a variable)

In your move method why do you have wallSwitch at all? Why not just a reverse direction method like ...

void reverseDirection() {
  if (faceLeft) {
    //move right
    //face right
  } else {
    //move left
    //face left
  }
}

... that you can call when the Enemy hits the boundary. Then your move() method can be simpler - just keep moving in the current direction.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.