You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame平台游戏动画列表索引持续越界问题求助

问题:Pygame平台游戏动画列表索引越界异常

游戏经常无法正常启动,仅在调试模式下可运行,报错为动画列表索引越界,报错位置为代码中的self.image = self.animations['idle'][self.frame_index]。已确认所有动画列表项配置完整,替换为教程原型工程并导入自身资源后问题仍存在。预期效果为角色根据自身状态播放对应动画。

附player.py代码

import pygame 
from support import import_folder

class Player(pygame.sprite.Sprite):
    def __init__(self,pos,surface,create_jump_particles):
        super().__init__()
        self.import_character_assets()
        self.frame_index = 0
        self.animation_speed = 0.15
        self.image = self.animations['idle'][self.frame_index]
        self.rect = self.image.get_rect(topleft = pos)
        
        # dust particles 
        self.import_dust_run_particles()
        self.dust_frame_index = 0
        self.dust_animation_speed = 0.15
        self.display_surface = surface
        self.create_jump_particles = create_jump_particles

        # player movement
        self.direction = pygame.math.Vector2(0,0)
        self.speed = 8
        self.gravity = 0.8
        self.jump_speed = -16

        # player status
        self.status = 'idle'
        self.facing_right = True
        self.on_ground = False
        self.on_ceiling = False
        self.on_left = False
        self.on_right = False

    def import_character_assets(self):
        character_path = '../graphics/character/'
        self.animations = {'idle':[],'run':[],'jump':[],'fall':[]}

        for animation in self.animations.keys():
            full_path = character_path + animation
            self.animations[animation] = import_folder(full_path)

    def import_dust_run_particles(self):
        self.dust_run_particles = import_folder('../graphics/character/dust_particles/run')

    def animate(self):
        animation = self.animations[self.status]

        # loop over frame index 
        self.frame_index += self.animation_speed
        if self.frame_index >= len(animation):
            self.frame_index = 0

        image = animation[int(self.frame_index)]
        if self.facing_right:
            self.image = image
        else:
            flipped_image = pygame.transform.flip(image,True,False)
            self.image = flipped_image

        # set the rect
        if self.on_ground and self.on_right:
            self.rect = self.image.get_rect(bottomright = self.rect.bottomright)
        elif self.on_ground and self.on_left:
            self.rect = self.image.get_rect(bottomleft = self.rect.bottomleft)
        elif self.on_ground:
            self.rect = self.image.get_rect(midbottom = self.rect.midbottom)
        elif self.on_ceiling and self.on_right:
            self.rect = self.image.get_rect(topright = self.rect.topright)
        elif self.on_ceiling and self.on_left:
            self.rect = self.image.get_rect(topleft = self.rect.topleft)
        elif self.on_ceiling:
            self.rect = self.image.get_rect(midtop = self.rect.midtop)

    def run_dust_animation(self):
        if self.status == 'run' and self.on_ground:
            self.dust_frame_index += self.dust_animation_speed
            if self.dust_frame_index >= len(self.dust_run_particles):
                self.dust_frame_index = 0

            dust_particle = self.dust_run_particles[int(self.dust_frame_index)]

            if self.facing_right:
                pos = self.rect.bottomleft - pygame.math.Vector2(6,10)
                self.display_surface.blit(dust_particle,pos)
            else:
                pos = self.rect.bottomright - pygame.math.Vector2(6,10)
                flipped_dust_particle = pygame.transform.flip(dust_particle,True,False)
                self.display_surface.blit(flipped_dust_particle,pos)

    def get_input(self):
        keys = pygame.key.get_pressed()

        if keys[pygame.K_RIGHT]:
            self.direction.x = 1
            self.facing_right = True
        elif keys[pygame.K_LEFT]:
            self.direction.x = -1
            self.facing_right = False
        else:
            self.direction.x = 0

        if keys[pygame.K_SPACE] and self.on_ground:
            self.jump()
            self.create_jump_particles(self.rect.midbottom)

    def get_status(self):
        if self.direction.y < 0:
            self.status = 'jump'
        elif self.direction.y > 1:
            self.status = 'fall'
        else:
            if self.direction.x != 0:
                self.status = 'run'
            else:
                self.status = 'idle'

    def apply_gravity(self):
        self.direction.y += self.gravity
        self.rect.y += self.direction.y

    def jump(self):
        self.direction.y = self.jump_speed

    def update(self):
        self.get_input()
        self.get_status()
        self.animate()
        self.run_dust_animation()

解决方案

1. 修复资源路径问题(调试与正常运行的工作目录差异)

调试模式和正常运行时的工作目录可能不同,导致相对路径失效。改用动态路径拼接:

import os

# 修改import_character_assets方法
def import_character_assets(self):
    script_dir = os.path.dirname(os.path.abspath(__file__))
    character_path = os.path.join(script_dir, '../graphics/character/')
    self.animations = {'idle':[],'run':[],'jump':[],'fall':[]}

    for animation in self.animations.keys():
        full_path = os.path.join(character_path, animation)
        self.animations[animation] = import_folder(full_path)

# 修改import_dust_run_particles方法
def import_dust_run_particles(self):
    script_dir = os.path.dirname(os.path.abspath(__file__))
    dust_path = os.path.join(script_dir, '../graphics/character/dust_particles/run')
    self.dust_run_particles = import_folder(dust_path)

2. 验证资源加载结果

在资源加载后添加检查,确认每个动画列表是否有帧:

def import_character_assets(self):
    # ...原路径代码...
    for animation in self.animations.keys():
        full_path = os.path.join(character_path, animation)
        self.animations[animation] = import_folder(full_path)
        # 打印加载结果,确认是否有帧
        print(f"{animation}动画加载帧数: {len(self.animations[animation])}")

如果输出为0,说明import_folder未正确读取文件,需检查该函数是否过滤了非图片文件、文件名是否正确。

3. 添加空列表防护,避免索引越界

初始化和动画更新时,先判断列表是否为空:

# 修改__init__中的image初始化
def __init__(self,pos,surface,create_jump_particles):
    super().__init__()
    self.import_character_assets()
    self.frame_index = 0
    self.animation_speed = 0.15
    
    # 空列表防护
    idle_frames = self.animations.get('idle', [])
    if idle_frames:
        self.image = idle_frames[self.frame_index]
    else:
        # 临时生成红色占位图,提示资源加载失败
        self.image = pygame.Surface((32, 32))
        self.image.fill('red')
    
    self.rect = self.image.get_rect(topleft = pos)
    # ...其余代码...
# 修改animate方法,添加空列表检查
def animate(self):
    animation = self.animations[self.status]
    if not animation:
        return  # 无帧则跳过动画更新
    
    # ...原动画逻辑...

内容的提问来源于stack exchange,提问作者murayeeto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:15:35