3

I'm fairly new to python and I'm trying to build a game with Pygame. I kept having issues with collisions not being recognized. Here's the code I tried

import pygame
pygame.init()

WIDTH, HEIGHT = (900, 500)
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Bong Pong')

FPS = 60
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BORDER = pygame.Rect(WIDTH// 2 -5, 0, 10, HEIGHT)
VEL = 3
PLAYER_HEIGHT = 50
PLAYER_WIDTH = 15
BALL_HEIGHT = 15
BALL_WIDTH = 15


def draw_window(player_1, player_2, game_ball):
    WIN.fill(WHITE)
    pygame.draw.rect(WIN, BLACK, BORDER)
    pygame.draw.rect(WIN, BLACK, player_1)
    pygame.draw.rect(WIN, BLACK, player_2)
    pygame.draw.rect(WIN, RED, game_ball)
    pygame.display.update()


def player_1_movement(keys_pressed, player_1):
    if keys_pressed[pygame.K_w] and player_1.y - VEL > 0:
        player_1.y -= VEL
    if keys_pressed [pygame.K_s] and player_1.y + PLAYER_HEIGHT + VEL < 500:
        player_1.y += VEL
    
def player_2_movement(keys_pressed, player_2):
    if keys_pressed[pygame.K_UP] and player_2.y - VEL > 0:
        player_2.y -= VEL
    if keys_pressed [pygame.K_DOWN] and player_2.y + PLAYER_HEIGHT + VEL < 500:
        player_2.y += VEL


def player_collision(player_1, player_2, game_ball, ball_vel_x): 
    if game_ball.colliderect(player_1) or game_ball.colliderect(player_2):
        ball_vel_x *= -1
        
   
        
    
    

def main(): 
    clock = pygame.time.Clock()
    run = True

    player_1 = pygame.Rect(50, HEIGHT//2 - PLAYER_HEIGHT// 2, PLAYER_WIDTH, PLAYER_HEIGHT)
    player_2 = pygame.Rect(850, HEIGHT//2 - PLAYER_HEIGHT// 2, PLAYER_WIDTH, PLAYER_HEIGHT)
    game_ball = pygame.Rect(50 + PLAYER_WIDTH, HEIGHT//2 - BALL_HEIGHT// 2, BALL_WIDTH, BALL_HEIGHT)
    ball_vel_y = 2
    ball_vel_x = 2
    while run:
        clock.tick(FPS)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False 
                pygame.QUIT()
            
        keys_pressed = pygame.key.get_pressed()
        player_1_movement(keys_pressed, player_1)
        player_2_movement(keys_pressed, player_2)
        draw_window(player_1, player_2, game_ball)
        
        if game_ball.y - BALL_HEIGHT - VEL <= 0 or game_ball.y + BALL_HEIGHT + VEL >= 500:
            ball_vel_y *= -1
        
        game_ball.y -= ball_vel_y

      
        player_collision(player_1, player_2, game_ball, ball_vel_x)
         

        game_ball.x += ball_vel_x


    main()

if __name__ == '__main__':
    main()
     

I've also tried putting the

game_ball.x += ball_vel_x

in the player_collsion function but it doesn't reverse it properly.

I've already solved the issue by putting the entire player_collision function code inside the main function like so


def main(): 
    clock = pygame.time.Clock()
    run = True

    player_1 = pygame.Rect(50, HEIGHT//2 - PLAYER_HEIGHT// 2, PLAYER_WIDTH, PLAYER_HEIGHT)
    player_2 = pygame.Rect(850, HEIGHT//2 - PLAYER_HEIGHT// 2, PLAYER_WIDTH, PLAYER_HEIGHT)
    game_ball = pygame.Rect(50 + PLAYER_WIDTH, HEIGHT//2 - BALL_HEIGHT// 2, BALL_WIDTH, BALL_HEIGHT)
    ball_vel_y = 2
    ball_vel_x = 2
    while run:
        clock.tick(FPS)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False 
                pygame.QUIT()
            
        keys_pressed = pygame.key.get_pressed()
        player_1_movement(keys_pressed, player_1)
        player_2_movement(keys_pressed, player_2)
        draw_window(player_1, player_2, game_ball)
        
        if game_ball.y - BALL_HEIGHT - VEL <= 0 or game_ball.y + BALL_HEIGHT + VEL >= 500:
            ball_vel_y *= -1
        
        game_ball.y -= ball_vel_y

        if game_ball.colliderect(player_1) or game_ball.colliderect(player_2):
            ball_vel_x *= -1


        game_ball.x += ball_vel_x


    main()

and this works exactly how I want it I just want to clear up my understanding of why this function wouldn't work properly if just called in the main function instead of putting it directly in.

1
  • 1
    why are you calling main from main? Commented Sep 6, 2022 at 19:40

1 Answer 1

6

Python has no concept of in-out parameters. The argument is passed by value. If you change ball_vel_x in the player_collision function, only the parameter changes, but the argument remains unchanged. You must return the new value of ball_vel_x from the function:

def player_collision(player_1, player_2, game_ball, ball_vel_x): 
    if game_ball.colliderect(player_1) or game_ball.colliderect(player_2):
        ball_vel_x *= -1
    return ball_vel_x 
def main():
    # [...]

    while run:
        # [...]

        ball_vel_x = player_collision(player_1, player_2, game_ball, ball_vel_x)

        # [...]

Another possibility is to store the velocity in an object (e.g. gyame.math.Vector2). A variable stores a reference to an object, so you can change the object's attributes in the function if the variable is an argument of the function call:

def player_collision(player_1, player_2, game_ball, ball_vel): 
    if game_ball.colliderect(player_1) or game_ball.colliderect(player_2):
        ball_vel.x *= -1 


def main(): 
    # [...]

    ball_vel = pygame.math.Vector2(2, 2)
    
    while run:
        # [...]
        
        if game_ball.y - BALL_HEIGHT - VEL <= 0 or game_ball.y + BALL_HEIGHT + VEL >= 500:
            ball_vel.y *= -1
        
        game_ball.y -= ball_vel.y
        player_collision(player_1, player_2, game_ball, ball_vel)
        game_ball.x += ball_vel.x
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.