2

我正在尝试编写这个简单的 pygame pong 游戏。我还没有完成,但我的代码有很多滞后,我不知道为什么。滞后发生在球从桨上反弹时,它似乎有一个无意的速度爆发。看到这一点的最好方法是运行代码:

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)
4

1 回答 1

0

主要有四个错误:

  • 您的球以2 个像素(x+=2分别 y+=2)的速度垂直和水平移动。但是如果你的球垂直移动(让我们x+=2y+=2),球的实际速度不是 2,而是sqrt(2**2 + 2**2)= 2.828

    因此,要执行对角线移动等操作,您需要移动以创建移动向量,对其进行归一化,然后对其应用速度(通过乘法)。

  • 通过 a 渲染文本Font是一项非常昂贵的操作。您应该缓存新创建的表面,这样您就不必一次又一次地渲染相同的文本。如果您使用大量文本,这将大大提高性能。

  • draw_stuff每个循环可以多次调用。

  • 200 FPS 太高了。尝试更低的速度,例如 60 FPS

修复了这些问题的完整代码(我的更改在 - 注释下方###):

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)

请注意,还有一些其他可能的改进,但这应该可以解决您的问题。

于 2013-07-11T07:51:45.137 回答