Pong Collision Pygame - python

I'm writing code for a one paddle pong game in pygame where the ball will bounce off of the 3 walls the paddle is not on, and when it does hit the paddle's wall instead of the paddle, it makes you lose a life. My problem is that I cannot figure out the collision detection to do this. Here is what I've done so far:
import pygame, sys
from pygame.locals import *
pygame.init()
screen_width = 640
screen_height = 480
Display = pygame.display.set_mode((screen_width, screen_height), 0, 32)
pygame.display.set_caption('Lonely Pong')
back = pygame.Surface((screen_width, screen_height))
background = back.convert()
background.fill((255, 255, 255))
paddle = pygame.Surface((80, 20))
_paddle = paddle.convert()
_paddle.fill((128, 0, 0))
ball = pygame.Surface((15, 15))
circle = pygame.draw.circle(ball, (0, 0, 0), (7, 7), 7)
_ball = ball.convert()
_ball.set_colorkey((0, 0, 0))
_paddle_x = (screen_width / 2) - 40
_paddle_y = screen_height - 20
_paddlemove = 0
_ball_x, _ball_y = 8, 8
speed_x, speed_y, speed_circle = 250, 250, 250
Lives = 5
clock = pygame.time.Clock()
font = pygame.font.SysFont("verdana", 20)
paddle_spd = 5
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
_paddlemove = paddle_spd
elif event.key == K_LEFT:
_paddlemove = -paddle_spd
elif event.type == KEYUP:
if event.key == K_RIGHT:
_paddlemove = 0
elif event.key == K_LEFT:
_paddlemove = 0
Livespr = font.render(str(Lives), True, (0, 0, 0))
Display.blit(background, (0, 0))
Display.blit(_paddle, (_paddle_x, _paddle_y))
Display.blit(_ball, (_ball_x, _ball_y))
Display.blit(Livespr, ((screen_width / 2), 5))
_paddle_x += _paddlemove
passed = clock.tick(30)
sec = passed / 1000
_ball_x += speed_x * sec
_ball_y += speed_y * sec
pygame.display.update()
Another problem I've been having is that when I start it up, the ball doesn't appear at all. Could somebody please point me in the right direction?

first things first, the ball doesn't appear because you are not filling the surface, you are setting the color_key:
_ball.set_colorkey((0, 0, 0))
should be
_ball.fill((0, 0, 0))
Second, for collision detection, pygame offers some functions such as collidepoint and colliderect.
https://www.pygame.org/docs/ref/rect.html#pygame.Rect.collidepoint
which means you will need the rectangles of the surfaces. do this by:
my_surface.get_rect()
https://www.pygame.org/docs/ref/surface.html#pygame.Surface.get_rect
In order to collide with the edges of the screen, you can always do
if _ball_x <= 0 or _ball_y <= 0 or _ball_x >= 640 or _ball_y >= 480:
# collision detected

Related

Why do i get an error when switching windows?

