Kivy点击Play跳转游戏后窗口静止但后台已运行如何解决?
错误根源
- 实例不匹配:调用
Builder.load_file("myMenu.kv")已经生成了一个包含MenuWindow、Game实例的WindowManager对象,存在代码中的kv变量中。但原build方法中要么返回了单独新建的Game实例,要么返回了新建的空WindowManager实例,和KV加载的已有实例完全独立,导致后台运行的游戏逻辑和前端显示的界面不匹配,画面静止。 - 初始化时机错误:原代码在build阶段就启动了Game的update调度和发球逻辑,此时Game实例还未被挂载到显示树,画面不会同步更新。
- 实例获取方式错误:
WindowManager()每次调用都会生成全新的空实例,因此查询current_screen永远返回None,实际运行的WindowManager实例可以通过App.get_running_app().root或者Screen子类的self.manager获取。
修正代码
Python代码
import kivy from kivy.app import App from kivy.uix.widget import Widget from kivy.lang.builder import Builder from kivy.uix.screenmanager import Screen, ScreenManager from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty from kivy.vector import Vector from kivy.clock import Clock class WindowManager(ScreenManager): pass class MenuWindow(Screen): pass class PongBall(Widget): velocity_y= NumericProperty(0) velocity_x= NumericProperty(0) velocity=ReferenceListProperty(velocity_x,velocity_y) def move(self): self.pos = Vector(self.velocity) + self.pos class PongPad(Widget): score=NumericProperty(0) def Check_bounce(self,ball): if self.collide_widget(ball): vx,vy= ball.velocity bounced= Vector(-1* vx, vy ) speedup= abs(((ball.velocity_x *0.1) -(ball.center_y - self.center_y)) *0.002) vel = bounced * (speedup +1.1) if (ball.center_y - self.center_y) > 0: ball.velocity=vel.x,vel.y ball.velocity_y= 2 else: ball.velocity= vel.x,vel.y ball.velocity_y= -2 class Game(Screen): ball = ObjectProperty(None) player_1 = ObjectProperty(None) player_2 = ObjectProperty(None) _update_event = None # 存储调度事件避免重复调度 def serve_ball(self,vel=(1,0.5)): print("234Served") self.ball.velocity= vel self.ball.center = self.center def Check_Top_Bottom(self): if self.ball.y <0: self.ball.velocity_y= abs(self.ball.velocity_y) if self.ball.y+50> self.height: self.ball.velocity_y = -abs(self.ball.velocity_y) def Check_if_score(self): if self.ball.x >self.width: self.player_1.score +=1 self.serve_ball() if self.ball.x+50 <0: self.player_2.score += 1 self.serve_ball() def update(self,dt): self.ball.move() self.Check_Top_Bottom() self.Check_if_score() self.player_1.Check_bounce(self.ball) self.player_2.Check_bounce(self.ball) print(self.manager.current_screen) # 正确获取当前屏幕 def on_enter(self, *args): # 进入游戏界面时才初始化游戏 self.serve_ball() if not self._update_event: self._update_event = Clock.schedule_interval(self.update, 1.0/60.0) def on_leave(self, *args): # 离开游戏界面时停止调度,不需要可删除 if self._update_event: Clock.unschedule(self._update_event) self._update_event = None def on_touch_move(self,touch): if touch.x > self.width/2: self.player_2.center_y = touch.y else: self.player_1.center_y= touch.y kv= Builder.load_file("myMenu.kv") class myMenuApp(App): def build(self): # 直接返回KV加载生成的WindowManager实例 return kv if __name__ == "__main__": myMenuApp().run()
KV代码无需修改,可保持原有内容。
修正后效果
- 应用启动后直接显示主菜单界面,查询当前屏幕可正常返回对应实例
- 点击Play按钮跳转至游戏界面后,球才开始运动,画面和逻辑完全同步
- 切回主菜单时可自动停止游戏更新(可根据需求删除on_leave逻辑保留后台运行)
内容的提问来源于stack exchange,提问作者Kol4o100
相关产品推荐
相关产品推荐

