Collisions in python ping pong game [duplicate] - python

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to make ball bounce off wall with PyGame?
(1 answer)
Closed 1 year ago.
So, im having this trouble with collisions in my pygame Python Ping-pong game. Exactly in that fragment of code
#computer
if (x_ball > (x*9) and x_ball < (x*9)+15) and (y_ball < y+55 and y_ball > y-55):
print(f"col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
So it is basic computer movement, repeating the y position of ball. But when i implemented AI movement, ball is going through the computer pallete, sometimes bouncing away. How to make it right? I lost my mind tbh.
import pygame
from pygame.constants import DROPTEXT
pygame.init()
#window
w_width = 1000
w_height = 600
screen = pygame.display.set_mode((w_width, w_height))
clock = pygame.time.Clock()
open = True
#player
x,y = 100,250
#define player action variables
speed = 5
speed_x,speed_y = -5,3
moving_down = False
moving_up = False
#define ball action variables
x_ball,y_ball = 500,250
radius = 10
class palette(pygame.sprite.Sprite):
global x,y
def __init__(self, x, y, speed):
self.speed = speed
pygame.sprite.Sprite.__init__(self)
self.player_rect = pygame.Rect(x,y,30,100)
def draw(self):
pygame.draw.rect(screen, 'White', self.player_rect)
def move(self, moving_up, moving_down):
#reset movement variables
global dy
dy = 0
#assing movement variables if moving up or down
if moving_up:
dy = -self.speed
if moving_down:
dy = self.speed
#update pallete possition
self.player_rect.y += dy
class EnemyPalette(pygame.sprite.Sprite):
global x,y
def __init__(self, x, y, speed):
self.speed = speed
pygame.sprite.Sprite.__init__(self)
self.enemy_rect = pygame.Rect(x,y,30,100)
def draw(self):
pygame.draw.rect(screen, 'White', self.enemy_rect)
#ai move
def move(self, speed,x_ball,y_ball):
self.speed = speed
self.x_ball = x_ball
self.y_ball = y_ball
global dy
dy = 0
dy = y_ball-50
#update enemy pallete possition
self.enemy_rect.y = dy
def ball():
global speed_x,speed_y,x_ball,y_ball
#update pos of bal
x_ball += speed_x
y_ball += speed_y
#basic colision with screen
y = player.player_rect.y
x = player.player_rect.x
#turn off left and right collisions
# if x_ball>=w_width-(0.5*radius) or x_ball <=0+(0.5*radius):
# speed_x*=-1
if y_ball>=w_height-(0.5*radius) or y_ball <=0+(0.5*radius):
speed_y*=-1
#set ball on middle when crosses screen
if x_ball>=w_width or x_ball<=0:
x_ball=500
#collision with pallettes
#player
if (x_ball < x+30 and x_ball > x) and (y_ball < y+120 and y_ball > y):
print(f"left paddle col at x={x_ball} y= {y_ball}")
x_ball = x+30
speed_x*=-1
#computer
if (x_ball > (x*9) and x_ball < (x*9)+15) and (y_ball < y+55 and y_ball > y-55):
print(f"right paddle col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
pygame.draw.circle(screen, (255,255,255), (x_ball,y_ball), radius, 5)
return x_ball,y_ball
#ai movement
#build players and enemies
player = palette(x,y, speed)
enemy = EnemyPalette(x*9,y,speed)
#game
while open:
for event in pygame.event.get():
#quit game
if event.type == pygame.QUIT:
open = False
#keyboard presses
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
moving_up = True
if event.key == pygame.K_s:
moving_down = True
if event.key == pygame.K_ESCAPE:
open = False
#keyboard button released
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
moving_up = False
if event.key == pygame.K_s:
moving_down = False
screen.fill((0,0,0))
clock.tick(60)
pygame.display.flip
#init players
player.draw()
enemy.draw()
player.move(moving_up, moving_down)
enemy.move(speed,x_ball,y_ball)
ball()
pygame.display.update()

You have to test against the enemy rectangle. Get the x and y coordinate form the enemy rectangle before the collision test:
y = enemy.enemy_rect.y
x = enemy.enemy_rect.x
if (x_ball > x and x_ball < x+15) and (y_ball < y+100 and y_ball > y):
print(f"right paddle col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
Simplify the code with chained Comparisons:
y = enemy.enemy_rect.y
x = enemy.enemy_rect.x
if x < x_ball < x+15 and y < y_ball < y+100:
# [...]
Or even better pygame.Rect.collidepoint:
if enemy.enemy_rect.collidepoint(x_ball, y_ball):
# [...]
I recommend reading How do I detect collision in pygame? and Sometimes the ball doesn't bounce off the paddle in pong game.

Related

My Simple Platformer Character Drifts Left but not Right and I Can't Find the Bug That Causes It [duplicate]

This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Simple drag physics, acting differently when moving left or right [duplicate]
(1 answer)
Closed 2 years ago.
Basically I am working on a simple platformer and I have all of the basics like the gravity, acceleration, and platforms, but for some reason the character will decelerate going right, but when it goes left it will continue moving slowly instead of stopping. I even printed the value of my variable "changeX" to see what was going on, and it showed me the values I that should be happening rather than what was displayed. Sorry my comments are very limited in their helpfulness. The code regarding variables rect.x , changeX, and accelX are likely the most relevant.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
COLOR = BLUE
#Top Speed
tSpeedX = 7
tSpeedY = 20
#gravity constant
gConstant = 1
#acceleration X variable
accelX = 0
#acceleration Y variable
accelY = 0
#whether you can jump or not
jumpB = True
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
#iniatilized values for rect
self.image = pygame.Surface([50, 50])
self.image.fill(COLOR)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.changeX = 0
self.changeY = 0
self.walls = None
#the velocity function. X and Y values are assigned based on the accelX
#and Y constants and added to the points of the rectangle
def velocity(self,x,y):
#change in speed
self.changeX += x
self.changeY += y
if abs(self.changeX) >= tSpeedX:
self.changeX = self.changeX/abs(self.changeX) * tSpeedX
if abs(self.changeY) >= tSpeedY:
self.changeY = self.changeY/abs(self.changeY) * tSpeedY
#standard update function. Will update rectangles position and deaccelerate it if no key held
def jump(self,y):
self.changeY = y
def update(self):
if accelX == 0:
self.changeX *= 0.92
if accelY == 0:
self.changeY *= .95
self.rect.x += self.changeX
print(self.changeX)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeX > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.changeY + (9*gConstant)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeY >= -5:
global jumpB
jumpB = True
COLOR = WHITE
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class wall(pygame.sprite.Sprite):
def __init__(self, sx, sy,px,py):
super().__init__()
#iniatilized values for walls
collision = False
self.image = pygame.Surface([sx, sy])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
self.rect.x = px
self.rect.y = py
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
spriteList = pygame.sprite.Group()
wallList = pygame.sprite.Group()
Player = player(100,100)
spriteList.add(Player)
Wall1 = wall(1000, 30, 0, 400)
Wall2 = wall(100, 30, 150, 350)
wallList.add(Wall2)
spriteList.add(Wall2)
wallList.add(Wall1)
spriteList.add(Wall1)
Player.walls = wallList
clock = pygame.time.Clock()
#Allows program to exit
quit = False
while not quit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True
#Sets accel values
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
accelX = -.25
if event.key == pygame.K_RIGHT:
accelX = .25
if event.key == pygame.K_UP and jumpB == True:
Player.jump(-20)
jumpB = False
COLOR = BLUE
if event.key == pygame.K_DOWN:
accelY = .25
#reverses accel values to allow for deaccleration
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
accelX = 0
if event.key == pygame.K_RIGHT:
accelX = 0
if event.key == pygame.K_UP:
accelY = 0
if event.key == pygame.K_DOWN:
accelY = 0
#calls function to move rectangle
Player.velocity(accelX, accelY)
spriteList.update()
screen.fill(BLACK)
spriteList.draw(screen)
pygame.display.flip()
clock.tick(60)

Pygame Multiple bullets not spawning

So im new at pygame and coding my first project- a side scrolling shooter. The issue im having is with my bullets: when i press the space key, some of the bullets will show up but there are times when nothing happens, and no bullets spawn when i jump. Not quite sure how to go about fixing this issue- any ideas would be greatly appreciated.
Code is as follows:
import pygame
import math, random, sys, pygame.mixer
from pygame.locals import *
pygame.init()
pygame.mixer.pre_init(44100, -16, 2, 8192)
pygame.mixer.init()
jump = False
jump_offset = 0
jump_height = 250
k = pygame.key.get_pressed()
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
def do_jumping():
global jump_height
global jump
global jump_offset
if jump:
jump_offset += 3
if jump_offset >= jump_height:
jump = False
elif jump_offset > 0 and jump == False:
jump_offset -= 3
#Defining colours
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
#Window Settings
w = 1280
h = 720
half_w = w /2
half_h = h /2
AREA = w*h
#Initialising the window
pygame.init()
display = pygame.display.set_mode((w,h)) #Sets the size of the window
pygame.display.set_caption("Cattleman") #Sets the title of the window
Clock = pygame.time.Clock() #clockspeed for the game ie. 60fps
FPS = 600
#pygame.mouse.set_visible(True) #Allows the mouse to be shown in the game window.
background = pygame.image.load("background.png").convert()
backgroundWidth, backgroundHeight = background.get_rect().size
stageWidth = backgroundWidth*2 #sets the area which the player can move in
stagePosX = 0 #Records position of stage as the player moves
startScrollPosX = half_w
circleRadius = 25
circlePosX = circleRadius
playerPosX = circleRadius
playerPosY = 602
playerVelocityX = 0
playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
bullets = []
bulletSprite = pygame.image.load("Bullet1.png").convert_alpha()
bulletSprite = pygame.transform.scale(bulletSprite, (20,10))
#Sounds
#gunSounds = ["pew1.wav", "pew2.wav", "pew3.wav", "pew4.wav"]
#SOUNDS
shot = pygame.mixer.Sound("pew1.wav")
#------------------------MAIN PROGRAM LOOP------------------------#
while True:
events()
do_jumping()
k = pygame.key.get_pressed()
if k[K_RIGHT]:
playerVelocityX = 2 #Moves the player right
playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
if k[K_LEFT]:
playerVelocityX = -2 #Moves the player left
playersprite = pygame.image.load("player_spriteL2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
if k[K_UP] and jump == False and jump_offset == 0:
jump = True
if not k[K_RIGHT] and not k[K_LEFT]:
playerVelocityX = 0 #If no input detected, the player does not move
if k[K_SPACE]:
for event in pygame.event.get():
bullets.append([circlePosX-100, playerPosY-20])
shot.play()
playerPosX += playerVelocityX
if playerPosX > stageWidth - circleRadius-25: playerPosX = stageWidth - circleRadius-25 #Checks if the player trie to go past the right boundary
if playerPosX < circleRadius+55:playerPosX = circleRadius+55 #Checks if the player tries to go past the left boundary
if playerPosX < startScrollPosX: circlePosX = playerPosX
elif playerPosX > stageWidth - startScrollPosX: circlePosX = playerPosX - stageWidth + w
else:
circlePosX = startScrollPosX
stagePosX += -playerVelocityX
for b in range(len(bullets)):
bullets[b][0] -= 3
for bullet in bullets[:]:
if bullet[0] < 0:
bullets.remove(bullet)
rel_x = stagePosX % backgroundWidth
display.blit(background,(rel_x - backgroundWidth, 0))
if rel_x < w:
display.blit(background, (rel_x, 0))
for bullet in bullets:
display.blit(bulletSprite, pygame.Rect(bullet[0], bullet[1], 0, 0,))
#pygame.draw.circle(display,WHITE, (int(circlePosX),playerPosY - jump_offset), circleRadius, 0)
display.blit(playersprite, (int(circlePosX-80),playerPosY-100 - jump_offset))
pygame.display.update()
Clock.tick(FPS)
display.fill(BLACK)
I have done this in my code that leaves multiple balls similar like bullets :
class Bullet():
def __init__(self, x, y):
# self.image = pygame.image.load("SingleBullet.png")
self.image = pygame.image.load("ball.png")
self.image = pygame.transform.scale(self.image, (25, 25))
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
self.is_alive = True
# --------------------
def update(self):
self.rect.y -= 15
if self.rect.y < 0:
self.is_alive = False
# --------------------
def draw(self, screen):
screen.blit(self.image, self.rect.topleft)
for getting keyboard :
def event_handler(self, event):
if event.type == KEYDOWN:
if event.key == K_LEFT:
self.move_x = -5
elif event.key == K_RIGHT:
self.move_x = 5
elif event.key == K_SPACE:
if len(self.shots) < self.max_shots:
self.shots.append(Bullet(self.rect.centerx, self.rect.top))
if event.type == KEYUP:
if event.key in (K_LEFT, K_RIGHT):
self.move_x = 0

How to implement jump in Pygame without sprites?

I'm new to programming and to Python as well as Pygame. As such, I'm not yet comfortable with sprites in Pygame. I'm trying to make a game where a block jumps whenever the spacebar is pressed - similar to Mario.
My code doesn't work as desired because whenever the spacebar is pressed, the block incrementally moves up (I've added a gravity component), instead of "jumping".
import pygame
pygame.init()
game_display = pygame.display.set_mode((800, 800))
# fixed variables at the start
x_pos = 400
y_pos = 400
current_speed = 15
def jump_coords(y_position, speed):
if speed >= 0:
#to move up, reduce the y-coordinate
y_position -= speed
return y_position
game_exit = False
# main loop
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
y_pos = jump_coords(y_pos, current_speed)
# 1 represents gravity value
current_speed -= 1
rect_one = pygame.Rect(x_pos, y_pos, 10, 10)
pygame.draw.rect(game_display, (255, 0, 0), rect_one)
pygame.display.update()
I know that I have to somehow make y_pos keep updating in the while loop whilst speed >= 0 but I'm not sure how to implement it.
I made the minimal changes to your code to get the block to bounce:
import pygame
pygame.init()
game_display = pygame.display.set_mode((800, 800))
# fixed variables at the start
x_pos = 400
y_pos = 400
x_old = x_pos
y_old = y_pos
current_speed = 15
def jump_coords(y_position, speed):
# to move up, reduce the y-coordinate
y_position -= speed
if y_position > 400:
y_position = 400
global jump_flag
jump_flag = False
global current_speed
current_speed = 15
return y_position
game_exit = False
jump_flag = False
# main loop
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
jump_flag = True
elif event.key == pygame.K_ESCAPE:
exit(0)
if jump_flag:
x_old = x_pos
y_old = y_pos
y_pos = jump_coords(y_pos, current_speed)
# 1 represents gravity value
current_speed -= 1
rect_old = pygame.Rect(x_old, y_old, 10, 10)
pygame.draw.rect(game_display, (0, 0, 0), rect_old)
rect_one = pygame.Rect(x_pos, y_pos, 10, 10)
pygame.draw.rect(game_display, (255, 0, 0), rect_one)
pygame.display.update()
The most important changes was the removal of the check for speed greater than zero. The speed has to go negative if the block is going to come back down. The next change was to save the old x and y coordinates so that we can draw a black square over the old position. I also made it possible to exit the program by pressing the Escape key.
I made this from scratch, I hope it's not too daunting!
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800, 800))
tm = 20 # Terminal Velocity
gravity = 1
class Player:
def __init__(self,speed,x,y):
self.speed = speed
self.x = x; self.y = y
self.yVelocity = 0
self.xVelocity = 0
def getKeys(self):
key = pygame.key.get_pressed()
if key[pygame.K_a]: self.xVelocity -= self.speed
if key[pygame.K_d]: self.xVelocity += self.speed
if key[pygame.K_SPACE]:
if isGround(self.x,self.y):
self.yVelocity -= 20
def move(self,dt):
if self.x < 0:
self.x = 0
if self.x > 800-15:
self.x = 800-15
if self.y < 0:
self.y = 0
if self.y > 800-10:
self.y = 800-10
self.x += self.xVelocity
self.y += self.yVelocity
if self.xVelocity != 0:
self.xVelocity /= 70*dt
if self.yVelocity < tm and not isBlocking(self.x,self.y+self.yVelocity):
self.yVelocity += gravity
if isBlocking(self.x,self.y):
self.yVelocity = 0
def draw(self):
screen.fill((255,0,0),(self.x,self.y,10,10))
def isBlocking(x,y):
if x < 0 or x > 800 or y < 0 or y > 800:
return True
elif y >= 400:
return True
else:
return False
def isGround(x,y):
if y >= 400:
return True
else:
return False
player = Player(1,400,400)
clock = pygame.time.Clock()
while True:
dt = clock.tick(60)/1000 # limit to 60 FPS.
screen.fill((0,0,0))
if pygame.event.poll().type == pygame.QUIT: pygame.quit(); sys.exit()
player.getKeys()
player.move(dt)
player.draw()
pygame.display.flip()
Hope it helps!

Unable to fix broken ball movement in pygame pong

I'm fairly new to programming, game programming especially. I'm trying to make pong using pygame, but have run into a slight issue. Essentially, the ball hits a paddle, stops, and then keeps going once the paddle is out of the way. Obviously I want the ball to bounce back, but I can't figure out why it won't, when I've coded (what I thought was) the appropriate logic for ball-paddle collisions. Here's my code:
# importing stuff
import sys, pygame
from pygame.locals import *
# starting pygame
pygame.init()
# defining basic colours
white = (255, 255, 255)
black = (0, 0, 0)
# set up the clock
clock = pygame.time.Clock()
# text and such
tFont = pygame.font.SysFont("monospace", 15)
# setting window res and setting display
winX, winY = 600, 300
window = pygame.display.set_mode((winX, winY))
# setting the speed for on screen stuff
playSpeed = 5 # player speed (p1 and p2)
# counts points for each player
# 1 2
points = [0, 0]
# tallies number of times FPS is counted and added to toal amount
fpsCount = 0
fpsTotal = 0
class Ball(object):
def __init__(self, speed):
# set default ball position in screen centre
self.ballX = winX / 2
self.ballY = winY / 2
self.ballSpeed = speed
def move(self):
if points[0] > points[1]: # if p1 has more points than p2
self.ballX -= self.ballSpeed # ball goes to p1's side
elif points[0] < points[1]: # only other condition could be p2 having more points
self.ballX += self.ballSpeed # ball goes to p2's side
elif points[0] == points[1]: # if points are equal
self.ballX -= self.ballSpeed # favour player 1 (change later)
pygame.draw.circle(window, black, (self.ballX, self.ballY), 3)
def collide(self, paddle): # unsure if 'paddle' necessary
# if ball hits top of paddle, bounce to top
# if hits bottom, bounce to bottom
# if ball hits midsection, bounce straight (middle could be about 10px?)
if paddle == playerOne:
self.ballX
self.ballX += self.ballSpeed
class Paddle(object):
# set the player number (1/2) and if it's an AI or real player
def __init__(self, player, aiornot):
if player == 1 and aiornot == False:
self.coords = [[40, 130], [40, 160]]
elif player == 2 and aiornot == False:
self.coords = [[560, 130], [560, 160]]
self.movement = 'stop' # sets default movement
def move(self):
if self.movement == 'down' and self.coords[1][1] < 300:
self.moveDown()
elif self.movement == 'up' and self.coords[0][1] > 0:
self.moveUp()
elif self.movement == 'stop':
self.stop()
# draw the paddle in new position
pygame.draw.line(window, black, self.coords[0], self.coords[1], 10)
# movement functions, for direction and such
def moveDown(self):
self.coords[0][1] += playSpeed
self.coords[1][1] += playSpeed
def moveUp(self):
self.coords[0][1] -= playSpeed
self.coords[1][1] -= playSpeed
def stop(self):
self.coords[0][1] = self.coords[0][1]
self.coords[1][1] = self.coords[1][1]
ball = Ball(playSpeed)
playerOne = Paddle(1, False)
playerTwo = Paddle(2, False)
# main loop
while True:
# event handling for exit
for event in pygame.event.get():
if event.type == QUIT:
# print the average FPS
print round(fpsTotal / fpsCount, 2), "fps (avg)"
pygame.quit()
sys.exit()
# setting direction upon arrow key press
elif event.type == KEYDOWN:
if event.key == K_DOWN:
playerOne.movement = 'down'
elif event.key == K_UP:
playerOne.movement = 'up'
elif event.key == K_s:
playerTwo.movement = 'down'
elif event.key == K_w:
playerTwo.movement = 'up'
# when the key is released, stop moving
elif event.type == KEYUP:
if event.key == K_DOWN or event.key == K_UP:
playerOne.movement = 'stop'
elif event.key == K_s or event.key == K_w:
playerTwo.movement = 'stop'
print "player1:", playerOne.coords
print "player2:", playerTwo.coords
# this is a mess... if the balls x coords = the paddles x coords, and the balls y
# coord is somewhere between the start and end point of the paddle, then do the balls
# collision function on the paddle
if ball.ballX >= playerOne.coords[0][0] and ball.ballX <= playerOne.coords[1][0]: # or ball.ballX == 40
if ball.ballY >= playerOne.coords[0][1] and ball.ballY <= playerOne.coords[1][1]:
ball.collide(playerOne)
print ball.ballX, ball.ballY
# fill the window
window.fill(white)
# redraw the bat with new position
playerOne.move()
playerTwo.move()
# redraw the ball with new position
ball.move()
# set FPS to 60
clock.tick(60)
# for working out average FPS
fpsCount += 1
fpsTotal += clock.get_fps()
# set window title
pygame.display.set_caption("Long Pong")
# render FPS to text, display text
text = tFont.render(str(round(clock.get_fps(), 2)), 8, black)
window.blit(text, (545, 5))
# update display
pygame.display.update()
And also a pastebin here if it's easier to look at/copy.
I appreciate any help with this, I've been able to work out any other problem on my own, but I can't tell what I'm missing here.
I hope the below code helps. Although my program was a bit different because every time the ball hit the paddle we had to generate a new ball.
import random
from livewires import games, color
games.init(screen_width = 640, screen_height = 480, fps = 50)
class Ball(games.Sprite):
quit_label = games.Text(value = "Press Q to Quit", size = 25, color = color.white, top = 5, right = 130,
is_collideable = False)
games.screen.add(quit_label)
def update(self):
if self.right > games.screen.width:
self.dx = -self.dx
if self.left < 0:
self.game_over()
if self.bottom > games.screen.height or self.top < 0:
self.dy = -self.dy
#pressing 'q' quits the game
if games.keyboard.is_pressed(games.K_q):
self.game_over()
def bounce(self):
self.dx = -self.dx
def game_over(self):
""" End the game. """
end_message = games.Message(value = "Game Over",
size = 90,
color = color.red,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 3 * games.screen.fps,
after_death = games.screen.quit,
is_collideable = False)
games.screen.add(end_message)
self.destroy()
class Paddle(games.Sprite):
image = games.load_image("paddle.bmp")
score = games.Text(value = 0, size = 25, color = color.white, top = 15,
right = games.screen.width - 10, is_collideable = False)
games.screen.add(score)
def __init__(self):
super(Paddle, self).__init__(image = Paddle.image, x = games.mouse.x, bottom = games.screen.height)
def update(self):
""" Move to mouse y position. """
self.y = games.mouse.y
if self.left > 0:
self.left = 10
if self.right > games.screen.height:
self.right = games.screen.height
self.check_catch()
def check_catch(self):
for ball in self.overlapping_sprites:
Paddle.score.value += 1
ball_image2 = games.load_image("ball.bmp")
ball2 = Ball(image = ball_image2,
x = games.screen.width/2,
y = games.screen.height/2,
dx = 1,
dy = 1)
games.screen.add(ball2)
ball.bounce()
def main():
wall_image = games.load_image("background.bmp", transparent = False)
games.screen.background = wall_image
ball_image = games.load_image("ball.bmp")
the_ball = Ball(image = ball_image,
x = games.screen.width/2,
y = games.screen.height/2,
dx = 1,
dy = 1)
games.screen.add(the_ball)
the_paddle = Paddle()
games.screen.add(the_paddle)
games.mouse.is_visible = False
games.screen.mainloop()
# kick it off!
main()

Artificial inteligence in python and pygame for Pong clone

I'm making a program that clones pong based off a tutorial and I already have the program to where it is multiplayer with two separate people. I want to add an AI in the program instead of a player 2. I've been stuck on this for quite some time and would appreciate any help! Here is the code currently:
import sys, os, math, random, pygame
from pygame.locals import *
class paddle(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_paddle.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.movementspeed = 5
self.velocity = 0
def up(self):
# increases vertical velocity
self.velocity -= self.movementspeed
def down(self):
# decreases vertical velocity
self.velocity += self.movementspeed
def move(self, dy):
# moves the paddle y, doesn't go out of top or bottom
if self.rect.bottom + dy > 400:
self.rect.bottom = 400
elif self.rect.top + dy < 0:
self.rect.top = 0
else:
self.rect.y += dy
def update(self):
# makes the paddle move every frame
self.move(self.velocity)
class aiplayer(object):
def __init__(self):
self.bias = random.random() - 0.5
self.hit_count = 0
def update(self, paddle, game,):
if (paddle.rect.centerx < game.bounds.centerx and game.ball.rect.centerx < game.bounds.centerx) or (paddle.rect.centerx > game.bounds.centerx and game.ball.rect.centerx > game.bounds.centerx):
delta = (paddle.rect.centery + self.bias * paddle.rect.height) - game.ball.rect.centery
if abs(delta) > paddle.velocity:
if delta > 0:
paddle.direction = -1
else:
paddle.direction = 1
else:
paddle.direction = 0
else:
paddle.direction = 0
def hit(self):
self.hit_count += 1
if self.hit_count > 6:
self.bias = random.random() - 0.5
self.hit_count = 0
def lost(self):
self.bias = random.random() - 0.5
def won(self):
pass
def render(self, surface):
x, y = self.location
w, h = self.image.get_size()
surface.blitz(self.image, (x-w/2, y-h/2))
class Ball(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_ball.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.maxspeed = 10
self.servespeed = 5
self.velx = 0
self.vely = 0
def reset(self):
self.rect.centerx, self.rect.centery = 400, 200
self.velx = 0
self.vely = 0
def serve(self):
angle = random.randint(-45, 45)
if abs(angle) < 5 or abs(angle-180) < 5:
angle = random.randint(10, 20)
if random.random() > .5:
angle += 180
# this gets the velocity for the x and y coords
x = math.cos(math.radians(angle))
y = math.sin(math.radians(angle))
self.velx = self.servespeed * x
self.vely = self.servespeed * y
class Game(object):
def __init__(self):
pygame.init()
# creates the window
self.window = pygame.display.set_mode((800, 400))
# makes a clock
self.clock = pygame.time.Clock()
# window title
pygame.display.set_caption("Pong")
# tells pygame to watch for these certain events so we can close window
pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])
self.background = pygame.Surface((800, 400))
self.background.fill((55, 255, 85))
pygame.draw.line(self.background, (0,0,0), (400, 0), (400, 400), 2)
self.window.blit(self.background, (0,0))
#lets the background show up
pygame.display.flip()
#renders the sprites so that they actually show up
self.sprites = pygame.sprite.RenderUpdates()
# makes the paddles, adds to sprite group
self.leftpaddle = paddle((50, 200))
self.sprites.add(self.leftpaddle)
self.rightpaddle = paddle((750, 200))
self.sprites.add(self.rightpaddle)
# makes the ball
self.ball = Ball((400, 200))
self.sprites.add(self.ball)
def run(self):
# this lets the game run using a loop so its always active and never closes
running = True
while running:
self.clock.tick(60)
# pygame event, if user closes the game, then stop running
running = self.handleEvents()
pygame.display.set_caption("Pong %d fps" % self.clock.get_fps())
self.manageBall()
# updates the sprites(paddles, ball)
for sprite in self.sprites:
sprite.update()
# renders the sprites
self.sprites.clear(self.window, self.background)
dirty = self.sprites.draw(self.window)
pygame.display.update(dirty)
def handleEvents(self):
for event in pygame.event.get():
if event.type == QUIT:
return False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
return False
# controls the right paddle
if event.key == K_w:
self.leftpaddle.up()
if event.key == K_s:
self.leftpaddle.down()
if event.key == K_UP:
self.rightpaddle.up()
if event.key == K_DOWN:
self.rightpaddle.down()
# serves the ball
if event.key == K_SPACE:
if self.ball.velx == 0 and self.ball.vely == 0:
self.ball.serve()
elif event.type == KEYUP:
if event.key == K_w:
self.leftpaddle.down()
if event.key == K_s:
self.leftpaddle.up()
if event.key == K_UP:
self.rightpaddle.down()
if event.key == K_DOWN:
self.rightpaddle.up()
elif event.type ==
return True
def manageBall(self):
# this moves the ball
self.ball.rect.x += self.ball.velx
self.ball.rect.y += self.ball.vely
if self.ball.rect.top < 0:
self.ball.rect.top = 1
# makes the ball bounce
self.ball.vely *= -1
elif self.ball.rect.bottom > 400:
self.ball.rect.bottom = 399
# makes ball bounce off bottom
self.ball.vely *= -1
# resets the ball if it hits the left or right screen
if self.ball.rect.left < 0:
self.ball.reset()
return
elif self.ball.rect.right > 800:
self.ball.reset()
return
collision = pygame.sprite.spritecollide(self.ball, [self.leftpaddle, self.rightpaddle], dokill = False)
if len(collision) > 0:
hitpaddle = collision[0]
# sends the ball back
self.ball.velx *= -1
# makes sure the ball doesn't get stuck in the paddle
self.ball.rect.x += self.ball.velx
# makes the game and runs it
if __name__ == '__main__':
game = Game()
game.run()
Make a function AI in the aiplayer and have it return up or down
int AI(self.position,ball.position):
if self.y>ball.y:
return -1
elif self.y<ball.y:
return 1
then, in the update() code for aiplayer, do something similar to this
self.y += movespeed*AI(self.position,ball.position)
Then, it either moves the paddle up or down depending on where the ball is ( you might need to switch if you add or subtract the movespeed to get the paddle to go the right direction). Also, it might be more effective to use the center of the paddle so that it won't put the top or bottom edge of the paddle at the ball.

Categories