1

Detecting collision between two rectangles has been very simple, however making sure they don't collide for walls in a 2d game has been quite difficult. I've managed it but it's buggy and requires about 14 if statements per tick to prevent the player from passing through a wall.

if wall_bottom > entity_top and wall_top < entity_bottom:  # is player between y min and max
    if entity_left >= wall_right - entity.max_velocity:  # is the player on the right side of the box (in or out)
        if (entity_left + entity.x_velocity) < wall_right:  # will the player be past the right side
            if entity.x_velocity < 0:  # is the player's velocity heading left (into right side)
                entity.x = wall_right  # x coord changed to edge of wall
                entity.x_velocity = 0  # velocity reset, wall stops player
    elif entity_right <= wall_left + entity.max_velocity and \
            (entity_right + entity.x_velocity) > wall_left and \
            entity.x_velocity > 0:
        entity.x = wall_left - entity.x_length
        entity.x_velocity = 0
if wall_right > entity_left and wall_left < entity_right:  # is player between x min and max
    if entity_top >= wall_bottom - entity.max_velocity and \
            (entity_top + entity.y_velocity) < wall_bottom and \
            entity.y_velocity < 0:
        entity.y = wall_bottom
        entity.y_velocity = 0
    elif entity_bottom <= wall_top + entity.max_velocity and \
            (entity_bottom + entity.y_velocity) > wall_top and \
            entity.y_velocity > 0:
        entity.y = wall_top - entity.y_length
        entity.y_velocity = 0

I defined the edges of all the entities and check if the player will be colliding one frame into the future and then set the coordinates to the side of the box the player is on. This solution is inelegant and has had many bugs. I've been trying to come up with a better solution but can't seem to find a simple way to do it. Am I missing something obvious?

Aeolus
  • 996
  • 1
  • 8
  • 22
  • Check out: https://gamedev.stackexchange.com/questions/586/what-is-the-fastest-way-to-work-out-2d-bounding-box-intersection – Jacob G. Jul 10 '17 at 14:27
  • Thanks, but I'm looking to prevent collision. Detecting collision between rectangles is easy, I'm not looking for that. – Aeolus Jul 10 '17 at 14:35
  • I've posted a complete example [here](https://stackoverflow.com/questions/40966994/pygame-sprite-wall-collision/45017561#45017561). – skrx Jul 10 '17 at 16:49
  • If collisions are easy to detect, make a rectangle around your player and if that rectangle collides, you know it before the player would collide. Just a thought. – bstipe Jul 10 '17 at 19:56
  • I have tried something similar to check 1 frame into the future based on current velocity. The problem with that is with variable speed, the player won't collide at the same place every time. Player could be 5 px away from box and travelling 10px/s, it will stop you there. Or player could be 9 px away from box and travelling 10px/s and it will stop you there. Thanks everyone for the advice still trying to figure it out. – Aeolus Jul 11 '17 at 15:31

1 Answers1

0

Since your code is very particular for your project, i'm going to help you with this concept and then you can apply it to your program. One way to do it is to compare the position of the player with the position of the edge inside the move function, lets say you have something like this:

class Player:       

def __init__(self): # The player born in a random place of X
    self.x = random.randomrange(0, WIDTH)      

def move_x(self): # The player moves left,right, or doesn't move. its random
    self.x = self.x + random.randomrange(-1, 2)

    if self.x < 0:
        self.x = 0 # If the player is going to collide with the left wall
                   # we put him again on the edge

    elif self.x > WIDTH: # If the player is going to collide with the right
        self.x = WIDTH   # wall, we put him again on the edge

you can see that the conditionals are inside the move function, by doing this, the player is never going to collide with the wall because the move function itself is checking that the player's position never match the position of the wall, or whatever obstacle you want to avoid, including other players.

José Garcia
  • 136
  • 9
  • This is essentially what I was doing in my code, sorry if it was too complicated to understand. When you add more sides, acceleration, and velocity it becomes more complicated but I was setting the player coordinates to the edge of the wall they were on. – Aeolus Jul 10 '17 at 14:42
  • Sorry again, I just realized my wording was confusing. I'm looking for general collision between any two rectangles. So a player is unable to collide with a box in the middle of the screen with 4 sides. Not interested in the edge of the screen. – Aeolus Jul 10 '17 at 14:45
  • You just have to apply the same principle, but now you need to compare the position of the player with the position of the boxes, assuming the boxes are also objects you can easily access their current position, even if the position change over time. I havent check this entire code, but it seems like it can help you [link](https://inventwithpython.com/chapter18.html) – José Garcia Jul 10 '17 at 14:55
  • That is what my current code does. The problem is it is too complicated due to direction, velocity, and acceleration. Thanks for your help. Your code is where I started but it got my complicated as I fixed problems. – Aeolus Jul 10 '17 at 14:59
  • Im sorry i could'nt be more helpful, one way to avoid complications is to make functions for almost everything i.e: detectCollision(), stopPlayer(), etc. So you end up with a very readable code and also you can check which function is causing the game to crash instead of reviewing a huge piece of code. Good luck with your project. – José Garcia Jul 10 '17 at 15:05
  • Thank you. I appreciate the help. – Aeolus Jul 10 '17 at 15:07