I tried to build a simple game in python using pygame. At first my problem was to make the movement more smooth, because about every second the movement of the rectangles stuck for a few milliseconds. Then I found an solution by adding "os.environ['SDL_VIDEODRIVER'] = 'directx'" in to my code and changing the display mode to "FULLSCREEN" and "DOUBLEBUFF". The movement is more fluid now, but whenever I Alt + Tab out of the fullscreen game, i get this error:
Traceback (most recent call last):
File "C:\Users\L-Tramp-GAMING\Documents\Python\Game\Main_Game.py", line 64, in <module>
screen.fill(BG_COLOR)
pygame.error: IDirectDrawSurface3::Blt: Surface was lost
I don't know how to bypass this problem. I am also wondering if i can somehow run the game in windowed mode with the directx line added in normal speed. At the moment the game runs in much higher speed when it is in windowed mode. I hope some of you guys can help me. Thank you, Paul
import pygame
import random
import os
#Variables
WIDTH = 1280
HEIGHT = 720
GAME_OVER = False
BG_COLOR = (0, 0, 20)
playerWidth = 50
playerHeight = 50
playerPosX = WIDTH / 2 - playerWidth / 2
playerPosY = HEIGHT - (playerHeight + 75)
playerSpeed = 10
enemieWidth = 75
enemieHeight = 75
enemiePosX = random.randint(0, WIDTH - enemieWidth)
enemiePosY = 0
enemieSpeed = 5
enemieCounter = 1
####################################################################################################
os.environ['SDL_VIDEODRIVER'] = 'directx'
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.FULLSCREEN | pygame.DOUBLEBUF)
pygame.display.set_caption("Game")
pygame.key.set_repeat(1, 10)
clock = pygame.time.Clock()
#GameLoop
while not GAME_OVER:
for e in pygame.event.get():
if e.type == pygame.QUIT:
GAME_OVER = True
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_a:
playerPosX -= playerSpeed
print(hex(screen.get_flags() & 0xFFFFFFFF))
if e.key == pygame.K_d:
playerPosX += playerSpeed
#Graphics
screen.fill(BG_COLOR)
player = pygame.draw.rect(screen, (0, 255, 0), (playerPosX, playerPosY, playerWidth, playerHeight))
if enemiePosY < HEIGHT:
enemie = pygame.draw.rect(screen, (255, 0, 0), (enemiePosX, enemiePosY, enemieWidth, enemieHeight))
enemiePosY += enemieSpeed
else:
enemieCounter += 1
enemiePosY = 0
enemiePosX = random.randint(0, WIDTH - enemieWidth)
if (enemieCounter + 1) % 2 == 0:
pass
#End Graphics
pygame.display.flip()
Your movement lag was caused by pygame.key.set_repeat. To allow the player to hold down a and d to move you can update the players position in your game loop instead of using set_repeat by keeping track of a speed variable. If you wanted to use os.environ for another reason besides fixing the lag then this won't work but otherwise this should be fine.
import pygame
import random
import os
#Variables
WIDTH = 1280
HEIGHT = 720
GAME_OVER = False
BG_COLOR = (0, 0, 20)
playerWidth = 50
playerHeight = 50
playerPosX = WIDTH / 2 - playerWidth / 2
playerPosY = HEIGHT - (playerHeight + 75)
playerSpeed = 10
enemieWidth = 75
enemieHeight = 75
enemiePosX = random.randint(0, WIDTH - enemieWidth)
enemiePosY = 0
enemieSpeed = 5
enemieCounter = 1
####################################################################################################
#os.environ['SDL_VIDEODRIVER'] = 'directx'
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
#pygame.key.set_repeat(1, 10) <----- This line is the problem
clock = pygame.time.Clock()
#GameLoop
speed = 0
while not GAME_OVER:
for e in pygame.event.get():
if e.type == pygame.QUIT:
GAME_OVER = True
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_a:
speed = -playerSpeed
if e.key == pygame.K_d:
speed = +playerSpeed
playerPosX += speed
#Graphics
screen.fill(BG_COLOR)
player = pygame.draw.rect(screen, (0, 255, 0), (playerPosX, playerPosY, playerWidth, playerHeight))
if enemiePosY < HEIGHT:
enemie = pygame.draw.rect(screen, (255, 0, 0), (enemiePosX, enemiePosY, enemieWidth, enemieHeight))
enemiePosY += enemieSpeed
else:
enemieCounter += 1
enemiePosY = 0
enemiePosX = random.randint(0, WIDTH - enemieWidth)
if (enemieCounter + 1) % 2 == 0:
pass
#End Graphics
pygame.display.flip()
Can the code handle the error, and then try re-creating the screen object ?
This is the same sort of process as when switching from full-screen to windowed.
EDIT: Added some code from the PyGame Wiki: https://www.pygame.org/wiki/toggle_fullscreen to hopefully work around further issues from OP's comment.
try:
screen.fill(BG_COLOR)
except pygame.error as e:
# Get the size of the screen
screen_info= pygame.display.Info()
cursor = pygame.mouse.get_cursor() # Duoas 16-04-2007
new_width = screen_info.current_w
new_height = screen_info.current_h
# re-initialise the display, creating a re-sizable window
pygame.display.quit()
pygame.display.init()
screen = pygame.display.set_mode( ( new_width, new_height ), pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE )
pygame.key.set_mods( 0 ) # HACK: work-a-round for a SDL bug??
pygame.mouse.set_cursor( *cursor ) # Duoas 16-04-2007
# did it work?
screen.fill(BG_COLOR)

