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

Python Arcade 2D僵尸射击游戏添加GUI按钮报AttributeError

问题根因
  • 你把主菜单UI的UIManager(也就是代码里的self.manager)初始化逻辑全部写在了独立的MyWindow类中,但程序入口main()函数实际实例化运行的是MyGame类窗口,MyWindow从未被调用,其中初始化manager的代码压根没有执行。
  • MyGame类的__init__方法中从未定义self.manager属性,却在on_draw方法中直接调用self.manager.draw(),必然触发属性不存在的报错。
  • 额外逻辑缺陷:你写的on_click_start方法仅打印日志,没有实现菜单隐藏、游戏启动的状态切换,就算修复属性问题,点击开始按钮也无法进入游戏。
修复步骤
  1. 删除无用的MyWindow类,将UI初始化逻辑整合到MyGame类中
  2. 给MyGame增加状态标记,区分「主菜单」「游戏中」两种状态,避免菜单和游戏内容同时渲染
  3. 补全按钮点击的状态切换逻辑

具体代码修改

修改MyGame类的__init__方法

在原有初始化逻辑末尾添加UI和状态相关初始化代码:

def __init__(self, width, height, title):
    super().__init__(width, height, title)

    # 保留原有精灵列表、按键状态、背景色等初始化代码不变
    self.player_list = None
    self.player_sprite = None
    self.left_pressed = False
    self.right_pressed = False
    self.up_pressed = False
    self.down_pressed = False
    arcade.set_background_color(arcade.color.AMAZON)

    # --- 新增内容开始 ---
    # 游戏状态标记:False=显示主菜单,True=进入游戏
    self.game_started = False

    # 初始化UI管理器
    self.manager = arcade.gui.UIManager()
    self.manager.enable()

    # 创建垂直布局容器排列按钮
    self.v_box = arcade.gui.UIBoxLayout()

    # 创建三个功能按钮
    start_button = arcade.gui.UIFlatButton(text="开始游戏", width=200)
    self.v_box.add(start_button.with_space_around(bottom=20))

    settings_button = arcade.gui.UIFlatButton(text="设置", width=200)
    self.v_box.add(settings_button.with_space_around(bottom=20))

    quit_button = QuitButton(text="退出", width=200)
    self.v_box.add(quit_button)

    # 绑定按钮事件
    start_button.on_click = self.on_click_start

    @settings_button.event("on_click")
    def on_click_settings(event):
        print("打开设置面板")

    # 将按钮容器固定到窗口居中位置
    self.manager.add(
        arcade.gui.UIAnchorWidget(
            anchor_x="center_x",
            anchor_y="center_y",
            child=self.v_box
        )
    )
    # --- 新增内容结束 ---

修改开始按钮点击方法

替换原有的空实现,加入状态切换逻辑:

def on_click_start(self, event):
    self.game_started = True
    # 禁用UI管理器,隐藏主菜单
    self.manager.disable()
    # 加载游戏资源、初始化游戏内容
    self.setup()

修改on_draw渲染逻辑

按状态分别渲染菜单/游戏内容,避免未启动游戏时调用精灵绘制逻辑报错:

def on_draw(self):
    self.clear()
    if not self.game_started:
        # 主菜单状态仅渲染UI
        self.manager.draw()
    else:
        # 游戏状态渲染所有精灵和文字
        self.player_list.draw()
        self.enemy_list.draw()
        self.bullet_list.draw()

        output = f"Score: {self.score}"
        arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)

        output = f"Health: {self.health}"
        arcade.draw_text(output, 10, 40, arcade.color.WHITE, 14)

        if self.health <= 0:
            self.player_sprite.remove_from_sprite_lists()
            output = f"YOU DIED"
            arcade.draw_text(output, 500, 400, arcade.color.RED, 50)
            output = f"Click to Exit"
            arcade.draw_text(output, 550, 300, arcade.color.BLACK, 30)

修改程序入口

删除启动时主动调用setup()的逻辑,改为点击开始按钮后再初始化游戏内容:

def main():
    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    arcade.run()

改完后运行程序,会先显示居中的三个菜单按钮,点击开始游戏就会隐藏菜单进入僵尸射击玩法,点击退出直接关闭程序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:39:27