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ページに一部抜粋版を掲載しています。
技術系同人誌など まとめページ
この記事が気に入ったらサポートをしてみませんか?