1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ren'Pyで2D RPGを作る(2)―パーティーとステータス

Last updated at Posted at 2020-07-26

概要

こんにちは、しがないエロゲーマー蟹丸です。Ren'Pyを使った2D RPG制作第二回です。
今回はパーティーとステータスを作っていきたいと思います。

前回:Ren'Pyで2D RPGを作る(1)

本記事の範囲
Ren'Pyでパーティーとステータスの管理ができるようにする、ステータス画面を作る

背景

RPGと言ったらまずバトルがしたい!と思うんですが、その前に必要なものがあります。ステータスです。体力も攻撃力もわからないままバトルはしたくないですからね。
またDQ1みたいなケースを除いてパーティーが必要になってくるでしょう。
ステータスは一人分作ったら同じようにほかの仲間の分も制作できると思うので、このあたりを一緒に進めていきます。

1. デフォルトでできることを確認する

システム実装

ビジュアルノベルであれば好感度を使う場合があるので、ステータス管理がデフォルトであるかも?と思ったのですが、見た感じRen'Pyコード中にaffectionという変数を定義してそこで操作しているようでした。
登場人物数人の好感度を管理するのであればそれで十分ですが、多くのキャラクターと敵に共通する要素であるステータスをこれで実装するのは大変です。わかりやすい実装をする必要がありそうです。

UI周り

ゲームプレイ中にメニューを開いて仲間の状態やステータスが見られると便利です。
デフォルトのゲームメニューを見てみると、ヘルプが「上部に表示されているキーボード/マウス(/ゲームパッド)をクリックするとそれぞれに対応するヘルプが表示される」というUIになっています。
SnapCrab_test_2020-7-26_9-33-10_No-00.png
SnapCrab_test_2020-7-26_9-33-20_No-00.png
これを利用したら「パーティーメンバーに対してそれぞれのステータスを表示する」ということができそうです。

2. 作る

システム実装

この部分はRen'PyじゃなくてただのPythonだろ!という実装になっているので、Pythonは使えるよ、という方は流し見してください。

Statsクラス

まずはステータス用にStatsクラスを作ります。
英語だとステータスのことstatsとかstatisticsとか呼ぶみたいですね。言われれば確かにです。

任意のrpyファイル
    class Stats():
        def __init__(self, name, default_value, max_value):
            if default_value > max_value:
                raise ValueError("default_value must be equal to or less than max_value")
            self.name = name
            self.current_value = default_value
            self.max_value = max_value
            self.max_flag = False

        def get_name(self):
            return self.name

        def get_current_value(self):
            return self.current_value

        def add_value(self, diff):
            if not self.max_flag:
                if self.current_value + diff >= self.max_value:
                    self.max_flag = True
                    self.current_value = self.max_value
                else:
                    self.current_value += diff

簡単に以下を実装しています。後で他の機能が欲しくなったら追加します。

  • 名前、デフォルト値(初期値)、最大値でインスタンス生成
    • キャラクターによってデフォルト値や最大値が違う場合に対応。
  • 名前と現在値を取得するメソッド
    • 基本。
    • デフォルト値、最大値、名前はインスタンス生成後変更不可。
  • 最大値を超えないように現在値を増やすメソッド
    • レベルアップやステータスアップのアイテムに対応。

味方キャラクターにも敵にも使えるようになっています。敵にはmax_valueはいらないかもしれませんが、味方が強くなると敵も強くなるタイプのゲームなら使えそうなので残しておきます。

PartyMemberクラス

次に味方キャラクター用にPartyMemberクラスを作ります。

任意のrpyファイル
    class PartyMember():
        def __init__(self, name, default_stats = {"体力": 100, "攻撃力": 30, "防御力": 15}, max_stats = {"体力": 1000, "攻撃力": 100, "防御力": 100}, skills = None):
            if default_stats.keys() != max_stats.keys():
                raise ValueError("stats keys not corresponding")
            self.name = name
            self.default_stats = default_stats
            self.max_stats = max_stats
            # self.skills = skills
            self.stats = []
            for stats_name in default_stats.keys():
                self.stats.append(Stats(stats_name, default_stats[stats_name], max_stats[stats_name]))

        def get_name(self):
            return self.name

        def get_all_stats(self):
            return self.stats

