この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。
同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで290ページの本になります。ぜひ、こちらもご購入ください。
(2024-03-28:ver1.0.4 に更新、2024-03-10:ver1.0.3 に更新)
ここからは、レトロ風RPGのプログラムに入っていきます。同人誌の内容から、いくつかの場所を抜粋して掲載していきます。
プログラムの基本的な方針としては、辞書ではなくクラスをなるべく使います。辞書では静的解析ができず、『mypy』で効率的にバグを発見することができません。クラスならば、誤字脱字で属性名が違えばバグとして検出できます。辞書では、キー名に誤字脱字があってもバグとして検出できません。
また、機能ごとになるべくファイルを分割してモジュール化します。これは、プログラムの見通しをよくするためです。また、本として説明する際に、あまり長いコードでは読者が読み取りにくいためです。
コードの書き方については、横が80文字を越えないように書いています。現在のプログラムは横に長くなる傾向があります。しかし本として読む場合には、横に長すぎると読みにくいです。そのためプログラムの途中でも改行を入れるようにしています。
まずは「src/main.py」を示します。
import pygame, asynciofrom mymod.image import screenfrom mymod.game import event, sceneimport 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』を使った基本的な構造は同じです。そこから実際に使うプログラムとして、いくつか改良している点があります。
まず、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で290ページの本になります。ぜひ、こちらもご購入ください。
(2024-03-28:ver1.0.4 に更新、2024-03-10:ver1.0.3 に更新)