Function not being called in main function

Question:

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.

Asked By: Johnnathon

||

Answers:

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
Answered By: Rabbid76
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.