質問

I am hitting an issue after writing a small program with pygame. The program takes split .GIF animations and loads the images(frames of the gif) via:

pygame.image.load(filename)

This returns a pygame surface object which is then appended to an array. The program loads about 15 frames to an array, using 6 arrays in total.

The problem I am having is when accepting input through my while loop. The loop plays its idle animation and running animation fine, however, on accepting input from the keyboard (grabbing input from pygame's event list...)

for event in pygame.event.get(): via pygame.KEYDOWN

There is very noticeable lag, making for unresponsive animation set switching. If I am to make a game using this method, it will have to be fixed. I'm sure my code is inefficient, but it should suffice not to create pauses. Any help would be fantastic.

My guess? pygame.clock.tick() is creating some sort of event lag, but I am unsure as to how to go about fixing this, if event lag is even the case.

Here is the loop that I suspect to be problematic:

while running == 2:
pygame.display.flip()
#mouse = pygame.mouse.get_pos()
#events = pygame.event.get()
#(pygame.QUIT, pygame.KEYDOWN, pygame.KEYUP)
for event in pygame.event.get():
#event = pygame.event.wait()
    if event.type == pygame.QUIT:
        sys.exit(0)
    elif event.type == pygame.KEYDOWN:
        print event.key
        wait = 0
        if event.key == pygame.K_d:
            tmpcache = wr
            lastkey = "wr"
        elif event.key == pygame.K_a:
            tmpcache = wl
            lastkey = "wl"
    elif event.type == pygame.KEYUP:
        wait = 1
        if lastkey == "wr":
            tmpcache = sr
        elif lastkey == "wl":
            tmpcache = sl

if wait == 1:           
    for frame in tmpcache:
        screen.blit(test, (0,0))
        screen.blit(frame, (currentchar.posx, currentchar.posy))
        pygame.display.flip()
        clock.tick(charfps)

else:
    for frame in tmpcache:
        screen.blit(test, (0,0))
        screen.blit(frame, (currentchar.posx, currentchar.posy))
        pygame.display.flip()
        clock.tick(charfps)

some variables not shown here, but are used:

charfps = 30
currentchar.posx, currentchar.posy are both tuples set at (300, 240)

役に立ちましたか?

解決

Your problem is that you create sub-loops inside your main-loop:

while running == 2:
    pygame.display.flip()
    for event in pygame.event.get():
        ...
    for frame in tmpcache:
        screen.blit(test, (0,0))
        screen.blit(frame, (currentchar.posx, currentchar.posy))
        pygame.display.flip()
        clock.tick(charfps)

So if there are 15 elements in tmpcache, you're calling clock.tick() 15 time per frame, and while code runs inside this sub loop, you don't proceed events.

Simply calling pygame.display.flip() and clock.tick(charfps) only once per frame should resolve your issue.

Here's a simple example, changing the image of the animation three times a second, while running at 60 FPS:

import pygame
from collections import deque

pygame.init()
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()

# just some colored squares for our animation
def get_cache(colors):
    tmp=[]
    for c in colors:
        s = pygame.surface.Surface((50,50))
        s.fill(pygame.color.Color(c))
        tmp.append(s)
    return tmp

walk_left, walk_right = get_cache(('red', 'yellow', 'blue')), get_cache(('black', 'white', 'grey'))

rect = walk_left[0].get_rect(top=100, right=100)
cachedeque = deque(walk_left)
state = None
quit = False

# a simple variable to keep track of time
timer = 0

# a dict of {key: (animation, direction)}
moves = {pygame.K_LEFT:  (walk_left,  (-2, 0)),
         pygame.K_RIGHT: (walk_right, ( 2, 0))}

while not quit:
    quit = pygame.event.get(pygame.QUIT)
    pygame.event.poll()

    # state of the keys
    keys = pygame.key.get_pressed()

    # filter for the keys we're interessted in
    pressed = ((key, _) for (key, _) in moves.iteritems() if keys[key])
    key, (cache, dir) = next(pressed, (None, (None, None)))

    # if a key of the 'moves' dict is pressed:
    if key:
        # if we change the direction, we need another animation
        if state != key: 
            cachedeque = deque(cache)
            state = key
        # move the square                
        rect.move_ip(dir) 
    else:
        state = None

    screen.fill(pygame.color.Color('green'))

    # display first image in cachedeque    
    screen.blit(cachedeque[0], rect)

    # rotate cachedeque to the left, so the second image becomes the first
    # do this three times a second:
    if state and timer >= 1000./3:
        cachedeque.rotate(-1)
        timer = 0

    # call flip() and tick() only once per frame
    pygame.display.flip()

    # keep track of how long it took to draw this frame
    timer += clock.tick(60)

enter image description here

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top