見出し画像

5-1 プログラムの開始場所

同人誌について

 この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。

 同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで288ページの本になります。ぜひ、こちらもご購入ください(2024-03-10:ver1.0.3 に更新)。


 ここからは、レトロ風RPGのプログラムに入っていきます。同人誌の内容から、いくつかの場所を抜粋して掲載していきます。


説明

 プログラムの基本的な方針としては、辞書ではなくクラスをなるべく使います。辞書では静的解析ができず、『mypy』で効率的にバグを発見することができません。クラスならば、誤字脱字で属性名が違えばバグとして検出できます。辞書では、キー名に誤字脱字があってもバグとして検出できません。

 また、機能ごとになるべくファイルを分割してモジュール化します。これは、プログラムの見通しをよくするためです。また、本として説明する際に、あまり長いコードでは読者が読み取りにくいためです。

 コードの書き方については、横が80文字を越えないように書いています。現在のプログラムは横に長くなる傾向があります。しかし本として読む場合には、横に長すぎると読みにくいです。そのためプログラムの途中でも改行を入れるようにしています。

main.py

 まずは「src/main.py」を示します。

import pygame, asyncio
from mymod.image import screen
from mymod.game import event, scene
import init

# メイン
async def main():
    # 初期化
    init.init_cwd()     # CWDの初期化
    pygame.init()       # Pygameを初期化
    screen.init_win()   # ウィンドウの初期化
    init.init_game()    # ゲームの初期化

    # ゲームループ
    while True:
        screen.update_pre() # 更新の前処理
        screen.clear()      # 画面の消去

        e = event.exec()    # イベント実行
        if e.running == False: break    # ゲームの終了

        b = screen.get_buffer() # バッファ取得
        await scene.Manager.update(b, e)    # シーンの更新
        screen.update_post()    # 更新の後処理
    # 終了
    pygame.quit()

# 実行
if __name__ == "__main__":
    asyncio.run(main())

 『Pygame』を使った基本的な構造は同じです。そこから実際に使うプログラムとして、いくつか改良している点があります。

async/await

 まず、1行目で`asyncio`をインポートしています。6行目の`main()`には`async`を付けています。29行目の最初の実行は`asyncio.run(main())`にしています。

import pygame, asyncio
async def main():
    asyncio.run(main())

 これは、23行目の`await scene.Manager.update(b, e)`でシーンの更新を`await`付きでおこなっているためです。

        await scene.Manager.update(b, e)    # シーンの更新

 各シーンの`update()`では、`await`付きのプログラムを使います。具体的にはダイアログの表示で使います。ダイアログを表示しているあいだ、メイン ループの処理を待ちます。そのため、`async`で`main()`関数を実行しています。

 それでは、`main()`関数の処理を順番に見ていきましょう。

初期化

 まずは初期化の部分です。

    # 初期化
    init.init_cwd()     # CWDの初期化
    pygame.init()       # Pygameを初期化
    screen.init_win()   # ウィンドウの初期化
    init.init_game()    # ゲームの初期化

 次のような初期化をおこないます。

  • `init.init_cwd()` …… カレント ワーキング ディレクトリの調整をおこないます。

  • `screen.init_win()` …… ディスプレイのサイズに合わせて、ウィンドウの初期化をおこないます。

  • `init.init_game()` …… ゲーム自体の初期化をおこないます。

描画とイベント処理

 次は描画とイベント処理です。

    # ゲームループ
    while True:
        screen.update_pre() # 更新の前処理
        screen.clear()      # 画面の消去

        e = event.exec()    # イベント実行
        if e.running == False: break    # ゲームの終了

        b = screen.get_buffer() # バッファ取得
        await scene.Manager.update(b, e)    # シーンの更新
        screen.update_post()    # 更新の後処理

 ここでは隠蔽されていますが、描画処理は`screen`に直接おこなうのではなく、ドット絵用の小さな`Surface`(`b` バッファ)に描画したあと、画面に相当する`Surface`(`screen`)に描画しています。

 こうすることで、ドット絵風の画面を、ウィンドウのサイズに自動で拡大表示できるようにしています。

 イベントについては、`event.exec()`関数で、イベントの情報をまとめたオブジェクトを得ています。`e.running`が`False`ならゲームは終了します。それ以外の場合は、シーンの更新をおこないます。

 シーンの更新をおこなう`scene.Manager.update()`関数は、`screen.get_buffer()`関数で得た`b`と、イベントのオブジェクト`e`を引数にします。


同人誌について

 この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。

 同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで288ページの本になります。ぜひ、こちらもご購入ください(2024-03-10:ver1.0.3 に更新)。

 このnoteの記事と、Webページに一部抜粋版を掲載しています。

 技術系同人誌など まとめページ


この記事が気に入ったらサポートをしてみませんか?