简单的Pygame动画口吃

时间:2016-10-03 16:38:55

标签: python pygame

我正在学习python *\(^o^)/*

我有一个使用Pygame绘制的简单弹跳框窗口。除了一个小麻烦外,一切似乎都运转正常。它不断口吃!我不知道是什么原因导致口吃。我认为它可能是滞后的,所以我实现了一个固定的时间步骤以允许循环赶上,但这没有任何影响。

#--- initialize pygame window ---#
import pygame
import time
pygame.init()
size = (1200,500)
screen = pygame.display.set_mode(size, pygame.RESIZABLE)
fps = 60

#--- define color palette ---#
black = (0,0,0)
white = (255,255,255)

#--- define the player ---#
class player:
    def __init__(self,screen,surface, color):
        self.speed = 3
        self.direction_x = 1
        self.direction_y = 1
        self.screen = screen
        self.surface = surface
        self.rect = self.surface.get_rect()
        self.color = color
    def set_pos(self, x,y):
        self.rect.x = x
        self.rect.y = y
    def advance_pos(self):
        screen_width, screen_height = screen.get_size()
        if self.rect.x + self.rect.width > screen_width or player1.rect.x < 0:
            player1.direction_x *= -1
            player1.speed = 3
        elif player1.rect.y + player1.rect.height > screen_height or player1.rect.y < 0:
            player1.direction_y *= -1
            player1.speed = 3
        else:
            player1.speed -= 0.001
        self.rect.x += self.speed * self.direction_x
        self.rect.y += self.speed * self.direction_y
    def draw(self):
        pygame.draw.rect(self.surface, self.color, [0,0,self.rect.width,self.rect.height])
    def blit(self):
        screen.blit(self.surface, self.rect)
player1 = player(screen, pygame.Surface((50,50)), white)
player1.set_pos(50,50)
player1.draw()

#--- define game variables ---#
previous = time.time() * 1000
lag = 0.0
background = black
done = False

#--- game ---#
while not done:

    #--- update time step ---#
    current = time.time() * 1000
    elapsed = current - previous
    lag += elapsed
    previous = current

    #--- process events ---#
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
            break
        if event.type == pygame.VIDEORESIZE:
            screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)

    #--- update logic ---#

    while True:
        player1.advance_pos()
        lag -= fps
        if lag <= fps:
            break

    #--- draw to screen ---#
    screen.fill(background)
    player1.blit()
    pygame.display.update()
    pygame.time.Clock().tick(fps)

2 个答案:

答案 0 :(得分:1)

这是对代码的重写,它使用opengl代替渲染。主要变化如下:

  1. 我使用的是opengl立即模式,它已经过时并且已弃用,但最初要容易理解。大多数gl调用都在player.draw()方法或主循环中。
  2. 我修正了计时器的完成方式。我不是手动执行clock.tick(fps),而是手动跟踪对帧执行所有处理所需的时间,并添加适当的毫秒延迟以达到60 fps。您可以在迁移到opengl之前尝试使用现有的pygame代码进行修改,因为这可能足以删除大部分断断续续的内容。

    import pygame
    import time
    from OpenGL.GL import *
    
    class Player:
        def __init__(self, screen, width, height, color):
            self.x = 0
            self.y = 0
            self.speed = 3
            self.direction_x = 1
            self.direction_y = 1
            self.screen = screen
            self.width = width
            self.height = height
            self.color = color
    
        def set_pos(self, x, y):
            self.x = x
            self.y = y
    
        def advance_pos(self):
            screen_width, screen_height = screen.get_size()
            if self.x + self.width > screen_width or self.x < 0:
                self.direction_x *= -1
                self.speed = 3
            elif self.y + self.height > screen_height or self.y < 0:
                self.direction_y *= -1
                self.speed = 3
            else:
                self.speed -= 0.001
            self.x += self.speed * self.direction_x
            self.y += self.speed * self.direction_y
    
        def draw(self):
            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()
            glTranslate(self.x, self.y, 0)
            glBegin(GL_QUADS)
            glColor(*self.color)
            glVertex(0, 0, 0)
            glVertex(self.width, 0, 0)
            glVertex(self.width, self.height, 0)
            glVertex(0, self.height, 0)
            glEnd()
    
    if __name__ == "__main__":
        pygame.init()
        size = width, height = (550, 400)
        screen = pygame.display.set_mode(size, pygame.RESIZABLE | pygame.DOUBLEBUF | pygame.OPENGL)
        fps = 60
        black = (0,0,0,255)
        white = (255,255,255,255)
    
        player1 = Player(screen, 50, 50, white)
        player1.set_pos(50,50)
    
        done = False
        previous = time.time() * 1000
        glClearColor(*black)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(0, width, height, 0, -1, 1)
        clock = pygame.time.Clock()
    
        while not done:
            current = time.time() * 1000
            elapsed = current - previous
            previous = current
            delay = 1000.0/fps - elapsed
            delay = max(int(delay), 0)
    
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True
                    break
                if event.type == pygame.VIDEORESIZE:
                    size = width, height = event.w, event.h
                    screen = pygame.display.set_mode(size, pygame.RESIZABLE | pygame.DOUBLEBUF | pygame.OPENGL)
                    glMatrixMode(GL_PROJECTION)
                    glLoadIdentity()
                    glOrtho(0, width, height, 0, -1, 1)
                    glViewport(0, 0, width, height)
    
                    #reset player movement and position to avoid glitches where player is trapped outside new window borders
                    player1.set_pos(50, 50)
                    player1.direction_x = 1
                    player1.direction_y = 1
    
            player1.advance_pos()
            glClear(GL_COLOR_BUFFER_BIT)
            glClear(GL_DEPTH_BUFFER_BIT)
            player1.draw()
            pygame.display.flip()
            pygame.time.delay(delay)
    

答案 1 :(得分:0)

我在进入“未完成”循环之前创建了一个时钟对象,不再有滞后现象

#--- initialize pygame window ---#
import pygame
import time
pygame.init()
size = (1200,500)
screen = pygame.display.set_mode(size, pygame.RESIZABLE)
fps = 60

#--- define color palette ---#
black = (0,0,0)
white = (255,255,255)

#--- define the player ---#
class player:
    def __init__(self,screen,surface, color):
        self.speed = 3
        self.direction_x = 1
        self.direction_y = 1
        self.screen = screen
        self.surface = surface
        self.rect = self.surface.get_rect()
        self.color = color
    def set_pos(self, x,y):
        self.rect.x = x
        self.rect.y = y
    def advance_pos(self):
        screen_width, screen_height = screen.get_size()
        if self.rect.x + self.rect.width > screen_width or player1.rect.x < 0:
            player1.direction_x *= -1
            player1.speed = 3
        elif player1.rect.y + player1.rect.height > screen_height or player1.rect.y < 0:
            player1.direction_y *= -1
            player1.speed = 3
        else:
            player1.speed -= 0.001
        self.rect.x += self.speed * self.direction_x
        self.rect.y += self.speed * self.direction_y
    def draw(self):
        pygame.draw.rect(self.surface, self.color, [0,0,self.rect.width,self.rect.height])
    def blit(self):
        screen.blit(self.surface, self.rect)
player1 = player(screen, pygame.Surface((50,50)), white)
player1.set_pos(50,50)
player1.draw()

#--- define game variables ---#
previous = time.time() * 1000
lag = 0.0
background = black
done = False
clock=pygame.time.Clock()

#--- game ---#
while not done:

    #--- update time step ---#
    current = time.time() * 1000
    elapsed = current - previous
    lag += elapsed
    previous = current

    #--- process events ---#
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
            break
        if event.type == pygame.VIDEORESIZE:
            screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)

    #--- update logic ---#

    while True:
        player1.advance_pos()
        lag -= fps
        if lag <= fps:
            break

    #--- draw to screen ---#
    screen.fill(background)
    player1.blit()
    pygame.display.update()
    clock.tick(fps)

pygame.quit()