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.
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
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.
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