【问题标题】:Exception using sprite with pyganim将精灵与 pyganim 一起使用时出现异常
【发布时间】:2026-01-02 04:35:01
【问题描述】:

美好的一天。我正在尝试编写一个平台游戏。创建地图、创建角色、交互和摄像机移动等基本操作已经实现。有4个文件:

游戏.py:

负责创建窗口,并绘制其余部分。还用于在执行任何操作时启用和禁用标志。

import pygame
from pygame import *
import Camera as cam
import Player as plr
import Platform as plfm


WIN_WIDTH = 800
WIN_HEIGHT = 640
HALF_WIDTH = int(WIN_WIDTH / 2)
HALF_HEIGHT = int(WIN_HEIGHT / 2)

DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 32
FLAGS = 0
CAMERA_SLACK = 30


def main():
    global cameraX, cameraY
    pygame.init()
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH)
    pygame.display.set_caption("JohnTeeworlds")
    timer = pygame.time.Clock()

    up = down = left = right = running = False
    bg = Surface((32,32))
    bg.convert()
    bg.fill(Color("#000000"))
    entities = pygame.sprite.Group()
    player = plr.Player(32, 32)
    platforms = []

    x = y = 0
    level = [
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                    PPPPPPPPPPP           P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P    PPPPPPPP                              P",
        "P                                          P",
        "P                          PPPPPPP         P",
        "P                 PPPPPP                   P",
        "P                                          P",
        "P         PPPPPPP                          P",
        "P                                          P",
        "P                     PPPPPP               P",
        "P                                          P",
        "P   PPPPPPPPPPP                            P",
        "P                                          P",
        "P                 PPPPPPPPPPP              P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]
    # build the level
    for row in level:
        for col in row:
            if col == "P":
                p = plfm.Platform(x, y)
                platforms.append(p)
                entities.add(p)
            if col == "E":
                e = plfm.ExitBlock(x, y)
                platforms.append(e)
                entities.add(e)
            x += 32
        y += 32
        x = 0

    total_level_width  = len(level[0])*32
    total_level_height = len(level)*32
    camera = cam.Camera(cam.complex_camera, total_level_width, total_level_height)
    entities.add(player)

    while 1:
        timer.tick(60)

        for e in pygame.event.get():
            if e.type == QUIT:
                raise SystemExit
            if e.type == KEYDOWN and e.key == K_ESCAPE:
                raise SystemExit
            if e.type == KEYDOWN and e.key == K_w:
                up = True
            if e.type == KEYDOWN and e.key == K_s:
                down = True
            if e.type == KEYDOWN and e.key == K_a:
                left = True
            if e.type == KEYDOWN and e.key == K_d:
                right = True
            if e.type == KEYDOWN and e.key == K_SPACE:
                running = True

            if e.type == KEYUP and e.key == K_w:
                up = False
            if e.type == KEYUP and e.key == K_s:
                down = False
            if e.type == KEYUP and e.key == K_d:
                right = False
            if e.type == KEYUP and e.key == K_a:
                left = False

        # draw background
        for y in range(32):
            for x in range(32):
                screen.blit(bg, (x * 32, y * 32))

        camera.update(player)

        # update player, draw everything else
        player.update(up, down, left, right, running, platforms)
        for e in entities:
            screen.blit(e.image, camera.apply(e))

        pygame.display.update()


if __name__ == "__main__":
    main()

平台.py:

只是描述它们外观的一类平台。

from pygame import *


class Entity(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()


class Platform(Entity):
    def __init__(self, x, y):
        super().__init__()
        self.image = Surface((32, 32))
        self.image.convert()
        self.image.fill(Color("#DDDDDD"))
        self.rect = Rect(x, y, 32, 32)

    def update(self):
        pass

class ExitBlock(Platform):
    def __init__(self, x, y):
        super().__init__(x,y)
        self.image.fill(Color("#0033FF"))

播放器.py:

类玩家。在这里,我们已经在处理运动、重力,好吧,我正在尝试向我的角色询问精灵,目前处于“等待”状态。这里出现错误,我会在下面描述。

import pygame
from pygame.sprite import Sprite
from pygame import Surface, Rect
import pygame.image
import Platform as plfm
import pyganim


ANIMATION_DELAY = 0.1
ANIMATION_STAY = [('images/player/player_stay/1.png', ANIMATION_DELAY)]


class Entity(Sprite):
    def __init__(self):
        super().__init__()


class Player(Entity):
    def __init__(self, x, y):
        super().__init__()
        self.xvel = 0
        self.yvel = 0
        self.onGround = False
        self.image = Surface((30,93))
        self.image.convert()
        self.rect = Rect(x, y, 30, 93)
        self.image.set_colorkey((0, 0, 0))
        self.bolt_anim_stay = pyganim.PygAnimation(ANIMATION_STAY)
        self.bolt_anim_stay.play()

    def update(self, up, down, left, right, running, platforms):
        if up:
            # only jump if on the ground
            if self.onGround: self.yvel -= 10
        if down:
            pass
        if running:
            self.xvel = 12
        if left:
            self.xvel = -8
        if right:
            self.xvel = 8
        if not self.onGround:
            # only accelerate with gravity if in the air
            self.yvel += 0.3
            # max falling speed
            if self.yvel > 100: self.yvel = 100
        if not(left or right):
            self.xvel = 0
            if not up:
                self.image.fill((0, 0, 0))
                self.bolt_anim_stay.blit(self.image, (0, 0))
        # increment in x direction
        self.rect.left += self.xvel
        # do x-axis collisions
        self.collide(self.xvel, 0, platforms)
        # increment in y direction
        self.rect.top += self.yvel
        # assuming we're in the air
        self.onGround = False
        # do y-axis collisions
        self.collide(0, self.yvel, platforms)

    def collide(self, xvel, yvel, platforms):
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if isinstance(p, plfm.ExitBlock):
                    pygame.event.post(pygame.event.Event(QUIT))
                if xvel > 0:
                    self.rect.right = p.rect.left
                if xvel < 0:
                    self.rect.left = p.rect.right
                if yvel > 0:
                    self.rect.bottom = p.rect.top
                    self.onGround = True
                    self.yvel = 0
                if yvel < 0:
                    self.rect.top = p.rect.bottom

还有 Camera.py:

摄像机的类,用于监控玩家在关卡上的移动。

from pygame import *
import Game as game


class Camera:
    def __init__(self, camera_func, width, height):
        self.camera_func = camera_func
        self.state = Rect(0, 0, width, height)

    def apply(self, target):
        return target.rect.move(self.state.topleft)

    def update(self, target):
        self.state = self.camera_func(self.state, target.rect)

def simple_camera(camera, target_rect):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    return Rect(-l+game.HALF_WIDTH, -t+game.HALF_HEIGHT, w, h)

def complex_camera(camera, target_rect):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    l, t, _, _ = -l+game.HALF_WIDTH, -t+game.HALF_HEIGHT, w, h

    l = min(0, l)                           # stop scrolling at the left edge
    l = max(-(camera.width-game.WIN_WIDTH), l)   # stop scrolling at the right edge
    t = max(-(camera.height-game.WIN_HEIGHT), t) # stop scrolling at the bottom
    t = min(0, t)                           # stop scrolling at the top
    return Rect(l, t, w, h)

问题是我试图用图片创建一个对象。这是 ANIMATION_STAY。 然后我这样做,如果角色没有去任何地方,也没有跳跃,那么我会尝试绘制这个对象。

    if not(left or right):
        self.xvel = 0
        if not up:
            self.image.fill((0, 0, 0))
            self.bolt_anim_stay.blit(self.image, (0, 0))

同样在构造函数中,我正在尝试播放这个动画。

    self.bolt_anim_stay = pyganim.PygAnimation(ANIMATION_STAY)
    self.bolt_anim_stay.play()

当你启动程序时会出现这个异常:

Traceback(最近一次调用最后一次):

文件“C:/Users/User/PycharmProjects/teeworlds/Game.py”,第 125 行,在 主要()

文件“C:/Users/User/PycharmProjects/teeworlds/Game.py”,第 31 行,在 main player = plr.Player(32, 32)

文件“C:\Users\User\PycharmProjects\teeworlds\Player.py”,第 28 行,在 init 中 self.bolt_anim_stay = pyganim.PygAnimation(ANIMATION_STAY)

文件“C:\Users\User\PycharmProjects\teeworlds\venv\lib\site-packages\pyganim__init__.py”,第 168 行,在 init

assert frame[1] > 0, 'Frame %s duration must be greater than zero.' % (i)

AssertionError:第 0 帧持续时间必须大于零。

我不明白错误是什么,在哪里,一般是什么原因造成的。我将不胜感激。

精灵本身,如果需要的话:

【问题讨论】:

  • 在 self.image.fill 中你不应该提供颜色吗?这不是必需的参数吗?
  • @Thunderwood 喜欢这种颜色(“#DDDDDD”)?我看了视频指南,那里的人指出了这样的颜色(0, 0, 0)
  • 你说得对,它的RGB,我的错
  • 尝试将动画延迟设置为 1 并告诉我是否遇到同样的错误
  • 抱歉删除了我之前的答案,Pyganimation 的来源有几个名称非常相似的变量,我把它们弄糊涂了,这让我的答案大打折扣大声笑

标签: python python-3.x animation pygame sprite


【解决方案1】:

Pyganimation Class 的源中,帧被定义为元组列表中的每个元素。在您的程序中,此列表称为ANIMATION_STAY

ANIMATION_STAY 中,您将延迟的值设置为0.1,这是您的错误。 ANIMATION_DELAY 应该是整数,而不是浮点数或双精度数,因此请使用整数而不是 0.1

稍后在源代码中执行此操作时: assert frame[1] &gt; 0, 'Frame %s duration must be greater than zero.' % (i),它会引发错误。您的延迟需要为&gt;0,但它正在向下舍入为0

【讨论】:

  • 如果将 ANIMATION_DELAY 设置为 1,则动画播放速度非常快,而且,就在那里弄清楚了。非常感谢你:
  • 常用时间是 100。我相信这对应于 .1s