この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。
同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで290ページの本になります。ぜひ、こちらもご購入ください。
(2024-03-28:ver1.0.4 に更新、2024-03-10:ver1.0.3 に更新)
「src/mymod/data/game.py」の説明です。保存するデータのルートにあたります。
from dataclasses import dataclass, fieldfrom . import growth, item, map, map_event
@dataclassclass Game: # 主人公 x: int = 10 # X位置 y: int = 10 # Y位置 next_x: int = 10 # 次のX位置 next_y: int = 10 # 次のY位置 move_rate: float = 0.0 # 移動比率 exp: int = 0 # 経験値 level: int = 0 # レベル hp: int = 0 # HP mp: int = 0 # MP hp_max: int = 0 # 最大HP mp_max: int = 0 # 最大MP at: int = 0 # 攻撃力 df: int = 0 # 防御力 items: item.Items = field( default_factory = lambda: item.Items.from_blank()) # アイテム img_nums: list[int] = field(default_factory = lambda: [0, 1]) # 画像参照
# マップ map_w: int = 60 map_h: int = 40 data_map: map.Map = field(default_factory = lambda: map.Map.from_wh(0, 0)) map_events: list[map_event.Event] = field(default_factory = list)
# 空引数から生成 @classmethod def from_blank(cls) -> "Game": d = Game() growth.add_exp(d, 0) # 経験値追加(レベル1の値を計算) d.data_map = map.Map.from_wh(d.map_w, d.map_h) d.data_map.gen(d.x, d.y) # マップ生成 d.map_events = map_event.gen_event_from_map(d) # イベント return d
data: Game # インスタンス格納用
まずはインポート部分を示します。
from dataclasses import dataclass, fieldfrom . import growth, item, map, map_event
1行目では、組み込みのdataclasses
から、dataclass
とfield
をインポートします。
dataclass
は、作成するクラスをデータ クラスにするためのものです。保存するオブジェクトのクラスは、全てデータ クラスとして作ります。
field
は、データ クラス内で、インスタンス変数の初期値のオブジェクトを作成するために利用します。
2行目では、同じパッケージ内のgrowth
item
map
map_event
モジュールを読み込みます。
Game
クラスを分解して説明していきます。まずはクラスの作成部分と、2つのインスタンス変数です。
@dataclassclass Game: # 主人公 x: int = 10 # X位置 y: int = 10 # Y位置
データ クラスとしてGame
クラスを作成します。属性をx
y
……のように設定して初期値を書いていきます。
データ クラスなので、各属性に型ヒントを書きます。データ クラスのインスタンス変数は、型ヒントを書いておく必要があります。
インスタンス変数の定義は続きます。
next_x: int = 10 # 次のX位置 next_y: int = 10 # 次のY位置 move_rate: float = 0.0 # 移動比率 exp: int = 0 # 経験値 level: int = 0 # レベル hp: int = 0 # HP mp: int = 0 # MP hp_max: int = 0 # 最大HP mp_max: int = 0 # 最大MP at: int = 0 # 攻撃力 df: int = 0 # 防御力
HPなどが0
になっていますが、これらの値は、他の場所で初期化します。
インスタンス変数の定義は続いています。
items: item.Items = field( default_factory = lambda: item.Items.from_blank()) # アイテム img_nums: list[int] = field(default_factory = lambda: [0, 1]) # 画像参照
次は、初期値がオブジェクトのインスタンス変数を作ります。
値がオブジェクトのインスタンス変数は、field
のdefault_factory
を使って初期値を設定します。そうしなければ、全てのインスタンス オブジェクトで、同じオブジェクトを利用してしまいます。
default_factory
に登録した関数(ここではラムダ関数)は、オブジェクトが作成されるときに実行されます。この関数の戻り値が、インスタンス変数の値になります。
なぜこうしたことが必要なのか、より詳しく知りたい方は、「浅い複製」「深い複製」のキーワードで、ネットを調べてみてください(この本では割愛します)。
次は、マップについての変数を書きます。
# マップ map_w: int = 60 map_h: int = 40 data_map: map.Map = field(default_factory = lambda: map.Map.from_wh(0, 0)) map_events: list[map_event.Event] = field(default_factory = list)
マップdata_map
や、マップ イベントmap_events
についても、同じように値とオブジェクトの生成関数を登録します。
map_events
のようにリストを生成するときは、default_factory = list
と書くだけでよいです。
次は、クラス メソッドfrom_blank()
です。
# 空引数から生成 @classmethod def from_blank(cls) -> "Game": d = Game() growth.add_exp(d, 0) # 経験値追加(レベル1の値を計算) d.data_map = map.Map.from_wh(d.map_w, d.map_h) d.data_map.gen(d.x, d.y) # マップ生成 d.map_events = map_event.gen_event_from_map(d) # イベント return d
データ クラスでは、自動でコンストラクターが作られます。しかし、初期化段階で値を設定したり、計算をおこなったりしたい場合もあります。そうしたときは、コンストラクターとは別に、オブジェクトを作成する関数を用意しておくとよいです。
先ほどHPなどの値を他の場所で初期化しますと書きました。このfrom_blank()
関数で初期化をおこないます。
ここでは、レベルと能力値を計算するgrowth.add_exp()
関数や、マップを生成するd.data_map.gen()
関数、マップ イベントを生成するmap_event.gen_event_from_map()
関数を書いています。これらの関数で値を生成します。
最後は、Game
クラスのインスタンス オブジェクトを保持するdata
変数です。
data: Game # インスタンス格納用
モジュールの外から利用することを想定しています。data.game.data
のように使います。
この変数にゲームで保存するデータが全てぶら下がるようにします。そうすることで、手軽に保存や復帰ができるようになります。
次の内容については省略します。こちらは同人誌をご覧ください。
この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。
同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで290ページの本になります。ぜひ、こちらもご購入ください。
(2024-03-28:ver1.0.4 に更新、2024-03-10:ver1.0.3 に更新)