Kevin
Kevin

Reputation: 13

Problem with 2D collision detection from beginner

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?

Upvotes: 1

Views: 1467

Answers (1)

Mike Sherov
Mike Sherov

Reputation: 13427

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

Upvotes: 1

Related Questions