I am currently trying to make a version of Pong using pygame, but I am having some issues with detecting the collision between the ball and the paddle. I got the detection working with both paddles, but I soon came to realize that the left player cannot move their paddle when the ball collides with it without the ball passing through. The player on the right has no such issue, and keeping the left player still allows the ball to reflect normally.
import pygame, sys
from pygame.locals import *
pygame.init()
pygame.mixer.init()
pygame.font.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
screenx = 1080
screeny = 720
clock = pygame.time.Clock()
for pygame.mouse.get_pos in (screenx, screeny):
pygame.mouse.set_visible(False)
# Blueprint for creating player character
class Player:
# Defines initial conditions for player
def __init__(self):
self.xpos = 0
self.ypos = 0
self.width = 20
self.length = 100
self.speed = 10
self.move = 0
self.upkey = 0
self.downkey = 0
self.score = 0
self.rect = pygame.Rect((self.xpos, self.ypos, self.width, self.length))
# if player character, defines paddle movement
def player_move(self, key):
if key[self.upkey]:
self.ypos -= self.speed
self.move = -1
elif key[self.downkey]:
self.ypos += self.speed
self.move = 1
else:
self.move = 0
# Creates screen boundary for players
def player_boundary(self, key):
if self.ypos == 0:
self.speed = 0
self.move = 0
if key[self.downkey]:
self.speed = 10
self.move = -1
elif self.ypos + self.length == screeny:
self.speed = 0
self.move = 0
if key[self.upkey]:
self.speed = 10
self.move = 1
# Draws player rectangle to surface
def draw(self, surface):
self.rect = pygame.draw.rect(surface, WHITE, (self.xpos, self.ypos, self.width, self.length))
# Blueprint for creating the ball
class Ball:
def __init__(self):
self.size = 15
self.speed = 10
self.vy = 0
self.vx = 10
self.ypos = screeny/2
self.xpos = 100
self.rect = pygame.Rect((self.xpos, self.ypos, self.size, self.size))
# Defines movement of ball (in xy components)
def ball_move(self):
self.ypos += self.vy
self.xpos += self.vx
# method for ball bouncing off of player paddle **
def ball_block(self, player):
if player.move > 0:
self.vy += player.speed * 0.3
self.vx = -((self.speed**2 - self.vy**2) ** .5)
elif player.move < 0:
self.vy = player.speed * -0.3
self.vx = -((self.speed**2 - self.vy**2) ** .5)
elif player.move == 0:
self.vx = -self.vx
# for reflecting off of screen boundaries **
def ball_reflect(self, screeny):
if self.ypos == 0:
self.vy = -self.vy
elif self.ypos == screeny - self.size:
self.vy = -self.vy
# Method for detecting when player has scored
def score(self):
if self.xpos == 0:
self.vx = -self.vx
print ('Score')
elif self.xpos == screenx - self.size:
self.vx = -self.vx
print ('Score')
# Draws ball to surface
def draw(self, surface):
self.rect = pygame.draw.rect(surface, WHITE, (self.xpos, self.ypos, self.size, self.size))
def setup():
# Assigns values to player 1 (left side)
player1 = Player()
player1.xpos = 50
player1.ypos = screeny/1.5
player1.upkey = K_w
player1.downkey = K_s
# Assigns values to player 2 (right side)
player2 = Player()
player2.xpos = screenx - player2.width - 50
player2.ypos = screeny/1.5
player2.upkey = K_UP
player2.downkey = K_DOWN
return player1, player2
# Main loop of the game
def main():
player1, player2 = setup()
ball = Ball()
play = True
while play:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
key = pygame.key.get_pressed()
if key[K_ESCAPE]:
play = False
if ball.rect.colliderect(player1): # For some reason, ball can go through P1 while moving
ball.ball_block(player1)
elif ball.rect.colliderect(player2):
ball.ball_block(player2)
# Had issue with ball going through bottom, fixed by adding screeny to dependencies
if ball.ypos == 0:
ball.ball_reflect(screeny)
elif ball.ypos == screeny - ball.size:
ball.ball_reflect(screeny)
player1.player_move(key)
player2.player_move(key)
ball.ball_move()
# Calls methods for player boundaries and ball scoring
player1.player_boundary(key)
player2.player_boundary(key)
ball.score() # Ball will only score if colliding head on and not on P2's side
# Draws objects to screen
surface.fill(BLACK)
player1.draw(surface)
player2.draw(surface)
ball.draw(surface)
pygame.display.update()
clock.tick(60)
# Sets up screen, calls main loop
surface = pygame.display.set_mode((screenx, screeny))
pygame.display.set_caption('PONG')
main()
As far as I can tell, the code for both players is identical, and yet only one player works in the way I intended it to. Any help would be very much appreciated, and thank you for your time.
EDIT: Fixed by adding a few lines to the ball_block method
def ball_block(self, player):
if player.move > 0:
self.vy += player.speed * 0.3
if self.vx < 0:
self.vx = ((self.speed**2 - self.vy**2) ** .5)
elif self.vx > 0:
self.vx = -((self.speed**2 - self.vy**2) ** .5)
elif player.move < 0:
self.vy = player.speed * -0.3
if self.vx < 0:
self.vx = ((self.speed**2 - self.vy**2) ** .5)
elif self.vx > 0:
self.vx = -((self.speed**2 - self.vy**2) ** .5)
elif player.move == 0:
self.vx = -self.vx
If the player is moving during the collision, you are always setting
so it's always negative