I am trying to write this simple pygame pong game. I am not yet finished but my code has a lot of lag and i dont know why. The lag occurs when the ball bounces off the paddle, it seems to have an unintentional burst of speed. The best way to see this is to run the code :
import pygame, sys
import time
from pygame.locals import *
pygame.init()
fpsClock=pygame.time.Clock()
screen= pygame.display.set_mode((640,480))
pygame.display.set_caption('Test')
fontobj= pygame.font.Font('LCD_Solid.ttf',50)
mousex,mousey=0,0
x_1=15
x_2=600 #these varaibles (x_1, x_2) are different, but they are constants-- they will never change; think jon, the paddle will not move from left to right
y=0 #the y variable changes, but for this test it will be the same for both paddles bc they are moving in unisen.
x_ball=320
y_ball=240
direction=""
def draw_stuff (y):
msg=str(x_ball)
global x_ball,y_ball,direction
textobj=fontobj.render(msg, False , pygame.Color('green'))
screen.blit(textobj,(160,5))
screen.blit(textobj,(480,5))
pygame.draw.line(screen,pygame.Color('grey'),(320,0), (320,480), 4)
pygame.draw.line(screen,pygame.Color('grey'),(0,3), (640,3), 10)
pygame.draw.line(screen,pygame.Color('grey'),(0,475), (640,475), 10)
pygame.draw.rect(screen, pygame.Color('grey'),(x_1,y,30,192))
pygame.draw.rect(screen, pygame.Color('grey'),(x_2,y,30,192))
if x_ball==60 or x_ball==570:
print "we have reached the side",fpsClock.get_fps()
if ball_hit(y,x_ball,y_ball):
topl,middlel,bottoml=loc_of_ball_hitl(y,x_ball,y_ball)
topr,middler,bottomr=loc_of_ball_hitr(y,x_ball,y_ball)
if topl:
direction="upleft"
elif middlel:
direction='midleft'
elif bottoml:
direction='downleft'
elif topr:
direction="upright"
elif middler:
direction="midright"
elif bottomr:
direction="downright"
else:
direction=""
if not direction:
print "we have ",fpsClock.get_fps()
x_ball+=2
elif direction=="upleft":
x_ball+=2
y_ball-=2
elif direction=="midleft":
x_ball+=2
elif direction=="downleft":
x_ball+=2
y_ball+=2
elif direction=="upright":
x_ball-=2
y_ball-=2
elif direction=="midright":
x_ball-=2
elif direction=="downright":
x_ball-=2
y_ball+=2
ball(x_ball,y_ball)
def ball(x,y):
pygame.draw.circle(screen, pygame.Color('red'), (x,y), 15, 0)
pygame.display.update()
def ball_hit(y,ball_x,ball_y):
if ball_x==60 and ball_y>=y and ball_y<y+192 or ball_x==570 and ball_y>=y and ball_y<y+192:
return True
return False
def loc_of_ball_hitl(y,ball_x,ball_y):
middle=False
top=False
bottom=False
if ball_x==60 and ball_y>=y+64 and ball_y<y+128:
middle=True
elif ball_x==60 and ball_y>=y and ball_y<y+64:
top=True
elif ball_x==60 and ball_y>=y+128 and ball_y<y+192:
bottom=True
return top, middle, bottom
def loc_of_ball_hitr(y,ball_x,ball_y):
middle=False
top=False
bottom=False
if ball_x==570 and ball_y>=y+64 and ball_y<y+128:
middle=True
elif ball_x==570 and ball_y>=y and ball_y<y+64:
top=True
elif ball_x==570 and ball_y>=y+128 and ball_y<y+192:
bottom=True
return top, middle, bottom
while True:
screen.fill(pygame.Color('black'))
if mousey>y:
draw_stuff(y)
y+=2
if mousey<y:
draw_stuff(y)
y-=2
if mousey==y:
draw_stuff(y)
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
elif event.type== MOUSEMOTION:
mousex,mousey=event.pos
pygame.display.update()
fpsClock.tick(200)
Four main things wrong:
Your ball moves vertically and horizontally at a speed of 2 pixels ( x+=2
respectively y+=2
). But if your ball moves vertically (let's x+=2
and y+=2
), the actual speed of the ball is not 2, but sqrt(2**2 + 2**2)
= 2.828 .
So to do things like diagonal movement, you move to create a movement vector, normalize it, and then apply a speed to it (via multiplication).
Rendering a text via a Font
is a very expensive operation. You should cache newly created surfaces so you don't have to render the same text again and again. This will improve performance greatly if you use a lot of text.
draw_stuff
can get called multiple times per loop.
200 FPS is way to high. Try something lower, like 60 FPS
Full code with these issues fixed (my changes are below the ###
-comments):
import pygame, sys
import time
from pygame.locals import *
import math
### some simple vector helper functions, stolen from http://stackoverflow.com/a/4114962/142637
def magnitude(v):
return math.sqrt(sum(v[i]*v[i] for i in range(len(v))))
def add(u, v):
return [ u[i]+v[i] for i in range(len(u)) ]
def sub(u, v):
return [ u[i]-v[i] for i in range(len(u)) ]
def dot(u, v):
return sum(u[i]*v[i] for i in range(len(u)))
def normalize(v):
vmag = magnitude(v)
return [ v[i]/vmag for i in range(len(v)) ]
pygame.init()
fpsClock=pygame.time.Clock()
screen= pygame.display.set_mode((640,480))
pygame.display.set_caption('Test')
fontobj= pygame.font.SysFont('Arial',50)
mousex,mousey=0,0
x_1=15
x_2=600 #these varaibles (x_1, x_2) are different, but they are constants-- they will never change; think jon, the paddle will not move from left to right
y=0 #the y variable changes, but for this test it will be the same for both paddles bc they are moving in unisen.
x_ball=320
y_ball=240
direction=""
### the speed of the ball and the paddles
speed = 5
### a cache for font objects
cache={}
def get_msg(msg):
if not msg in cache:
cache[msg] = fontobj.render(msg, False , pygame.Color('green'))
return cache[msg]
def draw_stuff (y):
msg=str(x_ball)
global x_ball,y_ball,direction
### get the font surface from the cache
textobj=get_msg(msg)
screen.blit(textobj,(160,5))
screen.blit(textobj,(480,5))
pygame.draw.line(screen,pygame.Color('grey'),(320,0), (320,480), 4)
pygame.draw.line(screen,pygame.Color('grey'),(0,3), (640,3), 10)
pygame.draw.line(screen,pygame.Color('grey'),(0,475), (640,475), 10)
pygame.draw.rect(screen, pygame.Color('grey'),(x_1,y,30,192))
pygame.draw.rect(screen, pygame.Color('grey'),(x_2,y,30,192))
if x_ball==60 or x_ball==570:
print "we have reached the side",fpsClock.get_fps()
if ball_hit(y,x_ball,y_ball):
topl,middlel,bottoml=loc_of_ball_hitl(y,x_ball,y_ball)
topr,middler,bottomr=loc_of_ball_hitr(y,x_ball,y_ball)
if topl:
direction="upleft"
elif middlel:
direction='midleft'
elif bottoml:
direction='downleft'
elif topr:
direction="upright"
elif middler:
direction="midright"
elif bottomr:
direction="downright"
else:
direction=""
### create a vector
move = (0, 0)
if not direction:
print "we have ",fpsClock.get_fps()
move = (1, 0)
elif direction=="upleft":
move = (1, -1)
elif direction=="midleft":
move = (1, 0)
elif direction=="downleft":
move = (1, 1)
elif direction=="upright":
move = (-1, -1)
elif direction=="midright":
move = (-1, 0)
elif direction=="downright":
move = (-1, 1)
### normalize it and apply the speed
move = [int(c * speed) for c in normalize(move)]
### update ball position with movement vector
x_ball, y_ball = x_ball + move[0], y_ball + move[1]
ball(x_ball, y_ball)
def ball(x,y):
pygame.draw.circle(screen, pygame.Color('red'), (x,y), 15, 0)
pygame.display.update()
def ball_hit(y,ball_x,ball_y):
if ball_x==60 and ball_y>=y and ball_y<y+192 or ball_x==570 and ball_y>=y and ball_y<y+192:
return True
return False
def loc_of_ball_hitl(y,ball_x,ball_y):
middle=False
top=False
bottom=False
if ball_x==60 and ball_y>=y+64 and ball_y<y+128:
middle=True
elif ball_x==60 and ball_y>=y and ball_y<y+64:
top=True
elif ball_x==60 and ball_y>=y+128 and ball_y<y+192:
bottom=True
return top, middle, bottom
def loc_of_ball_hitr(y,ball_x,ball_y):
middle=False
top=False
bottom=False
if ball_x==570 and ball_y>=y+64 and ball_y<y+128:
middle=True
elif ball_x==570 and ball_y>=y and ball_y<y+64:
top=True
elif ball_x==570 and ball_y>=y+128 and ball_y<y+192:
bottom=True
return top, middle, bottom
while True:
screen.fill(pygame.Color('black'))
if mousey>y:
y+=speed
if mousey<y:
y-=speed
### call draw_stuff only once
draw_stuff(y)
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
elif event.type== MOUSEMOTION:
mousex,mousey=event.pos
pygame.display.update()
### realistic framerate
fpsClock.tick(60)
Note that there are some other improvements possible, but this should fix your issues.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.