0

状況は次のとおりです。

WXWidgets を使用して簡単なゲームを作成しています。私が持っているロジックは、ゲームのメイン ルーチンが最初に GUI を起動し、次にゲームのロジックを実際に実行するために新しい別のスレッドを生成するというものです。ゲーム ロジックは順次実行され、ときどき (ただしそれほど頻繁ではありません)、GUI を介してユーザーからの入力を受け取り、ゲーム データで GUI を更新します。ゲームは多くのオーディオを使用するため、GUI 自体はあまり操作されていません。

ゲーム スレッドは、ブロックしなければならない処理を行うことがよくあります。これは、ゲームであることを考えると適切です。AI の計算、インターネットからのデータの読み込みなどはすべて、ゲーム スレッドのブロックを引き起こします。ゲーム スレッドが UI を管理して、ゲーム スレッドが応答できない可能性がある状況でユーザーが UI を操作できないようにするため、これは問題ありません。

ユーザーが Alt+F4 または Command-Q を押してアプリを完全に終了すると、問題が発生します。これにより、メインの GUI が閉じますが、明らかにゲーム ロジック スレッドは強制終了されません。ゲーム スレッドは引き続きバックグラウンドで実行され、UI から切断され、UI と対話しようとするとすぐにクラッシュします (その状況で予想されるように)。

私が探しているのは、ユーザーがアプリを終了したことをスレッドに通知する方法を用意することです-ただし、「ユーザーがGUIを閉じたかどうかを確認する」ルーチンでコードを散らかす必要はありません。まず第一に、そのメソッドは常に機能するとは限りません。なぜなら、私が言ったように、ゲーム スレッドが何かを実行している間にブロックされることが多く、そのような呼び出しがチェックされない場所で数秒が経過する可能性があるからです。

ゲーム スレッドは関数として開始されるため、スレッドでカスタム例外を発生させる方法があれば、これを解決する良い方法があると考えていました。次に、ゲームのメイン関数を try ブロック内にラップする単純なラッパー関数を作成し、具体的にはその例外を探します。その例外が発生した場合は、必要に応じてソケットを適切に閉じたり、AI プレーヤーをシャットダウンしたりしてから、スレッドを適切に終了できます。

このようなことが起こるようにする方法はありますか?

問題を説明するための非常に大まかな擬似コードを次に示します。

現在:

def PlayGame(self):
    # Get the game ready
    self.initGame()

    # Go into a loop to run the game
    while (True):
        # Get user's move
        move = self.GUI_GetMove()
        # Act based on the move
        gameOver = self.processMove(move)
        # If we got True, game is over.
        if (gameOver == True): return
        # Run the AI's logic - THIS MIGHT BLOCK AS THE AI PROCESSES AND/OR 
        # GRABS STUFF OFF THE INTERNET ETC.
        move = self.AI_GetMove()
        # Act based on the move
        gameOver = self.processMove(move)
        # (Let's pretend in this game the AI never ends the game)
        continue

非常に醜い方法:

def PlayGame(self):
    # Get the game ready
    self.initGame()

    # Go into a loop to run the game
    while (True):
        # Get user's move
        move = self.GUI_GetMove()
        if (move == "EXIT" or self.GUI_Exited == True):
            return
        # Act based on the move
        gameOver = self.processMove(move)
        # If we got True, game is over.
        if (gameOver == True): return
        if (self.GUI_Exited == True):
            return
        # Run the AI's logic - THIS MIGHT BLOCK AS THE AI PROCESSES AND/OR 
        # GRABS STUFF OFF THE INTERNET ETC.
        move = self.AI_GetMove()
        # self.AI_GetMove might take 10 or more seconds - game will appear to
        # be STUCK if user exits during an AI Process!
        if (self.GUI_Exited == True):
            return
        # Act based on the move
        gameOver = self.processMove(move)
        if (self.GUI_Exited == True):
            return
        # (Let's pretend in this game the AI never ends the game)
        continue

        # That self.GUI_Exited code is duplicated SO many times - making
        # this an awfully ugly and confusing block of code! In the real
        # app, the check might need to be duplicated 100+ times!!!

私ができるようにしたいこと:

def PlayGame(self):
    try:
        self._PlayGame()
    except UserExitedApplicationError:
        self.AI.Stop() 
        self.sockets.closeAll() 
        return # return gracefully so thread exits

(その多くは実際のコードや関数ではないことを覚えておいてください。これは、私が考えていたことが良い解決策になると考えているだけです)

4

1 に答える 1

0

threadingPython のライブラリの一部としてデーモン スレッドを調べてください。スレッドはデフォルトでは非デーモンであり、Python ではデーモン スレッドのみが実行されている場合に終了できます。バックグラウンド ゲーム ロジック スレッドを最初に作成するときにデーモン スレッドとして指定すると、メインの非デーモン スレッドが終了すると、スレッドは自動的に強制終了されます。

これは、これを行うための最も簡単で簡単な方法であり、欠点があることに注意してください。スレッドは、リソースを解放する前に強制終了されます。スレッド シグナルを使用して、そのスレッドが停止する前にそのリソースを最初に解放するようにすることもできます。スレッド シグナリングの最も単純な形式はイベントで、これもthreadingライブラリの一部です。

于 2013-09-01T07:53:38.323 に答える