以下を実装しています。スキルについてはあとから必要になると思うので形だけ作り、メソッドは定義していません。

  • 名前、デフォルトステータス、最大ステータス、初期スキルを与えてインスタンス生成
    • ここはやや特殊で、自分の作ろうとしているゲームはキャラクターによって持っているステータスの種類が違う(壁は魔力ステータスがないみたいなイメージです)ため、ステータスをdictで渡します。ステータスの種類が共通であればdefault_hp = 100のような渡し方もできると思います。
    • 渡された値を元に、statsリストにStatsクラスのインスタンスを追加します。
  • 名前を取得するメソッド
    • 基本。
  • ステータスを取得するメソッド
    • statsリストを返します。要素はStatsクラスのインスタンスです。

パーティーメンバーの追加

クラスができたので、パーティーメンバーを追加してみます。

script.rpy
init:
    $party = []
label join_member:
    $party.append(PartyMember(name = "バランス型の人"))

これでjoin_memberラベルに飛んだとき、パーティーにデフォルトステータスを持った「バランス型の人」が追加されるようになりました。

UI実装

ここからはRen'Pyらしいことをやっていきます。
上述のとおり、ヘルプメニューのデフォルト実装を参考に作ってみます。

screens.rpy
screen stats():

    tag menu
    
    python:
        party_member_list = []
        stats_list = []
        for party_member in party:
            party_member_list.append(party_member.get_name())
            stats_dict = {}
            for stats in party_member.get_all_stats():
                stats_dict[stats.get_name()] = stats.get_current_value()
            stats_list.append(stats_dict)

    default member = party_member_list[0]
    default member_stats = stats_list[0] # dict型

    use game_menu(_("ステータス"), scroll="viewport"):

        style_prefix "stats"

        vbox:
            spacing 15

            hbox:

                for i, party_member in enumerate(party_member_list):
                    textbutton _(party_member) action [SetScreenVariable("member", party_member), SetScreenVariable("member_stats", stats_list[i])]
            
            use stats_screen(member, member_stats) 

screen stats_screen(member, member_stats):

    for k, v in member_stats.items():

        hbox:
            label _(k)
            text str(v)

以下のような流れになっています。

  1. まずPythonコードで各パーティーメンバーに対して名前とステータスのmapを取得する
  2. 押されたらmember変数とmember_stats変数をセットするテキストボタンを配置する
  3. membermember_statsを渡して画面にステータスを表示する

member_statsをRen'Pyコード内で扱えるdict型にしてから渡しているのは、screenに渡されるargsをPythonコード内で使う方法がわからなかったためです……。

ゲームメニューから上で作ったstatsスクリーンを表示できるようにします。メインメニューでは必要ないのでhistoryやsaveと同じところに追加します。

screens.rpy
# 文言をデフォルトからありがちなものに変えています。
# 直近でやっていたエロゲに寄せたなんてことはありません。
screen navigation():

    vbox:
        style_prefix "navigation"

        xpos gui.navigation_xpos
        yalign 0.5

        spacing gui.navigation_spacing

        if main_menu:

            textbutton _("はじめから") action Start()

            textbutton _("つづきから") action ShowMenu("load")

        else:

            textbutton _("ステータス") action ShowMenu("stats") # これを追加

            textbutton _("ログ") action ShowMenu("history")
            ### 後略 ###

メニューを開くとまずセーブが開いているのはあまりRPGライクではないので、ステータスを開くようにします。

screens.rpy
################################################################################
## 初期化
################################################################################

init offset = -1
default _game_menu_screen = "stats" # ここを追加

これでゲームメニューからパーティーメンバーのステータスを確認できるようになりました。
1人だけのとき:
SnapCrab_griseo_2020-7-25_23-35-42_No-00.png
2人に増えたとき:
SnapCrab_griseo_2020-7-25_23-36-4_No-00.png

結論と今後

今回はRen'Pyを使ってパーティーとステータスの管理・確認ができるようになりました。

まだまだバトルができるには程遠いので、道具やスキルなどをゆっくり実装していきたいと思います。

1
0
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?