2025年12月11日木曜日

【Pythonゲーム開発 】#4.ゲームの心臓「メインループ」を作ろう(QTimer編)

 はじめに

 前回、画面に四角形を描くことができましたが、まだ動きません。 ゲームとは、パラパラ漫画のように「少しずつ動かした絵」を高速で切り替えることで成立しています。多くの初心者はここで「while Trueループで回せばいいんでしょ?」と考えますが、GUIアプリでそれをやると画面がフリーズして死にます。今回は、PySide6における正しいループの作り方、「QTimer」の使い方をマスターしましょう。


§1. なぜ「while True」はダメなのか?

 #2で解説した通り、GUIアプリは常に「イベントループ(待機状態)」の中にいます。もし自分で while True: を書いてしまうと、プログラムがそこで全力疾走を始めてしまい、ウィンドウの描画やクリックを受け付ける余裕がなくなります。結果、アプリは「応答なし」になります。


§2. 正解は「QTimer(キッチンタイマー)」

そこで使うのが QTimer です。 これは、「指定した時間ごとに、ベル(合図)を鳴らす」機能です。

設定: 「0.016秒(約16ミリ秒)ごとに合図して!」

動作:0.016秒経つ。

合図が鳴る → 「キャラの座標を+1する」

合図が鳴る → 「画面を書き直す(再描画)」

(待機)

また0.016秒経つ...

この隙間があるおかげで、アプリはフリーズせずに動き続けることができます。 ちなみに 1秒 ÷ 60回 ≒ 0.016秒 なので、これで滑らかな60FPSが実現できます。


§3. 実践コード:四角形を走らせろ!

四角形が左から右へ自動で動くコードです。 コピーして実行してみてください。

pythonコード

はじまり---------------------------------------------

import sys

from PySide6.QtWidgets import QApplication, QWidget

from PySide6.QtGui import QPainter, QBrush, QColor

from PySide6.QtCore import QTimer, Qt

class GameLoopWindow(QWidget):

    def __init__(self):

        super().__init__()

        self.setWindowTitle("動け!四角形")

        self.resize(500, 300)

        # ★ 変数の準備

        self.rect_x = 0  # 四角形のX座標(最初は0)

        # ★ 1. タイマーの準備

        self.timer = QTimer(self)

        self.timer.timeout.connect(self.update_game) # 時間が来たら呼ぶ関数を指定

        self.timer.start(16) # 16ミリ秒ごとにスタート!

    # ★ 2. 定期的に実行される「ゲームの更新処理」

    def update_game(self):

        # 座標を少し右にずらす

        self.rect_x += 2

        # 画面の端まで行ったら左に戻す(ループ)

        if self.rect_x > 500:

            self.rect_x = -50

        # 重要:「画面を書き直して!」とOSに依頼する

        self.update() 

    # ★ 3. 描画処理(update()されると呼ばれます)

    def paintEvent(self, event):

        painter = QPainter(self)

        # 背景を塗りつぶす(これがないと残像が残る!)

        painter.fillRect(self.rect(), Qt.white)

        # 変数(self.rect_x)の位置に描く

        painter.setBrush(QBrush(Qt.green))

        painter.drawRect(self.rect_x, 100, 50, 50)

if __name__ == "__main__":

    app = QApplication(sys.argv)

    window = GameLoopWindow()

    window.show()

    sys.exit(app.exec())

おわり---------------------------------------------


§4. コードの仕組み(リスト解説)

今回追加された「動き」の仕組みを表にまとめました。

ブロック役割コードの要点解説
準備タイマー設置

self.timer = QTimer()


self.timer.start(16)

「16ミリ秒ごとに update_game を実行せよ」とセットします。


これがゲームの心臓の鼓動になります。

計算座標の更新

def update_game(self):


self.rect_x += 2

変数の数字だけを変化させます。


※ここでは描画はしません。

通知再描画の依頼self.update()

「データが変わったから、画面を描き直して!」という命令です。


これを呼ぶと、自動的に paintEvent が実行されます。

描画表示

def paintEvent...


drawRect(self.rect_x...)

変化した新しい self.rect_x を使って、四角形を描きます。

今日のまとめ

  • 「変数」を変える。

  • 「QTimer」で定期的に変える。

  • 「update()」で画面に反映する。

この3ステップの繰り返しが、どんな複雑なゲームでも共通する「メインループ」の正体です。


次回予告

勝手に動く四角形は作れましたが、まだ操作できません。 次回は、あなたのキーボード操作でキャラを動かす「入力処理(Input)」を実装します。

Next Step: 【Vol.5】WASDで自由自在!キー入力でキャラを動かそう


0 件のコメント:

コメントを投稿

【Pythonゲーム開発 】#4.ゲームの心臓「メインループ」を作ろう(QTimer編)

 はじめに  前回、画面に四角形を描くことができましたが、まだ動きません。 ゲームとは、パラパラ漫画のように「少しずつ動かした絵」を高速で切り替えることで成立しています。多くの初心者はここで「while Trueループで回せばいいんでしょ?」と考えますが、GUIアプリでそれをやる...