Kivy GUI中如何不阻塞主线程实现代码等待用户决策输入?
解决方法
实现思路
你已经通过player_action回调把玩家选择的操作写入了player_action_pick属性,只需要借助asynckivy的异步等待能力,监听这个属性的变化即可,无需额外绑定按钮事件:
- 将战斗逻辑改为异步函数,避免阻塞Kivy主线程导致UI无响应
- 等待玩家操作时,直接监听
player_action_pick属性的变更事件,只要用户按下任意按钮触发属性变化,就自动恢复执行 - 玩家选择完成后重置按钮状态和属性值,方便下一轮操作使用
具体修改步骤
- 先安装依赖库:
pip install asynckivy
- 在Python代码头部导入asynckivy:
import asynckivy as ak
- 改造
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
相关产品推荐
相关产品推荐

