2013-07-10 71 views
2

我想寫這個簡單的pygame pong遊戲。我還沒有完成,但我的代碼有很多滯後,我不知道爲什麼。球從球拍反彈時就會發生滯後,這似乎是無意中爆發出的速度。 看到這一點,最好的方法是運行代碼:錯誤爲什麼這個pygame代碼滯後?

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) 
+0

[1]什麼樣的滯後? [2]每個循環你應該只有一個'pygame.display.update()'調用[3]我還不清楚你想要'loc_of_ballhitl'和'ball_hit'做什麼? – ninMonkey

回答

0

四個主要方面:

  • 你的球在像素(x+=2分別y+=2的速度垂直和水平移動)。但是如果你的球垂直移動(讓我們x+=2y+=2),球的實際速度不是2,但是sqrt(2**2 + 2**2) = 2.828

    因此,要做類似對角線運動的事情,您需要創建一個運動矢量,對其進行標準化,然後對其應用一個速度(通過乘法運算)。

  • 通過Font呈現文本是非常昂貴的操作。您應該緩存新創建的曲面,以便不必一次又一次渲染同一文本。如果使用大量文本,這將大大提高性能。

  • draw_stuff每個循環可以調用多次。

  • 200 FPS是高的方式。嘗試較低值,如60 FPS

這些問題固定的完整代碼(我的變化都低於### -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) 

注意,還有一些其他方面的改進可能的,但這應該解決你的問題。