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

Kivy GUI中如何不阻塞主线程实现代码等待用户决策输入?

解决方法

实现思路

你已经通过player_action回调把玩家选择的操作写入了player_action_pick属性,只需要借助asynckivy的异步等待能力,监听这个属性的变化即可,无需额外绑定按钮事件:

  • 将战斗逻辑改为异步函数,避免阻塞Kivy主线程导致UI无响应
  • 等待玩家操作时,直接监听player_action_pick属性的变更事件,只要用户按下任意按钮触发属性变化,就自动恢复执行
  • 玩家选择完成后重置按钮状态和属性值,方便下一轮操作使用

具体修改步骤

  1. 先安装依赖库:
pip install asynckivy
  1. 在Python代码头部导入asynckivy:
import asynckivy as ak
  1. 改造FightScreen类的相关方法:
  • 将fight方法改为异步方法
  • 进入战斗的on_enter方法用ak.start启动异步战斗逻辑
  • 玩家行动阶段等待player_action_pick属性变化即可

修改后的核心代码示例

class FightScreen(Screen):
    player_action_pick = StringProperty(rebind=True, allownone=True)

    def __init__(self, **kwargs):
        super(FightScreen, self).__init__(**kwargs)
        self.af_init = Clock.create_trigger(self._init)
        self.player_action_pick = None
        self.af_init()
        self.starting_hit = "Enemy"

    def _init(self, dt):
        self.app = App.get_running_app()

    # 改为异步方法
    async def fight(self, *args):
        hero_alive = True
        enemy_alive = True

        def enemy_move():
            # 敌方行动逻辑保持不变
            print("敌方执行攻击")
            return hero_alive

        async def player_move():
            # 等待玩家选择操作,只要属性发生变化就继续执行
            await ak.event(self, 'player_action_pick')
            # 拿到玩家选择的操作类型
            picked_action = self.player_action_pick
            print(f"玩家选择了操作:{picked_action}")
            # 重置所有ToggleButton状态为normal
            for btn in ToggleButtonBehavior.get_widgets('player_action'):
                btn.state = 'normal'
            # 重置属性值,方便下一轮等待
            self.player_action_pick = None
            # 后续玩家行动逻辑写在这里
            return enemy_alive

        # 回合制循环可以直接写在异步方法里,不会阻塞UI
        while hero_alive and enemy_alive:
            if self.starting_hit == "Enemy":
                print("-----敌方回合-----")
                hero_alive = enemy_move()
                if not hero_alive:
                    print("玩家战败,战斗结束")
                    break
                print("-----玩家回合-----")
                enemy_alive = await player_move()
                if not enemy_alive:
                    print("敌方战败,战斗结束")
                    break
            else:
                print("-----玩家回合-----")
                enemy_alive = await player_move()
                if not enemy_alive:
                    print("敌方战败,战斗结束")
                    break
                print("-----敌方回合-----")
                hero_alive = enemy_move()
                if not hero_alive:
                    print("玩家战败,战斗结束")
                    break

    def on_enter(self, *args):
        # 启动异步战斗逻辑
        ak.start(self.fight())

    def player_action(self, stat):
        self.player_action_pick = stat

kv代码无需做任何修改,原有逻辑可以直接复用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 20:15:00