1
votes

I'm making trying to recreate 'Pong' and I'm struggling to figure out what is wrong with the collision. Here's the code:

ball_x += ball_x_change
    collide = player_collision(player_x, ball_x, player_y, ball_y)
    if collide:
        ball_x -= ball_x_change
    ball(ball_x, ball_y)

This is meant to move the ball from its starting position towards the player and check if the player icon and the ball has collided. If its has, it will change the direction of the ball. It then renders the ball on the screen. Here's the whole thing:

import pygame
import math

pygame.init()

screen = pygame.display.set_mode((800, 600))

pygame.display.set_caption("Pong")

icon = pygame.image.load("ping-pong.png")
pygame.display.set_icon(icon)

player_icon = pygame.image.load("vertical-line.png")
player_x = 800 - (64 + 32)
player_y = 236
player_y_change = 0

cpu_icon = pygame.image.load("vertical-line.png")
cpu_x = 0 - 32
cpu_y = 236
cpu_y_change = 0

ball_icon = pygame.image.load("oval.png")
ball_x = 384
ball_y = 284
ball_x_change = 0.5
ball_y_change = 0

def player(player_x, player_y):
    screen.blit(player_icon, (player_x, player_y))

def cpu(cpu_x, cpu_y):
    screen.blit(cpu_icon, (cpu_x, cpu_y))

def ball(ball_x, ball_y):
    screen.blit(ball_icon,(ball_x, ball_y))

def player_collision(ball_x, ball_y, player_x, player_y):
    bump = math.hypot(player_x - ball_x, player_y - ball_y)
    if bump < 20:
        return True
    else:
        return False

running = True
while running:

    screen.fill((255, 255, 255))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                player_y_change += 1
            if event.key == pygame.K_UP:
                player_y_change -= 1
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN or pygame.K_UP:
                player_y_change = 0

    player_y += player_y_change
    if player_y <= 0:
        player_y = 0
    elif player_y >= 472:
        player_y = 472
    player(player_x, player_y)

    cpu_y += cpu_y_change
    if cpu_y <= 0:
        player_y = 0
    elif player_y >= 472:
        player_y = 472
    cpu(cpu_x, cpu_y)

    ball_x += ball_x_change
    collide = player_collision(player_x, ball_x, player_y, ball_y)
    if collide:
        ball_x -= ball_x_change
    ball(ball_x, ball_y)

    pygame.display.update()

Thanks for your time.

Updated the code and it still doesn't work:

import pygame
import math

pygame.init()

screen = pygame.display.set_mode((800, 600))

pygame.display.set_caption("Pong")

icon = pygame.image.load("ping-pong.png")
pygame.display.set_icon(icon)

player_icon = pygame.image.load("vertical-line.png")
player_x = 672
player_y = 236
player_y_change = 0

cpu_icon = pygame.image.load("vertical-line.png")
cpu_x = 0
cpu_y = 236
cpu_y_change = 0

ball_icon = pygame.image.load("oval.png")
ball_x = 384
ball_y = 284
ball_x_change = 0.8
ball_y_change = 0

def player(player_x, player_y):
    screen.blit(player_icon, (player_x, player_y))

def cpu(cpu_x, cpu_y):
    screen.blit(cpu_icon, (cpu_x, cpu_y))

def ball(ball_x, ball_y):
    screen.blit(ball_icon,(ball_x, ball_y))

def player_collision(ball_x, player_x, ball_y, player_y):
    touch = math.hypot(player_x - ball_x, ball_y - player_y)
    if touch < 10:
        return True
    else:
        return False

running = True
while running:

    screen.fill((255, 255, 255))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                player_y_change += 1
            if event.key == pygame.K_UP:
                player_y_change -= 1
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN or pygame.K_UP:
                player_y_change = 0

    player_y += player_y_change
    if player_y <= 0:
        player_y = 0
    elif player_y >= 472:
        player_y = 472
    player(player_x, player_y)

    cpu_y += cpu_y_change
    if cpu_y <= 0:
        player_y = 0
    elif player_y >= 472:
        player_y = 472
    cpu(cpu_x, cpu_y)

    ball_x += ball_x_change
    collide = player_collision(ball_x, player_x, ball_y, player_y)
    if collide:
        ball_x_change = -ball_x_change
        ball_x += ball_x_change
    ball(ball_x, ball_y)

    pygame.display.update()
2

2 Answers

2
votes

The function player_collision takes its arguments in (ball_x, ball_y, player_x, player_y), but when you call the function, you give the arguments in the wrong order

collide = player_collision(player_x, ball_x, player_y, ball_y)
#should be
collide = player_collision(ball_x, ball_y, player_x, player_y)

You should also do what @RFairey suggested and add ball_x_change *= -1

1
votes

Looks like when collision occurs, you only move the ball back one step in x:

if collide:
    ball_x -= ball_x_change   

To flip its direction you need to negate ball_x_change as well, so that it travels in the other direction after a bounce:

if collide:
    ball_x -= ball_x_change
    ball_x_change = -ball_x_change