見出し画像

6-2 保存するデータ1 ゲーム

同人誌について

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

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


説明と全体コード

 「src/mymod/data/game.py」の説明です。保存するデータのルートにあたります。

from dataclasses import dataclass, field
from . import growth, item, map, map_event

@dataclass
class 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, field
from . import growth, item, map, map_event

 1行目では、組み込みの`dataclasses`から、`dataclass`と`field`をインポートします。

 `dataclass`は、作成するクラスをデータ クラスにするためのものです。保存するオブジェクトのクラスは、全てデータ クラスとして作ります。

 `field`は、データ クラス内で、インスタンス変数の初期値のオブジェクトを作成するために利用します。

 2行目では、同じパッケージ内の`growth` `item` `map` `map_event`モジュールを読み込みます。

Gameクラス1

 `Game`クラスを分解して説明していきます。まずはクラスの作成部分と、2つのインスタンス変数です。

@dataclass
class Game:
    # 主人公
    x: int = 10     # X位置
    y: int = 10     # Y位置

 データ クラスとして`Game`クラスを作成します。属性を`x` `y`……のように設定して初期値を書いていきます。

 データ クラスなので、各属性に型ヒントを書きます。データ クラスのインスタンス変数は、型ヒントを書いておく必要があります。

Gameクラス2

 インスタンス変数の定義は続きます。

    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`になっていますが、これらの値は、他の場所で初期化します。

Gameクラス3 初期値がオブジェクトの属性

 インスタンス変数の定義は続いています。

    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`と書くだけでよいです。

Gameクラス4 空引数からインスタンスを生成

 次は、クラス メソッド`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`のように使います。

 この変数にゲームで保存するデータが全てぶら下がるようにします。そうすることで、手軽に保存や復帰ができるようになります。


 次の内容については省略します。こちらは同人誌をご覧ください。

  • 6-3 保存するデータ2 アイテム


同人誌について

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

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

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

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


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