1

I have been trying to add collision detection for a while now and just can't seem to do it..

To draw my map I'm just using x,y coords:

from setup import *

treeload = "Images/tree.jpg"
tree = pygame.image.load(treeload).convert_alpha()

class drawtree:

     def __init__(self, x, width, step1, y, height, step2):

        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.step1 = step1
        self.step2 = step2

    def draw(self):

        for x in range(self.x, self.x+self.width, self.step1):
            for y in range(self.y, self.y+self.height, self.step2):
                window.blit(tree, (x,y))

t1 = drawtree(100, 100, 20, 0, 90, 30)
t2 = drawtree(400, 300, 20, 0, 90, 30)
t3 = drawtree(100, 270, 20, 450, 150, 30)
t4 = drawtree(400, 300, 20, 450, 150, 30)

trees = [t1, t2, t3 ,t4]

Using this method I came up with this detection:

from setup import *
from drawtree import *
from player import *

def wall_detect(x1, y1, w1, h1, x2, y2, w2, h2):
    if (x2+w2>=x1>=x2 and y2+h2>=y1>=y2):
        return True
    elif (x2+w2>=x1+w1>=x2 and y2+h2>=y1>=y2):
        return True
    elif (x2+w2>=x1>=x2 and y2+h2>=y1+h1>=y2):
        return True
    elif (x2+w2>=x1+w1>=x2 and y2+h2>=y1+h1>=y2):
        return True
    else:
        return False

I have been trying to use for loops to loop through trees to detect if player (a rectangle) crosses into the trees but I cant think of anything.

I've tried

    for i in trees:
        collision = wall_detect(player.x, player.y, player.width, player.height, i.x, i.y, i.width, i.height)
    player.update(collision)

player.update(collision) changes the rectangle to red if collision = true and leaves it black if false.

I've tried using for and if e.g:

for i in trees:
        if wall_detect(player.x, player.y, player.width, player.height, i.x, i.y, i.width, i.height) == wall_detect(player.x, player.y, player.width, player.height, t1.x, t1.y, t1.width, t1.height):
            collision = wall_detect(player.x, player.y, player.width, player.height, t1.x, t1.y, t1.width, t1.height)
           player.update(collision)

        if wall_detect(player.x, player.y, player.width, player.height, i.x, i.y, i.width, i.height) == wall_detect(player.x, player.y, player.width, player.height, t2.x, t2.y, t2.width, t2.height):
            collision = wall_detect(player.x, player.y, player.width, player.height, t2.x, t2.y, t2.width, t2.height)
            player.update(collision)

etc.. but that doesn't work, it only for with 1 if statement and the rest commented out.

2
  • Does collision work correctly for tree #4? Commented May 8, 2014 at 19:21
  • use tuples, this will make it much more clear Commented May 8, 2014 at 20:07

1 Answer 1

2

One problem is with the nature of this loop:

for i in trees:
    collision = wall_detect(player.x, player.y, player.width, player.height, i.x, i.y, i.width, i.height)
player.update(collision)

Suppose the player collides with the first tree in trees. Then collision will be True, but the for loop continues. So collision will only end up being True if the player is colliding with the last tree in your list. There are multiple ways to fix this.

# Change the assignment to check if it is already true
collision = False
for i in trees:
    collision = collision or wall_detect(...

or

# Exit the loop if it is true
for i in trees:
    collision = wall_detect(...)
    if collision:
        break

or

# Turn it into a function that returns when it is true
def walls_detect(player, trees):
    for tree in trees:
        if wall_detect(...):
            return True
    return False

...
# Call it like this
player.update(walls_detect(player, trees))

Your logic for when collisions occur looks right to me, though it can also be simplified quite a bit:

def wall_detect(x1, y1, w1, h1, x2, y2, w2, h2):
    return (x2+w2>=x1>=x2 or x2+w2>=x1+w1>=x2) and (y2+h2>=y1>=y2 or y2+h2>=y1+h1>=y2)
Sign up to request clarification or add additional context in comments.

5 Comments

And from the point of view of a someone playing your game, you should consider changing >= into > to make collision detection slightly more lenient.
I am getting slightly confused. I understand where you are going but not sure where to fill in the gaps. Are you redefining wall_detect to the last definition below or in your main block under the for loop. If you are redefining wall_detect to the for loop returning true, what are you putting in as the parameters?
@Matt I was giving you three different options on how to fix it. I've made that a little more clear now. The easiest way to fix it would be the first option, where you change the collision = ... line to be collision = collision or ... and initialize collision to be False.
Ah yeah that makes much more sense now! I did option 2 (for loop) and it works perfectly. Out of question.. which if the 'best' way to run this out of what you said? Would this code be easily modified to make it so player stops when wall_detection returns true?
I don't think there really is a "best" way. All three options work, it's just a matter of what you feel looks best in your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.