Search code examples
pythonpygamepong

Debugging ping pong game in Python


I'm tired, and I've tried to run this all day. IT's a game of pong where the ball bounces off the wall and comes into contact with the user's "Slab" or paddle. I've treid to debug for a while, and turns out my iCollide and the iGet_Velocity parts have been causing a lot of issues.

from livewires import games, color
games.init (screen_width = 640, screen_height = 480, fps = 50)

class Ball (games.Sprite):
    def update (self):
        if self.right>544:
            self.dx = -self.dx
        if self.top > 11 or self.bottom > 470:
            self.dy = -self.dy
        if self.left < 0:
            self.iLost()

    def iLost (self):
        games.Message (screen = self.screen,
                       x = 340,
                       y = 240,
                       text = "Game Over",
                       size = 90,
                       color = color.red,
                       lifetime = 250,
                       after_death = self.screen.quit)                       

    def ihandle_collision (self):
        new_dx, new_dy = Slab.iVelocity()
        self.dx += self.dx + new_dx  #For handling collision, must take velocity of the mouse object and put add it to the velocity of the ball.
        self.dy += self.dy + new_dy

class Slab (games.Sprite):
    def update (self):
        self.x = games.mouse.x
        self.y = games.mouse.y
        self.iCollide()

    def iCollide (self):
        for Ball in self.overlapping_sprites:
            Ball.ihandle_collision()

    def iVelocity (self):
        self.get_velocity()


def main():
    #Backgrounds
    pingpongbackground = games.load_image ("pingpongbackground.jpg", transparent = False)
    games.screen.background = pingpongbackground
    #Ball: Initializing object and setting speed.
    ballimage = games.load_image ("pingpongball.jpg", transparent = True)
    theball = Ball (image = ballimage,
                    x = 320,
                    y = 240,
                    dx = 2,
                    dy = 2)
    games.screen.add(theball)
    #Paddle: Initializing ping pong object and setting initial poisition to the initial mouse position
    slabimage = games.load_image ("pingpongpaddle.jpg", transparent = True)
    theslab = Slab (image = slabimage,
                    x = games.mouse.x,
                    y = games.mouse.y)
    games.screen.add(theslab)
    games.mouse.is_visible = False
    games.screen.event_grab = True
    games.screen.mainloop()

main ()

Solution

  • Well, without having some more data, I can't say for certain what is wrong. But it looks like your collision response code is a bit screwy. For example, in the first section you should do this to handle your boundary conditions properly:

    def update (self):
        if self.right>544 and self.dx > 0:
            self.dx = -self.dx
        if (self.top > 11 and self.dy < 0) or (self.bottom > 470 and self.dy > 0):
            self.dy = -self.dy
        if self.left < 0:
            self.iLost()
    

    Also your collision response code is a bit wonky. This is untested, but it does approximately the right thing: (EDIT: Rewrote this with more comments so that it would be more clear)

    def iCollide (self):
        for Ball in self.overlapping_sprites:
    
            #Extract the components of the slab's velocity
            slab_vx, slab_vy = self.iVelocity()
    
            #Compute relative components of slab velocity
            rel_vx, rel_vy = Ball.dx - slab_vx, Ball.dy - slab_vy
    
            #Determine the time of intersection and the normal direction
            #This is done to compute which face the ball hits
            #Initially suppose that the objects intersect at t=infinity
            t, nx, ny = 100000, 0, 0
    
            #Check left/right faces
            if rel_vx != 0:
                #Check if ball hits left face
                toi = (self.left - Ball.right) / rel_vx
                if toi < t:
                    t, nx, ny = toi, -1, 0
    
                #Check if ball hits right face
                toi = (self.right - Ball.left) / rel_vx
    
                if toi < t:
                    t, nx, ny = toi, 1, 0
    
            #Check top/bottom faces:
            if rel_vy != 0:
    
                #Check if ball hits top face
                toi = (self.top - Ball.bottom) / rel_vx
                if toi < t:
                    t, nx, ny = toi, 0, -1
    
                #Check if ball hits right face
                toi = (self.bottom - Ball.top) / rel_vx
                if toi < t:
                    t, nx, ny = toi, 0, 1
    
            #Check if impact force properly corrects velocity
            if Ball.dx * nx + Ball.dy * ny < 0:
    
                #Reflect the ball's position
                Ball.dx += Ball.dx * nx * 2.0
                Ball.dy += Ball.dy * ny * 2.0
    
            #Check if cursor movement is not pushing ball into paddle:
            if slab_vx * nx + slab_vy * ny < 0:
                Ball.dx += slab_vx
                Ball.dy += slab.vy
    

    What you should try to do is find which face of the slab the ball intersects, then reflect the balls velocity according to that direction. Now this code is by no means tested, since I couldn't get your example to run. However it should give you an idea of what the correct solution ought to do.