简体   繁体   English

为什么这个pygame代码会滞后?

[英]Why does this pygame code lag?

I am trying to write this simple pygame pong game. 我正在尝试编写这个简单的pygame pong游戏。 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 ). 您的球以2个像素的速度垂直和水平移动( x+=2分别为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 . 但是,如果您的球垂直移动(让x+=2y+=2 ),那么球的实际速度不是2,而是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. 通过Font渲染文本是非常昂贵的操作。 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. 每个循环可以多次调用draw_stuff

  • 200 FPS is way to high. 200 FPS是很高的方法。 Try something lower, like 60 FPS 尝试更低的速度,例如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. 请注意,还可以进行其他一些改进,但这可以解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM