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

Kivy游戏窗口无Python报错却未响应后崩溃问题求助

Kivy游戏初始化GameController时窗口崩溃问题解决

问题描述

使用Kivy开发游戏,三个基础菜单屏幕单独运行及屏幕间切换均正常,但点击“开始游戏”按钮、初始化GameController类并切换到GameScreen时窗口崩溃。尝试用time.sleep(3)延迟加载菜单无效,仅不初始化GameController时程序可正常运行。

原代码

Python脚本

#importing all of the libraries I will be using
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
from kivy.core.window import Window
from kivy.logger import Logger
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty, NumericProperty
from kivy.uix.widget import Widget
import random
import time

class GameController:
    def __init__(self, num_players):
        self.game_deck=Deck()
        self.players=[]
        self.num_players=num_players
        self.shuffled_deck=self.shuffle_deck(self.game_deck)

    def shuffle_deck(self,deck):
        shuffled_deck=[]
        while len(deck.cards)!=0:
            temp=0
            for i in range(len(deck.cards)-1):
                r=random.randint(0,len(deck.cards)-1)
                temp=deck.cards.pop(r)
                shuffled_deck.append(temp)
        return shuffled_deck
                
class Deck:
    def __init__(self):
        self.cards=[]
        for suit in ['hearts', 'diamonds', 'spades', 'clubs']:
            for face in range(1,14):
                image=str(str(suit)+str(face)+'.png')
                card=Card(suit, face, image)
                self.cards.append(card)
                
    def get_deck(self):
        return self.cards
        
class Card:
    def __init__(self,face,suit,image):
        self.face=face
        self.suit=suit
        self.image=image

class Players:
    def __init__(self,Username,number):
        self.deck=GameController.deal
        self.name=Username
        self.is_in=True
        self.number=number

##################################################################################

class MainMenu(Screen):
    def close_game(self):
        App.get_running_app().stop() #When this procedure is called, it closes the app
        Window.close()
    

class SingleMenu(Screen):
    def start_game(self):
        game_screen =GameScreen(name='game_screen') 
        self.manager.current ='game_screen'
        time.sleep(3)
        num_players =3
        game_controller =GameController(num_players)  

        

class GameScreen(Screen):
    player_cards=NumericProperty(None)
    current_player=StringProperty(None)

class IrishSnapsApp(App):
    def build(self): #This builds the actual application

        sm=ScreenManager()
        sm.add_widget(MainMenu(name='main_menu')) #adds the widget under the name main_Menu
        sm.add_widget(SingleMenu(name='single_menu'))#adds the widget under the name single_menu
        sm.add_widget(GameScreen(name='game_screen'))
        sm.current='main_menu' #starts with the application up with the 'main_menu'
        return sm




root=IrishSnapsApp()#creates the root widget for the app
root.run()#runs the app

Kv文件

<MainMenu>:
    BoxLayout:
        
        canvas.before:
            Color:
                rgba:0.098,0.301,0.2,1
            Rectangle:
                pos: self.pos
                size: self.size
    
        orientation:'vertical'
        padding: 50
    
        Label:
            text: 'Irish Snaps'
            size_hint: 1, 0.2
            font_size: 30
        Button:
            id: Singleplayer
            text: 'Singleplayer'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x":0.5}
            on_press: root.manager.current= 'single_menu'
        Button:
            size_hint: 0.5, 0.1
            font_size: 24
            background_color: (0.811,0.745,0.549,0)
        Button:
            id: Multiplayer
            text: 'Multiplayer'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x":0.5}
        Button:
            size_hint: 0.5, 0.1
            font_size: 24
            background_color: (0.811,0.745,0.549,0)
        Button:
            id: Statistics
            text: 'Statistics'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x": 0.5}
        Button:
            size_hint: 0.5, 0.1
            font_size: 24
            background_color: (0.811,0.745,0.549,0)
        Button:
            id: Closegame
            text: 'Close game'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x":0.5}
            on_press: root.close_game()

<SingleMenu>:
    BoxLayout:
        
        canvas.before:
            Color:
                rgba:0.098,0.301,0.2,1
            Rectangle:
                pos: self.pos
                size: self.size
    
        orientation:'vertical'
        padding: 50
    
        Label:
            text: 'SinglePlayer'
            size_hint: 1, 0.2
            font_size: 30
        Button:
            id: Start_game
            text: 'Start game'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x":0.5}
            on_press: root.start_game()
        Button:
            size_hint: 0.5, 0.1
            font_size: 24
            background_color: (0.811,0.745,0.549,0)
        Button:
            id: Number_Of_Bots
            text: 'Number Of Bots'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x":0.5}
        Button:
            size_hint: 0.5, 0.1
            font_size: 24
            background_color: (0.811,0.745,0.549,0)
        Button:
            id: Difficulty
            text: 'Difficulty'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x": 0.5}
        Button:
            size_hint: 0.5, 0.1
            font_size: 24
            background_color: (0.811,0.745,0.549,0)
        Button:
            id: Back
            text: 'Back'
            size_hint: 0.5, 0.2
            font_size: 24
            background_color: (0.811,0.745,0.549,1)
            pos_hint: {"center_x":0.5}
            on_press: root.manager.current= 'main_menu'

