1
votes

I'm designing a Pacman clone for a University exam. I use pygame and I have some problems in the handling of the ghosts collisions with the wall.

For example when the ghost collides with the wall on the left side, the left side of the ghost's rectangle takes the value of the right side of the wall's rectangle:

rectGhost.left = blockRect.right

But after multiple collision (on the left of wall) the ghost go over the wall, as if with motion the ghost rectangle overcome the wall and the collision is detected to the left of the wall, and then moves to the left side of the rectangle of the phantom to the right of the wall.

Collision issue example

This is the Ghost's class:

import character, random
from globalVar import *

class ghost(character.character):

    def __init__(self, imgSprite):
        super(ghost, self).__init__(imgSprite)
        self._direction = random.choice([LEFT, RIGHT, UP, DOWN])

    def catch(self, wall):

        # Keep the direction 
        if self._direction ==  LEFT:
            self.moveToLeft()
        if self._direction ==  RIGHT:
            self.moveToRight()
        if self._direction ==  UP:
            self.moveToUp()
        if self._direction ==  DOWN:
            self.moveToDown()


        # Get ghost position
        rectGhost = self.getRectSprite()

        # Collision with wall
        for blockRect in wall:
            if rectGhost.colliderect(blockRect): # Check collision with the wall (wall contain a list of Rect object)

                if self._direction ==  LEFT:
                    rectGhost.left = blockRect.right 
                    self._direction = random.choice([RIGHT, UP, DOWN]) 

                if self._direction ==  RIGHT:
                    rectGhost.right = blockRect.left 
                    self._direction = random.choice([LEFT, UP, DOWN]) 

                if self._direction ==  UP:
                    rectGhost.top = blockRect.bottom 
                    self._direction = random.choice([LEFT, RIGHT, DOWN]) 

                if self._direction ==  DOWN:
                    rectGhost.bottom = blockRect.top 
                    self._direction = random.choice([LEFT, RIGHT, UP]) 

This is the superclass Character :

from globalVar import *

class character:

    def __init__(self, imgSprite):
        self._imageSprite = imgSprite
        self._spriteRect = self._imageSprite.get_rect() 
        self._dimStep = 10 
        self._direction = 0

    def setCharPos(self, charPos): 
        self._spriteRect.centerx = charPos[0]
        self._spriteRect.centery = charPos[1]


    def moveToLeft(self):
        self._spriteRect.x -= self._dimStep 


    def moveToRight(self):
        self._spriteRect.x += self._dimStep


    def moveToUp(self):
        self._spriteRect.y -= self._dimStep


    def moveToDown(self):
        self._spriteRect.y += self._dimStep


    def drawSprite(self):
        WINDOWSURF.blit(self._imageSprite, self._spriteRect)


    def getRectSprite(self):
        return self._spriteRect

    def setDirection(self, direction):
        self._direction = direction

This is the main:

def main():

    thisPacman = pacman.pacman(pacmanCImg) # Ghot obj

    thisGhost_a = ghost.ghost(ghostAImg) # Ghot obj

    thisGhost_o = ghost.ghost(ghostOImg) # Ghot obj

    thisGhost_p = ghost.ghost(ghostPImg) # Ghot obj

    thisGhost_r = ghost.ghost(ghostRImg) # Ghot obj

    # Coords of wall
    wall = thisLevel.getBlocksListPos()

    # Coords of Ghosts
    ghostsStartPos = thisLevel.getGhostsPos()

    # Start pos azure
    thisGhost_a.setCharPos(ghostsStartPos[0])

    # Start pos ghost orange
    thisGhost_o.setCharPos(ghostsStartPos[1])

    # Start pos ghost purple
    thisGhost_p.setCharPos(ghostsStartPos[2])

    # Start pos ghost red
    thisGhost_r.setCharPos(ghostsStartPos[3])

    while running:

        thisGhost_a.catch(wall)
        thisGhost_o.catch(wall)
        thisGhost_p.catch(wall)
        thisGhost_r.catch(wall)

        thisGhost_a.drawSprite()
        thisGhost_o.drawSprite()
        thisGhost_p.drawSprite()
        thisGhost_r.drawSprite()

        pygame.display.update()
        FPSCLOCK.tick(8)

Any ideas? Many thanks for your attention!

2
It might just be your code working a little too well. Say you hit the left well, and then your random direction is still right. After reassigning its position, the left side of your ghost might still be touching the wall, while having the self._direciton being RIGHT. This would make it collide, and then pop to the left side. Check that this isn't happenning, if it is happenning, can fix by just moving it to the right side of the wall, plus a little more to ensure a repeat collision doesnt happen - David Jay Brady
Yeah many thanks @DavidJayBrady! I had already solved but thank you for your explanation. I update the question. - Alessandro_russo

2 Answers

1
votes

The solution is here, Just as David Jay Bredy explained.

Collision with the wall.

        #pdb.set_trace() # Debugging

        for blockRect in wall:
            if rectGhost.colliderect(blockRect): 

                while 1:# Cycle that solve the problem
                    if self._direction ==  LEFT:
                        rectGhost.left = blockRect.right
                        self._direction = random.choice([RIGHT, UP, DOWN])
                        break

                    if self._direction ==  RIGHT:
                        rectGhost.right = blockRect.left
                        self._direction = random.choice([LEFT, UP, DOWN]
                        break

                    if self._direction ==  UP:
                        rectGhost.top = blockRect.bottom
                        self._direction = random.choice([LEFT, RIGHT, DOWN]
                        break 

                    if self._direction ==  DOWN:
                        rectGhost.bottom = blockRect.top
                        self._direction = random.choice([LEFT, RIGHT, UP])
                        break
0
votes

Without being more familiar with your code I'm finding it hard to give you an answer. However, you might try debugging your code from your catch() method:

# Collision with wall
import pdb; pdb.set_trace()

This might give you a bit more information about what is going on.

I've also noticed that your if statements in your catch() method come after the ghost movement. Surely these need to check for a collision before movement is allowed?