Sprite mask collision problems in pygame

I am attempting to create a racing game in pygame. I want it such that when the car goes off the track, it slows down. I have tried to do this by having another sprite that is an outline of the track and when the car touches that sprite, it slows down. This does not work and I don't know why. Is there a better way to do this?
Img is the car image
Back is the racetrack
BackHit is the outline
I receive this error code:
Traceback (most recent call last):
File "C:\Users\Daniella\Desktop\Python\Games\game.py", line 75, in
if pygame.sprite.collide_mask(Img, BackHit):
File "C:\Users\Daniella\AppData\Roaming\Python\Python36\site-packages\pygame\sprite.py", line 1470, in collide_mask
xoffset = right.rect[0] - left.rect[0]
AttributeError: 'pygame.Surface' object has no attribute 'rect'
This is the code:
import pygame
Width = 800
Height = 600
Black = (0, 0, 0)
White = (255, 255, 255)
Red = (255, 0, 0)
Green = (0, 255, 0)
Blue = (0, 0, 255)
Yellow = (255, 255, 0)
BackColour = (198, 151, 107)
pygame.init()
GameDisplay = pygame.display.set_mode((Width, Height))
pygame.display.set_caption("A bit Racey")
Clock = pygame.time.Clock()
Img = pygame.image.load("download.png")
ImgWidth = 46
ImgHeight = 68
Img = pygame.transform.scale(Img, (ImgWidth, ImgHeight))
Back = pygame.image.load("back1.png")
BackWidth = Width*4
BackHeight = Height*4
Back = pygame.transform.scale(Back, (BackWidth, BackHeight))
BackHit = pygame.image.load("back1 hit1.png")
BackHitWidth = Width*4
BackHitHeight = Height*4
BackHit = pygame.transform.scale(BackHit, (BackHitWidth, BackHitHeight))
def Car():
GameDisplay.blit(Img, (400-ImgWidth/2, 300-ImgHeight/2))
def Background(X, Y):
GameDisplay.blit(Back, (X, Y))
def BackgroundHit(X, Y):
GameDisplay.blit(BackHit, (X, Y))
X = (Width*0.45)
Y = (Height*0.5)
XChange = 0
YChange = 0
Changer = 1
Crashed = False
while not Crashed:
for Event in pygame.event.get():
if Event.type == pygame.QUIT:
Crashed = True
elif Event.type == pygame.KEYDOWN:
if Event.key == pygame.K_LEFT:
Img = pygame.transform.rotate(Img, -90)
XChange = 5 / Changer
elif Event.key == pygame.K_RIGHT:
Img = pygame.transform.rotate(Img, 90)
XChange = -5 / Changer
elif Event.key == pygame.K_UP:
Img = pygame.transform.rotate(Img, 0)
YChange = 5 / Changer
elif Event.key == pygame.K_DOWN:
Img = pygame.transform.rotate(Img, 180)
YChange = -5 / Changer
if Event.type == pygame.KEYUP:
if Event.key == pygame.K_LEFT or Event.key == pygame.K_RIGHT:
XChange = 0
elif Event.key == pygame.K_UP or Event.key == pygame.K_DOWN:
YChange = 0
if pygame.sprite.collide_mask(Img, BackHit):
Changer = 2
Y += YChange
X += XChange
GameDisplay.fill(White)
BackgroundHit(X, Y)
Background(X, Y)
Car()
pygame.display.update()
Clock.tick(200)
pygame.quit()
quit()
Here's a little example that shows you how you can use pygame.mask.from_surface and pygame.Mask.overlap for pixel perfect collision detection.
import pygame as pg
# Transparent surfaces with a circle and a triangle.
circle_surface = pg.Surface((60, 60), pg.SRCALPHA)
pg.draw.circle(circle_surface, (30, 90, 200), (30, 30), 30)
triangle_surface = pg.Surface((60, 60), pg.SRCALPHA)
pg.draw.polygon(triangle_surface, (160, 250, 0), ((30, 0), (60, 60), (0, 60)))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
# Use `pygame.mask.from_surface` to get the masks.
circle_mask = pg.mask.from_surface(circle_surface)
triangle_mask = pg.mask.from_surface(triangle_surface)
# Also create rects for the two images/surfaces.
circle_rect = circle_surface.get_rect(center=(320, 240))
triangle_rect = triangle_surface.get_rect(center=(0, 0))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEMOTION:
triangle_rect.center = event.pos
# Now calculate the offset between the rects.
offset_x = triangle_rect.x - circle_rect.x
offset_y = triangle_rect.y - circle_rect.y
# And pass the offset to the `overlap` method of the mask.
overlap = circle_mask.overlap(triangle_mask, (offset_x, offset_y))
if overlap:
print('The two masks overlap!', overlap)
screen.fill((30, 30, 30))
screen.blit(circle_surface, circle_rect)
screen.blit(triangle_surface, triangle_rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
To create a mask for the background or track you need to create an extra image and either leave the track transparent or the area where the car should slow down and then check if the car collides with the track or with the outside area. Here I check if the green triangle collides with the "track" (the blue lines), and in your game you would then slow the car down if it doesn't collide with the track.
import pygame as pg
bg_surface = pg.Surface((640, 480), pg.SRCALPHA)
pg.draw.lines(
bg_surface, (30, 90, 200), True,
((60, 130), (300, 50), (600, 200), (400, 400), (150, 300)),
12)
triangle_surface = pg.Surface((60, 60), pg.SRCALPHA)
pg.draw.polygon(triangle_surface, (160, 250, 0), ((30, 0), (60, 60), (0, 60)))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
bg_mask = pg.mask.from_surface(bg_surface)
triangle_mask = pg.mask.from_surface(triangle_surface)
bg_rect = bg_surface.get_rect(center=(320, 240))
triangle_rect = triangle_surface.get_rect(center=(0, 0))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEMOTION:
triangle_rect.center = event.pos
offset_x = triangle_rect.x - bg_rect.x
offset_y = triangle_rect.y - bg_rect.y
overlap = bg_mask.overlap(triangle_mask, (offset_x, offset_y))
if overlap:
print('The two masks overlap!', overlap)
screen.fill((30, 30, 30))
screen.blit(bg_surface, bg_rect)
screen.blit(triangle_surface, triangle_rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
pygame.sprite.collide_mask is meant for pygame.sprite.Sprite objects. Instead use mask_var.overlap(other_mask, offset). To calculate the offset between the two masks, use offset = [other_object_x - object_x, other_object_y - object_y]. And to get the mask of an image, use mask_var = pygame.mask.from_surface(image).

How to make the object move during a while infinite loop?

I've been trying to create a game. In the game there is a jet that would fly into the recursive background rectangles. The rectangles are created through an infinite loop so once it enters the loop rest of the functions don't work for example the object. My code is below and the problem arises in the main loop. I want the object to move with the recursive rectangles but it freezes when the rectangles start being drawn in the loop. PS help to fix this as I've tried almost every code sample out there to fix it. Thank you
EDIT: the main function of the game is to make the jet go through what seems like recursive like rectangles (there are two of them and the while loop makes it simultaneously move up and down giving the feeling that the jet is going into the screen.). But since the jet is drawn first, when the program enters the rectangle loop the jet freezes and wont be able to move. I want the jet to move while the background is also moving.
import pygame
import random
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
Blue = (2,55,55)
black=(0,0,0)
end_it=False
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, WHITE,
[x, y, width, height],
1)
speed = [10,0]
rect_change_x = 10
rect_change_y = 10
# Is the rectangle wide enough to draw again?
if (width > 25):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
def recursive_draw2(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, Blue,
[x, y, width, height],
1)
speed = [10,0]
rect_change_x = 10
rect_change_y = 10
# Is the rectangle wide enough to draw again?
if (width > 25):
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw2(x, y, width, height)
'''
def timer(self):
screen.fill(black)
myfont=pygame.font.SysFont("Britannic Bold", 40)
label2=myfont.render("Ready?", 1, (255, 0, 0))
screen.blit(label2, (350,250))
self =3
nlist=[]
for i in range (2):
score = myfont.render(str(self),1,(255,0,0))
screen.blit((score), (350,250))
self = self - 1
nlist.append(self)
pygame.display.flip()
'''
pygame.init()
#rectanglelist = [big()]
# Set the height and width of the screen
size = [700, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
USEREVENT = 0
pygame.time.set_timer(USEREVENT+1, 10)
milliseconds = 0
seconds = 0
start_it = False
while (end_it==False):
screen.fill(black)
myfont=pygame.font.SysFont("Britannic Bold", 40)
nlabel=myfont.render("Welcome to "+ " Jet shooter ", 1, (255, 0, 0))
label=myfont.render("Click on the mouse to start ", 1, (255, 0, 0))
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
end_it=True
screen.blit(nlabel,(200, 100))
screen.blit(label, (170,300))
pygame.display.flip()
while (start_it==False):
screen.fill(black)
myfont2=pygame.font.SysFont("Britannic Bold", 40)
label2=myfont2.render("Ready?", 1, (255, 0, 0))
screen.blit(label2, (300,250))
pygame.display.flip()
pygame.time.wait(3000)
start_it = True
fall = False
while (fall==False):
nlist = [3,2,1]
for i in (nlist):
screen.fill(black)
n = str(i)
myfont3=pygame.font.SysFont("Britannic Bold", 40)
score = myfont3.render(n,1,(255,0,0))
screen.blit((score), (350,250))
pygame.display.flip()
pygame.time.wait(1000)
screen.fill(black)
myfont4=pygame.font.SysFont("Britannic Bold", 40)
label4=myfont3.render("GOOO!!!", 1, (255, 0, 0))
screen.blit(label4, (300,250))
pygame.display.flip()
pygame.time.wait (1000)
fall = True
b = 0
flip = 1
a = 0
time = 100
x_speed = 0
y_speed = 0
x_coord = 320
y_coord = 400
image = pygame.image.load("spaceship.gif").convert()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# User pressed down on key
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_speed = -10
if event.key == pygame.K_RIGHT:
x_speed = 10
if event.key == pygame.K_UP:
y_speed = -10
if event.key == pygame.K_DOWN:
y_speed = 10
# User let go of key
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_speed = 0
if event.key == pygame.K_RIGHT:
x_speed = 0
if event.key == pygame.K_UP:
y_speed = 0
if event.key == pygame.K_DOWN:
y_speed = 0
x_coord += x_speed
y_coord += y_speed
# Set the screen background
screen.fill(BLACK)
screen.blit(image, [x_coord,y_coord])
pygame.display.flip()
clock.tick(60)
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
# Limit to 60 frames per second
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
while a == 0 :
if flip == 1 :
recursive_draw(35,25,625,450)
recursive_draw2(0, 0, 700, 500)
flip = flip + 1
pygame.display.flip()
clock.tick(60)
if flip == 2 :
recursive_draw(0, 0, 700, 500)
recursive_draw2(35, 25, 625, 450)
flip = flip - 1
pygame.display.flip()
clock.tick(60)
pygame.quit()
As #Paul Rooney has stated, you'll want to use threads. Here's how you would
import thread
.
.
.
# Instead of calling the function as you are, run it on a new thread
thread.start_new_thread(drawRectanglesFunction, ())
From what I can tell is that you're drawing things in the incorrect order, and I believe that while loop is not needed. (while a == 0). Another thing is that you're flipping the display too often it is hard to keep track of what gets drawn first, and what gets drawn afterwards. My suggestion would be to quickly rewrite your program so that it looks something similar to this:
flip = 1
while not done:
##Catch and handle events()
screen.fill(BLACK)
if flip == 1 :
recursive_draw(35,25,625,450)
recursive_draw2(0, 0, 700, 500)
flip = flip + 1
elif flip == 2 :
recursive_draw(0, 0, 700, 500)
recursive_draw2(35, 25, 625, 450)
flip = flip - 1
screen.blit(image, [x_coord,y_coord])
pygame.display.flip()
clock.tick(60);
I hope this helps out a little.
(Edit: I did this on my own and got the program to run)

Pygame: Spaceinvaders: can't shoot bullets

I am currently building a mockup of space invaders.
I want to make the user shoot stuff and the invaders will die (1hit kill), but I can't seem to figure out how to do that. I have tried drawing a small rectangle, but then the background paints over it. Thanks for your help!
import pygame, sys, random
from pygame.locals import *
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
windowwidth = 800
windowheight = 700
windowSurface = pygame.display.set_mode((windowwidth, windowheight), 0, 32)
pygame.display.set_caption('Sp#c3 inv#d3r5')
# set up movement variables
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
# set up direction variables
DOWNLEFT = 1
DOWNRIGHT = 3
UPLEFT = 7
UPRIGHT = 9
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2
MOVESPEED = 10
MOVE = 2
# set up counting
score = 0
# set up the colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (135, 206, 250)
# set up font
font = pygame.font.SysFont(None, 50)
def makeship(windowwidth): # set up the bouncer and food data structures
user = pygame.Rect(350, 600, 100, 25)
return user
def drawwalls(walls):
for i in range(6):
wall = pygame.Rect(0,i+1,100,25)
pygame.draw.rect(windowSurface,GREEN,wall)
walls.append(wall)
def makeinvaders(invaders):
y = 0
for i in invaders: # each row
x = 0
for j in range(10):
# create invader
invader = pygame.Rect(75+x, 100+y, 40, 25)
# append invader to invaders[row]
i.append(invader)
# increase invader's x attribute by 50
x += 60
# increase invaders y by 35
y += 45
return invaders
def movepaddle(user):
# move the paddle
if moveLeft and user.left > 0:
user.left -= MOVESPEED
if moveRight and user.right < windowwidth:
user.right += MOVESPEED
return user
def moveinvaders(invaders, invdir):
# move the invaders
for row in invaders:
for invader in row:
if invdir == RIGHT and invaders[1][9].right < windowwidth:
invader.right += MOVE
elif invaders[1][9].right > windowwidth:
invader.left -= MOVE
invdir = LEFT
if invdir == LEFT and invaders[0][0].left > 0:
invader.left -= MOVE
elif invaders[0][0].left < 0:
invader.right += MOVE
invdir = RIGHT
return invdir
def shootbullets(windowSurface,blue2):
x = pygame.Rect(400,595,2,5)
pygame.draw.rect(windowSurface,GREEN,x)
def movebullets(bullets):
for bullet in bullets:
pass
def drawstuff(user, invaders):
# draw the user onto the surface
pygame.draw.rect(windowSurface, BLACK, user)
for i in invaders:
for invader in i:
if invader in invaders[0]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[1]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[2]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[3]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[4]:
pygame.draw.rect(windowSurface, BLACK, invader)
invaders = [[],[],[],[],[]]
invdir = LEFT
walls = []
drawwalls(walls)
# make the figures
user = makeship(windowwidth)
# make invaders
invaders = makeinvaders(invaders)
# run the game loop
while True:
# draw the black background onto the surface
windowSurface.fill(WHITE)
# check for the QUIT event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
# change the keyboard variables
if event.key == K_LEFT or event.key == ord('a'):
moveRight = False
moveLeft = True
if event.key == K_RIGHT or event.key == ord('d'):
moveLeft = False
moveRight = True
if event.key == K_SPACE:
shootbullets(windowSurface,RED)
if event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_LEFT or event.key == ord('a'):
moveLeft = False
if event.key == K_RIGHT or event.key == ord('d'):
moveRight = False
# draw stuff
drawstuff(user, invaders)
# move invaders
invdir = moveinvaders(invaders, invdir)
# paddle movement
user = movepaddle(user)
# draw the window onto the screen
pygame.display.update()
mainClock.tick(80)
Take a look at this minimal space invaders-like game I've written for another question:
import pygame
# you'll be able to shoot every 450ms
RELOAD_SPEED = 450
# the foes move every 1000ms sideways and every 3500ms down
MOVE_SIDE = 1000
MOVE_DOWN = 3500
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
pygame.display.set_caption("Micro Invader")
# create a bunch of events
move_side_event = pygame.USEREVENT + 1
move_down_event = pygame.USEREVENT + 2
reloaded_event = pygame.USEREVENT + 3
move_left, reloaded = True, True
invaders, colors, shots = [], [] ,[]
for x in range(15, 300, 15):
for y in range(10, 100, 15):
invaders.append(pygame.Rect(x, y, 7, 7))
colors.append(((x * 0.7) % 256, (y * 2.4) % 256))
# set timer for the movement events
pygame.time.set_timer(move_side_event, MOVE_SIDE)
pygame.time.set_timer(move_down_event, MOVE_DOWN)
player = pygame.Rect(150, 180, 10, 7)
while True:
clock.tick(40)
if pygame.event.get(pygame.QUIT): break
for e in pygame.event.get():
if e.type == move_side_event:
for invader in invaders:
invader.move_ip((-10 if move_left else 10, 0))
move_left = not move_left
elif e.type == move_down_event:
for invader in invaders:
invader.move_ip(0, 10)
elif e.type == reloaded_event:
# when the reload timer runs out, reset it
reloaded = True
pygame.time.set_timer(reloaded_event, 0)
for shot in shots[:]:
shot.move_ip((0, -4))
if not screen.get_rect().contains(shot):
shots.remove(shot)
else:
hit = False
for invader in invaders[:]:
if invader.colliderect(shot):
hit = True
i = invaders.index(invader)
del colors[i]
del invaders[i]
if hit:
shots.remove(shot)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: player.move_ip((-4, 0))
if pressed[pygame.K_RIGHT]: player.move_ip((4, 0))
if pressed[pygame.K_SPACE]:
if reloaded:
shots.append(player.copy())
reloaded = False
# when shooting, create a timeout of RELOAD_SPEED
pygame.time.set_timer(reloaded_event, RELOAD_SPEED)
player.clamp_ip(screen.get_rect())
screen.fill((0, 0, 0))
for invader, (a, b) in zip(invaders, colors):
pygame.draw.rect(screen, (150, a, b), invader)
for shot in shots:
pygame.draw.rect(screen, (255, 180, 0), shot)
pygame.draw.rect(screen, (180, 180, 180), player)
pygame.display.flip()
It uses colliderect to detect collisions, which your code is missing.
Also, the code in general and especially the movement code is a lot simpler than yours; so maybe it can serve as an inspiration for you.

Python Pygame Pong Game Issues

So basically what I've tried to code here is a game of Pong using the Python programming language and the Pygame module.
My problems are as follows:
The game sometimes gets stuck in a loop in which the AI paddle sits there while over and over again it loses
The ball jumps up and down sometimes? I have no clue as to why...
The ball just goes back and forth? I can't figure out why it isn't following along a random line like I want...
And my biggest problem, it seems that when the ball hits the top or bottom, it just disappears and the game just continues as if it was still bouncing around.
My Code
# Pong
import random, pygame, sys
from pygame.locals import *
FPS = 300
WINWID = 640
WINHEI = 480
BROWN = (102, 51, 0)
LIGHTBLUE = (0, 204, 204)
GREEN = (0, 153, 0)
PADDLECOLOR = (255, 255, 255)
BALLCOLOR = PADDLECOLOR
BACKGROUNDCOLOR = (0, 0, 0)
def main():
global FPSCLOCK, DISPLAYSURF
SPEED = 1
DIFF = 1.0 # AI paddle speed handicap
ball_speed = 1
AISIGHT = WINWID/6
FONT = "Times New Roman"
pygame.init()
DEFAULTFONT = pygame.font.SysFont(FONT, 16)
BIGGERFONT = pygame.font.SysFont(FONT, 32)
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINWID, WINHEI))
DISPLAYSURF.fill(BACKGROUNDCOLOR)
BACKGROUND = pygame.Rect(0, 0, WINWID, WINHEI)
pygame.display.set_caption('Pong')
paddleUP, paddleDOWN = False, False
ballpos = (WINWID/2, WINHEI/2)
AIpoint, PLAYERpoint = 0, 0
score = "Player:%2f || Computer:%2f" % (AIpoint, PLAYERpoint)
paddle = WINHEI/2
AIpaddle = paddle
pygame.draw.rect(DISPLAYSURF, BACKGROUNDCOLOR, BACKGROUND)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (9, paddle-20), (9, paddle+20), 3)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (629, AIpaddle-20), (629, AIpaddle+20), 3)
pygame.draw.circle(DISPLAYSURF, BALLCOLOR, ballpos, 5)
slope, y_int = ballpath(None, ballpos[0], ballpos[1])
while True:
for event in pygame.event.get():
direction = None
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if (event.key == K_UP or event.key == K_w):
paddleUP = True
elif (event.key == K_DOWN or event.key == K_s):
paddleDOWN = True
elif event.type == KEYUP:
if (event.key == K_UP or event.key == K_w):
paddleUP = False
elif (event.key == K_DOWN or event.key == K_s):
paddleDOWN = False
# move player paddle
if paddleUP and paddle >= 20:
paddle-=SPEED
elif paddleDOWN and paddle <= 460:
paddle+=SPEED
# move AI paddle
if ballpos[0] > (AISIGHT):
if AIpaddle-20 < ballpos[1] and AIpaddle <= 460:
AIpaddle+=SPEED/DIFF
elif AIpaddle+20 > ballpos[1] and AIpaddle >= 20:
AIpaddle-=SPEED/DIFF
# move ball
x = ballpos[0] + ball_speed
y = (slope*x) + y_int
ballpos = (x, y)
# if it hits a paddle
if 9 < ballpos[0] < 11:
if paddle-20 < ballpos[1] < paddle+20:
slope, y_int = ballpath(None, ballpos[0], ballpos[1])
ball_speed*=-1
elif 629 < ballpos[0] < 631:
if AIpaddle-20 < ballpos[1] < AIpaddle+20:
slope, y_int = ballpath(None, ballpos[0], ballpos[1])
ball_speed*=-1
# if it hits the top or bottom
if WINHEI-5 > ballpos[1] or ballpos[1] < 5:
slope, y_int = ballpath(slope, ballpos[0], ballpos[1])
# if paddle misses ball
if ballpos[0] < 5:
AIpoint+=1
score = "Player:%2f || Computer:%2f" % (PLAYERpoint, AIpoint)
ballpos = (WINWID/2, WINHEI/2)
pygame.draw.rect(DISPLAYSURF, (0, 0, 0, 100), pygame.Rect(0, 0, 640, 480))
DISPLAYSURF.blit(BIGGERFONT.render("Point: Computer", 1, PADDLECOLOR), (WINWID/3, WINHEI/3))
paddle, AIpaddle = WINWID/2, WINWID/2
for i in range(5):
FPSCLOCK.tick(FPS)
elif ballpos[0] > 635 and AIpaddle-20 < ballpos[1] < AIpaddle+20:
PLAYERpoint+=1
score = "Player:%2f || Computer:%2f" % (PLAYERpoint, AIpoint)
ballpos = (WINWID/2, WINHEI/2)
pygame.draw.rect(DISPLAYSURF, (0, 0, 0, 100), pygame.Rect(0, 0, 640, 480))
DISPLAYSURF.blit(BIGGERFONT.render("Point: Player", 1, PADDLECOLOR), (WINWID/3, WINHEI/3))
for i in range(5):
FPSCLOCK.tick(FPS)
pygame.draw.rect(DISPLAYSURF, BACKGROUNDCOLOR, BACKGROUND)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (9, paddle-20), (9, paddle+20), 3)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (629, AIpaddle-20), (629, AIpaddle+20), 3)
pygame.draw.circle(DISPLAYSURF, BALLCOLOR, ballpos, 5)
DISPLAYSURF.blit(DEFAULTFONT.render(score, 1, PADDLECOLOR), (WINWID/3, 20))
pygame.display.update()
FPSCLOCK.tick(FPS)
def ballpath(old_slope, ball_x, ball_y):
if old_slope == None:
slope = int(random.random() * 2)
else:
slope = old_slope * -1
y_int = ball_y - (slope * ball_x)
return slope, y_int
def terminate():
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()
I cleaned up your code quite a bit. It should help a bit with how to use the classes. http://pastebin.com/rZF3Gr0D
Things to note:
prints when score event happens
paddle movement using keystate vs "on events". It makes that kind of input easier.
Sprite group's let you 'draw' or check collisions in batches.
removed global keyword. Game owns most things.
Using Rect functions and properties all over the place. Such as ball.rect.center = screen.get_rect().center .
random angle for ball spawns via trig.
caps framerate. Next you would move onto time-based movement. I left that out for simplicity.
Color() lets you do many things, including Color("red"), Color("gray40") , etc...

Categories