tags:

views:

79

answers:

1

I've taken an introductory course in Computer Science, but a short while back I decided to try and make a game. I'm having a problem with collision detection. My idea was to move an object, and if there is a collision, move it back the way it came until there is no longer a collision. Here is my code:

class Player(object):  
    ...  
    def move(self):
        #at this point, velocity = some linear combination of (5, 0)and (0, 5)
        #gPos and velocity are types Vector2    
        self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)
        self.gPos += self.velocity  
        while CheckCollisions(self):  
            self.gPos -= self.velocity/n #see footnote  
            self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)
    ...
def CheckCollisions(obj):
    #archList holds all 'architecture' objects, solid == True means you can't walk        
    #through it. colliderect checks to see if the rectangles are overlapping
    for i in archList:
        if i.solid:
            if i.hitBox.colliderect(obj.hitBox):
                return True
    return False

*I substituted several different values for n, both integers and floats, to change the increment by which the player moves back. I thought by trying a large float, it would only move one pixel at a time

When I run the program, the sprite for the player vibrates very fast over a range of about 5 pixels whenever I run into a wall. If I let go of the arrow key, the sprite will get stuck in the wall permanently. I wondering why the sprite is inside the wall in the first place, since by the time I blit the sprite to the screen, it should have been moved just outside of the wall.

Is there something wrong with my method, or does the problem lie within my execution?

+1  A: 

Looks like you're setting the hitbox BEFORE updating the position. The Fix seems simple.

Find:

    self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)
    self.gPos += self.velocity  

Replace:

    self.gPos += self.velocity  
    self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)

Other Suggestions: What you should do is check the position BEFORE you move there, and if it's occupied, don't move. This is untested so please just use this as psuedocode intended to illustrate the point:

class Player(object):  
    ...  
    def move(self):
        #at this point, velocity = some linear combination of (5, 0)and (5, 5)
        #gPos and velocity are types Vector2    
        selfCopy = self
        selfCopy.gPos += self.velocity
        selfCopy.hitBox = Rect(selfCopy.gPos.x, selfCopy.gPos.y, 40, 40)
        if not CheckCollisions(selfCopy)    
            self.gPos += self.velocity
    ...
def CheckCollisions(obj):
    #archList holds all 'architecture' objects, solid == True means you can't walk        
    #through it. colliderect checks to see if the rectangles are overlapping
    for i in archList:
        if i.solid:
            if i.hitBox.colliderect(obj.hitBox):
                return True
    return False
Mike Sherov
Hmm, that's odd. I actually caught that bug before I posted this. I don't know how that bug made it into the browser. I was originally going to do what you suggested (projecting the hitBox into the new position and then checking), but if there was something in the way, I wanted to move up against it instead of not moving at all. I afraid that the process of moving towards the wall is almost identical as moving out, and that I'll have the same problem when I make this change. I'll try this in the meantime, though.
Kevin
Disregard my first comment. There are two instances of those two lines. I had corrected the second one, but not the first. It's working perfectly now, thank you!
Kevin
@Kevin, I suggest you make a function that encapsulates changing position and updating the hotbox at the same time so that way you don't have to change it in multiple places. Also, you can you my look ahead to still move the character right up against the wall without the flicker. Just add incremental distance from the projection instead of subtracting from the overshot.
Mike Sherov