<GameScreen>:
    
    FloatLayout:
        canvas.before:
            Color:
                rgba:0.098,0.301,0.2,1
            Rectangle:
                pos: self.pos
                size: self.size
        Button:
            id: Slap
            text: 'SLAP!'
            size_hint: 0.3, 0.3
            pos_hint: {'x':0.7,'y':0.05}
            background_color: 1, 0, 0, 0
            canvas.before:
                Color:
                    rgba: 1, 0, 0, 1
                Ellipse:
                    pos: self.pos
                    size: self.size
        Image:
            id: Back_of_card
            source: 'Back_Of_Card.png'
            allow_stretch: True
            pos_hint: {'x':0.425,'y': 0.05}
            size_hint: 0.15, 0.325
        Label:
            text: 'number of cards: {}'.format(root.player_cards)
            font_size: 30
            size_hint: 0.2, 0.1
            pos_hint: {'x':0.1,'y':0.05}
            halign: 'left'
        Label:
            canvas.before:
                Color:
                    rgba:1,1,1,1
                Rectangle:
                    pos: self.pos
                    size: self.size
            text: "It is {}'s turn".format(root.current_player)
            font_size: 20
            size_hint: 0.3, 0.05
            pos_hint: {'x':0.35,'y':0.9}
            color: 0,0,0,1

问题分析及修复

1. Card类参数顺序错误

Deck类创建Card实例时传入的参数是Card(suit, face, image),但Card类的__init__方法定义为(face,suit,image),参数顺序不匹配,导致属性赋值混乱,初始化时触发错误。

修复:
调整Card类的__init__参数顺序,与调用处一致:

class Card:
    def __init__(self, suit, face, image):
        self.face = face
        self.suit = suit
        self.image = image

2. shuffle_deck方法逻辑错误

原方法中嵌套了for循环,会在每次while循环里重复执行多次pop操作,导致deck.cards被提前掏空引发索引错误。

修复:
移除多余的for循环,仅保留while循环内的随机pop:

def shuffle_deck(self, deck):
    shuffled_deck = []
    while len(deck.cards) != 0:
        r = random.randint(0, len(deck.cards)-1)
        temp = deck.cards.pop(r)
        shuffled_deck.append(temp)
    return shuffled_deck

3. Players类引用未定义的方法

Players类中self.deck=GameController.deal,但GameController根本没有deal方法,会触发AttributeError。

修复:
暂时注释或移除该错误代码,后续实现deal方法后再添加:

class Players:
    def __init__(self, Username, number):
        # self.deck=GameController.deal  # 先注释,待实现deal方法后修复
        self.name = Username
        self.is_in = True
        self.number = number

4. start_game方法阻塞主线程及重复创建Screen

  • time.sleep(3)会阻塞Kivy的主线程,导致UI无响应甚至崩溃,应使用Kivy的Clock.schedule_once替代。
  • ScreenManager中已经添加过GameScreen,无需重新创建,直接获取已有实例即可。

修复:

from kivy.clock import Clock  # 导入Clock

class SingleMenu(Screen):
    def start_game(self):
        # 直接切换到已有游戏屏幕
        self.manager.current = 'game_screen'
        # 用Clock延迟初始化GameController,避免阻塞主线程
        Clock.schedule_once(lambda dt: self.init_game_controller(), 0)

    def init_game_controller(self):
        num_players = 3
        game_controller = GameController(num_players)
        # 这里可以添加将game_controller关联到GameScreen的逻辑
        game_screen = self.manager.get_screen('game_screen')
        # 例如:game_screen.game_controller = game_controller

5. 可选优化:提前初始化GameController

如果初始化逻辑不复杂,也可以先完成GameController初始化再切换屏幕,避免延迟:

class SingleMenu(Screen):
    def start_game(self):
        num_players = 3
        game_controller = GameController(num_players)
        game_screen = self.manager.get_screen('game_screen')
        game_screen.game_controller = game_controller  # 关联到游戏屏幕
        self.manager.current = 'game_screen'

验证修复

完成以上修改后,重新运行程序,点击“开始游戏”按钮即可正常初始化GameController并切换到GameScreen,窗口不会崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:02:06