I'm trying to code a conveyor belt for a project made with LibGDX and Box2D and I would like to make it like this one from Bomberman Land Touch.
As you can see, the entities standing on it should be able to go in the opposite direction moving slower, the ones not moving should just be transported towards the direction of the belt, and the ones going along its direction should go faster.
For a single direction belt I first detect when the center of an entity's body is inside the block, and then with body.applyLinearImpulse(direction)
I move the body. This is working fine because it's applying a lower impulse than the one that the player uses to move and by checking the center of the entity instead of relying on the collide event, when the body is between two belts, it doesn't receive two impulses. This is the outcome:
I see two problems with that: the obvious one is that since it's checking the center of the body, as soon as it's in a belt with a different direction, it instantly changes direction without going to the center of the block. The other one is that while going backwards in a turn, it does a little "jump" due to the previous impulse.
I also tried to replicate the Bomberman mechanism by diving the corners into two fixtures but the result is quite the same (except a bug where the player doesn't move, probably because the center doesn't touch the next half of the block):
How can I mitigate these two problems or how can I rethink the whole structure/mechanism of the block?
Edit: I tried to implement the first part of @Theraot answer with this code:
if (active) {
for (Entity e : entities) {
// Check if the origin of the entity is inside the block
if (getBody().getFixtureList().get(0).testPoint(e.getOrigin())) {
// Take the x of the entity center if the inputDirection is horizontal, y otherwise
float entityAxis = inputDirection.y == 0 ? e.getOrigin().x : e.getOrigin().y;
// Same for the conveyor block
float blockAxis = inputDirection.y == 0 ? getOrigin().x : getOrigin().y;
Vector2 impulse = null;
// If they are really close
if (Math.abs(blockAxis - entityAxis) < 0.1f) {
impulse = outputDirection;
}
else {
impulse = inputDirection;
}
// Apply the impulse
e.getBody().applyLinearImpulse(impulse, e.getBody().getWorldCenter(), true);
}
}
}
and this is the result.