3
votes

I'm pretty new to Python and PyGame. I have made a ball and two paddles ( The two paddle's are controlled by 2 players ). My issue is when the ball hits player 2's paddle, it doesn't bounce off. The problem is at the bottom of the code where there's a comment saying: #WITH PLAYER 2.

# IMPORTS
import pygame, time;

# INIT PYGAME
pygame.init();

# GLOBALS
global screen, display_w, display_h;
global clock, FPS;
global gameOver;
global ball, player_1, player_2;

# ASSIGN GLOBALS
def assign_globals():
    global screen, display_w, display_h;
    global clock, FPS;
    global gameOver;
    global ball, player_1, player_2;

    display_w = 800;
    display_h = 600;
    screen = pygame.display.set_mode((display_w, display_h));

    clock = pygame.time.Clock();
    FPS = 60;

    gameOver = False;

    ball = Ball();
    player_1 = Player();
    player_1.x = 0;
    player_1.color = (255, 0, 0);
    player_2 = Player();
    player_2.x = display_w - 15;
    player_2.color = (0, 255, 0);

# MAIN
def main():
    assign_globals();
    setup();
    game_loop();
    set_fps();

# GAME LOOP
def game_loop():
    global gameOver;

    while(not gameOver):
        for event in pygame.event.get():
            if(event.type == pygame.QUIT):
                gameOver = True;

            if(event.type == pygame.KEYDOWN):
                # PLAYER 1
                if(event.key == pygame.K_w):
                    player_1.velY -= 1;
                if(event.key == pygame.K_s):
                    player_1.velY += 1;
                # PLAYER 2
                if(event.key == pygame.K_UP):
                    player_2.velY -= 1;
                if(event.key == pygame.K_DOWN):
                    player_2.velY += 1;

            if(event.type == pygame.KEYUP):
                # PLAYER 1
                if(event.key == pygame.K_w or event.key == pygame.K_s):
                    player_1.velY = 0;
                # PLAYER 2
                if(event.key == pygame.K_UP or event.key == pygame.K_DOWN):
                    player_2.velY = 0;

        draw();
        animate();
        collision();

# DRAW
def draw():
    global screen;

    screen.fill((0, 0, 0));
    ball.draw();
    player_1.draw();
    player_2.draw();

    pygame.display.update();

# ANIMATE
def animate():
    ball.animate();
    player_1.animate();
    player_2.animate();

# COLLISION
def collision():
    ball.collision();
    player_1.collision();
    player_2.collision();

# SETUP
def setup():
    pygame.display.set_caption("Pong");

# CLASSES
class Ball():
    def __init__(self, x=0, y=0, w=0, h=0, velX=0, velY=0, color=()):
        global display_w, display_h;

        self.x = display_w / 2;
        self.y = display_w / 2;
        self.w = 20;
        self.h = 20;
        self.color = (0, 0, 255);
        self.velX = 0.4;
        self.velY = 0.4;

    def reset(self):
        self.x = display_w / 2;
        self.y = display_w / 2;
        self.velX = 0.4;
        self.velY = 0.4;

    def draw(self):
        global screen;

        pygame.draw.ellipse(screen, self.color, (self.x, self.y, self.w, self.h));

    def animate(self):
        self.x += self.velX;
        self.y += self.velY;

    def collision(self):
        global display_w, display_h;

        # WITH WALL
        if(self.x >= display_w - self.w):
            self.reset();
        if(self.x <= 0):
            self.reset();
        if(self.y >= display_h - self.h):
            self.velY *= -1;
        if(self.y <= 0):
            self.velY *= -1;

        # WITH PLAYER 1
        if(self.x <= player_1.x + player_1.w and
            self.x >= player_1.x and
            self.y >= player_1.y and
            self.y <= player_1.y + player_1.h):
                ball.velX *= -1;

        # WITH PLAYER 2
        if(self.x <= player_2.x + player_2.w and
            self.x >= player_2.x and
            self.y >= player_2.y and
            self.y <= player_2.y + player_2.h):
                ball.velX *= -1;

class Player():
    def __init__(self, x=0, y=0, w=0, h=0, velY=0, color=()):
        global display_w, display_h;

        self.w = 15;
        self.h = 100;
        self.x = color;
        self.y = display_h / 2 - self.h / 2;
        self.velY = 0;
        self.color = color;

    def draw(self):
        global screen;

        pygame.draw.rect(screen, self.color, (self.x, self.y, self.w, self.h));

    def animate(self):
        self.y += self.velY;

    def collision(self):
        global display_h;

        # WITH WALL
        if(self.y + self.h > display_h):
            self.velY = 0;
        elif(self.y < 0):
            self.velY = 0;


# SET FPS
def set_fps():
    global clock, FPS;

    clock.tick(FPS);

# CALL MAIN
if(__name__ == "__main__"):
    main();

# QUIT
pygame.quit();
quit();
1
In python you don't have to end statements with ;, and even if it is allowed it's generally discouraged. The same applies to parenthesis around the condition in if statements. And don't be afraid to use elif in the event loop where the event can only be one type and have one key each iteration. Lastly, try to keep your naming consistent so you don't use lowercase_and_underscore for some variables and camelCase for others. These are just general conventions (PEP8) used to make code more readable between programmers. - Ted Klein Bergman

1 Answers

0
votes

The problem seems to be that you are basing collision detection on the upper-left corner of the ball's rectangle. The left paddle is against the left side, so that's (not accurate but usually) not so bad, but the right paddle is against the right side, so the left corner of the ball rectangle will only be inside the paddle of player 2 when the ball has already penetrated the paddle, and at that point, the wall detection routine (which comes before the paddle detection) will trigger a reset, because it scored.

So player 2's paddle is made irrelevant, since it detects the far corner, and any time it would detect a collision, it detects a score instead and resets the ball position before it tests for a collision.

So, you need to take into account the whole shape of the ball, or at least make the detection point symmetrical. If you use the center point, it'll be fair, but it'll also miss on the edges of the ball. Ideally you could do a test whether the paddle intersects the ball's ellipse.