1
\$\begingroup\$

I am working on a simple game with topdown movement, but I am unable to get the collisions to work properly. I know the collision detection itself works, but the constraining of the player is where I fail. It gets close to working, but on the corners it still clips into the squares. Also, if I add more squares for the player to collide with, it fails completely. I am programming this game in Processing, which uses Java. Here is my code:

void Collide(float WallX,float WallY,float WallWidth,float WallHeight) {

  this.WallX = WallX;
  this.WallY = WallY;

  this.WallWidth = WallWidth;
  this.WallHeight = WallHeight;

  float TestX = PosX;
  float TestY = PosY;

  if(PosX <= WallX) {
    TestX = WallX;
    CollideLeft();
  }

  if(PosX >= WallX+WallWidth) {
    TestX = WallX+WallWidth;
    CollideRight();
  }

  if(PosY <= WallY) {
    TestY = WallY;
    CollideUp();
  }

  if(PosY >= WallY+WallHeight) {
    TestY = WallY+WallHeight;
    CollideDown();
  }

  fill(255,0,0,150);
  ellipse(TestX,TestY,16,16);

  Dis = sqrt(sq(TestX-PosX) + sq(TestY-PosY));

  println("Dis= ",Dis,", TestX= ",TestX,", PosX= ",PosX,", TestY= ",TestY,", PosY= ",PosY);

}

boolean CollideLeft() {

  if(Dis <= Radius+5) {
    //PosX = WallX-Radius;
    return CollideLeft = true;
  }
  else {
    return CollideLeft = false;
  }

}

boolean CollideRight() {

  if(Dis <= Radius+5) {
    //PosX = WallX+WallWidth+Radius;
    return CollideRight = true;
  }
  else {
    return CollideRight = false;
  }

}

boolean CollideUp() {

  if(Dis <= Radius+5) {
    //PosY = WallY-Radius;
    return CollideUp = true;
  }
  else {
    return CollideUp = false;
  }

}

boolean CollideDown() {

  if(Dis <= Radius+5) {
    //PosY = WallY+WallHeight+Radius;
    return CollideDown = true;
  }
  else {
    return CollideDown = false;
  }

}

void Move() {

  if(MoveRight && !CollideLeft) {
    MoveX(1);
  }
  if(MoveLeft && !CollideRight) {
    MoveX(-1);
  }
  if(MoveDown && !CollideUp) {
    MoveY(1);
  }
  if(MoveUp && !CollideDown) {
    MoveY(-1);
  }

}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

It's hard to tell, but it looks like you are only ever testing for one collision. You need to maintain a list or collection of walls in order to test each one for the collision. That may be why it fails upon adding more walls. Once you have a collection of the walls you would test the player against each one before moving.

One way to solve the overlapping issue is inside of the collision code, calculate an overlap amount. The overlap amount could be calculated for the x by taking the distance between the specific wall currently being tested and the player and then subtracting the wall's width added with the player's width divided by 2. You would take the absolute values of the distance and the entire equation.

$$overlapX=| |distance_{player\rightarrow wall}| - \frac{player_{width}}{2} + \frac{wall_{width}}{2}|$$

In order to use this, you would first move the player in the x, test for collision with each wall, and then for each tested collision add/subtract this overlap. Whether you add or subtract can be determine by whether the player is to the left or right of the wall. To the left, subtract the overlap to push the player out to the left. To the right, add the overlap to push the player out to the right.

For an example, consider if you had a wall at 32,32 with a width and height of 4. The player is at 26,32 with a width and height of 2. The player then moves with a x velocity of 4, placing him at 30,32. Then collisions with walls are tested. The collision with the wall described occurs, and the overlap is calculated to be ||(32 - 30)| - (2 + 1)| = 1. Since the player is to the left of the wall, this overlap is subtracted from the player's position.

This method is not good with dealing with high velocities, as in the above example if the velocity was 7, then the player would end up past the center of the wall, and pushed out the right, thus tunneling through the wall. If you do end up having higher velocities than the half width's/height's of your walls, then you may want to consider breaking the velocity down into "steps" which are of a known safe velocity for all objects in your game, and attempting to move the player in these smaller steps in the same movement function call.

Here's some resources I found helpful:

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

Similar to what I outlined above.

https://www.gamedev.net/articles/programming/general-and-gameplay-programming/swept-aabb-collision-detection-and-response-r3084/

Another way to deal with high speed objects or small walls that is slightly more involved.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .