どうもです、タドスケです。
Python で何か作りたいけど、大きなゲームをまるっと作れるほどの余力がない現状。
いろいろ考えてみたところ、
ゲームそのものじゃなくて、ゲームで使えそうな処理を作ったら、誰かのお役に立てるのでは?
と思い立ちました。
第一回目の今日は、ドラクエ風のターンバトルシステムを作ってみました。
コード
実行可能なコードは GitHub で公開しています。
■本体
https://github.com/tadosuke/gametips/blob/master/src/turnbattle/main.py
■テスト
https://github.com/tadosuke/gametips/blob/master/tests/turnbattle/test_main.py
実行例
テストコードを実行すると、以下のようなログが出ます。
Hoge があらわれた! Piyo があらわれた! Fuga があらわれた! ■ 1 ターン Hogeの攻撃! Piyo に 12 のダメージ!(残りHP: 18) Piyoの攻撃! Hoge に 6 のダメージ!(残りHP: 44) Fugaの攻撃! Hoge に 20 のダメージ!(残りHP: 24) ■ 2 ターン Hogeの攻撃! Piyo に 12 のダメージ!(残りHP: 6) Piyoの攻撃! Hoge に 6 のダメージ!(残りHP: 18) Fugaの攻撃! Hoge に 20 のダメージ!(残りHP: 0) Hoge は倒れた。 ■ 3 ターン Piyoの攻撃! Fuga に 1 のダメージ!(残りHP: 199) Fugaの攻撃! Piyo に 22 のダメージ!(残りHP: 0) Piyo は倒れた。 --Fuga の勝ち--
3人のキャラクターが順番に攻撃し、HP が0になったら死亡。
最後に生き残っていた一人が勝者となります。
今回はわかりやすさとテストのしやすさのため、ランダム要素は一切入れていません。
クラス構成
クラス構成は以下のようになっています。
- Character:キャラクタークラス
- Turn:ターンクラス
- Action:アクションクラス
- Battle:戦闘クラス
順番に説明します。
Character クラス
戦闘に参加するキャラクターです。
HP、攻撃力、防御力、名前を持っています。
Action クラス
キャラクターの1回分の行動(攻撃)を表現するクラスです。
2つの Character 情報(行動者・ターゲット)を持っています。
Turn クラス
ターンを表現するクラスです。
1ターンは複数のアクションからなり、全てのキャラクターのアクションを実行すると1ターンが終了します。
Battle クラス
戦闘の開始から終了までの一連の流れを表現するクラスです。
複数のターンからなり、キャラクターが最後の一人になるまでターンを繰り返します。
最後に生き残ったキャラクターを勝者として返します。
Tell, Don’t Ask(求めるな、命じよ)
今回の設計では、オブジェクト指向設計の原則でよく言われている「Tell, Don’t Ask(求めるな、命じよ)」を意識しました。
キャラクターの攻撃力などのパラメータは全て protected にして、クラス外から直接アクセスしないようにしています。
ダメージ計算については、キャラクターの攻撃力や防御力を取ってきて外部で計算するのではなく、damage 関数内で行わせています。
攻撃者は攻撃力20 を attack 関数でターゲットに送り、ターゲットは 20 の攻撃力に対してどれくらいのダメージを受けるのかを自身の damage 関数で決めます。
攻撃者は相手の防御力を知る必要はありませんし、どれくらいのダメージを受けたのかも知る必要はありません。ただ命じるだけでよいのです。
拡張のアイデア
このシステムを利用して実際にターンバトルシステムを作るなら、以下の拡張が必要になるでしょう。
ランダム要素
攻撃相手や与えるダメージ量などに乱数を利用して、バラつきが出るようにした方がよりゲームらしくなります。
行動順も現状は固定ですが、キャラクターに素早さパラメーターを追加して、「素早さが高いほど先に行動しやすい」という表現もできます。
チーム
今回の例ではバトルロイヤル形式ですが、キャラクターを敵チーム・味方チームに分けるようにすれば、実際のドラクエのようになります。
select_target 関数に敵チームのキャラクターリストだけを渡して、その中からターゲットを決めるようにすれば、味方を攻撃しなくなります。
魔法攻撃
キャラクターに魔法攻撃力/防御力を追加して、魔法攻撃時は相手の魔法防御力によってダメージ計算を行うようにします。
attack や damege 関数の引数に攻撃属性のようなパラメーター(Enum)を渡すのが簡単そうです。
ただし属性が増えると damage 関数の中が分岐だらけになるので、ダメージ計算処理自体をクラスにしてしまうのも手かもしれません。
状態異常
混乱中は味方チームも攻撃ターゲットに含めるようにすれば、敵味方区別なく攻撃するようになります。
行動者が眠っていたらアクションの生成を行わないようにすることで、ターン内に行動しなくなります。
damage 関数の中やターン終了時に眠りから回復する処理を入れるのも忘れずに。
ダメージ計算時に攻撃力・防御に倍率をかけることで、ドラクエでいうところの「バイキルト(攻撃力アップ)」「スカラ(防御力アップ)」「ルカニ(防御力ダウン)」のようなことができます。
以上、ターンバトルシステムの説明でした!
コメント
コメント一覧 (3件)
[…] 【GameTips】ドラクエ風ターンバトルシステムどうもです、タドスケです。Py… […]
[…] 【GameTips】ドラクエ風ターンバトルシステムどうもです、タドスケです。Py… […]
[…] さらにその新・ダメージ計算機能をターンバトルシステムと組み合わせれば、より本格的なバトルシステムが作れます。 […]