こんにちは、Tech Samuraiです!
前回の記事「【実践OOPプロジェクト #1】PythonでテキストRPG開発!キャラクタークラスを作ろう」では、継承とカプセル化を駆使して、RPGの世界に生きるキャラクターたちの設計図を完成させましたね。
私たちの手で生み出された英雄「Tech Samurai」と敵「スライム」。しかし、彼らはまだ、私たちが一つずつ命令を与えなければ動けない、ただの人形です。今回の冒険の目的は、この人形たちに命を吹き込み、自律的に戦うための**「戦闘システム」**を構築することです。
その核心となるのが、多くのRPGで採用されている**「ターン制バトル」**の仕組みです。プレイヤーのターン、敵のターン、と交互に行動を繰り返す、あの馴染み深いシステムを、`while`ループを使って実装していきます。この記事を読み終える頃には、あなたのターミナルは、手に汗握る戦いの舞台へと変貌しているでしょう!
1. バトルの設計図:ターン制の流れを考える
コードを書き始める前に、戦闘がどのような流れで進むのか、そのルールを明確にしましょう。
- 戦闘開始!
- ループ開始: プレイヤーと敵の両方が生きている限り、戦闘を続ける。
- プレイヤーのターン:
- 現在のステータスを表示する。
- プレイヤーに「攻撃」や「逃げる」などの行動を選択させる。
- 選択に応じて、プレイヤーが行動を実行する。(例:
hero.attack(enemy)
)
- 行動後、敵がまだ生きているかチェック。もし倒れていれば、戦闘はプレイヤーの勝利で終了。
- 敵のターン:
- 敵が行動を実行する。(例:
enemy.attack(hero)
)
- 敵が行動を実行する。(例:
- 行動後、プレイヤーがまだ生きているかチェック。もし倒れていれば、戦闘はプレイヤーの敗北で終了。
- ループの先頭に戻る。
この一連の流れを、`while`ループを使ってプログラムに落とし込んでいきます。
2. 戦闘を司る監督役:「Battle」クラスの導入
戦闘のロジックを、前回のキャラクターコードとごちゃ混ぜに書くのはスマートではありません。OOPの考え方に従い、戦闘の進行を専門に管理する、新しいクラス**`Battle`**を導入しましょう。このクラスが、戦闘全体の監督役(ディレクター)を務めます。
# (前回のCharacter, Player, Enemyクラスの定義はここにあると仮定)
class Battle:
"""
戦闘の進行を管理するクラス
"""
def __init__(self, player, enemy):
self.player = player
self.enemy = enemy
def start(self):
"""戦闘ループを開始するメソッド"""
print("\n--- BATTLE START ---")
turn = 1
# プレイヤーと敵の両方が生きている間、ループを続ける
while self.player.is_alive() and self.enemy.is_alive():
print(f"\n--- ターン {turn} ---")
self.player.show_status()
self.enemy.show_status()
# --- プレイヤーのターン ---
action = input("どうする? (1: 攻撃, 2: 逃げる): ")
if action == '1':
self.player.attack(self.enemy)
elif action == '2':
print(f"{self.player.name}は逃げ出した!")
break # 戦闘ループを中断して終了
else:
print("コマンドが認識できませんでした。")
# 敵が倒れたら、敵のターンをスキップしてループを抜ける
if not self.enemy.is_alive():
break
# --- 敵のターン ---
print("\n敵のターン!")
self.enemy.attack(self.player)
turn += 1
# --- 戦闘終了後の結果表示 ---
print("\n--- BATTLE END ---")
if self.player.is_alive():
print(f"🎉 {self.player.name} は勝利した!")
else:
print(f"💀 {self.player.name} は敗北した...")
3. 全体コード:キャラクターと戦闘システムの統合
それでは、第1回で作成したキャラクタークラスと、今回作成した`Battle`クラスを統合し、実際にゲームを実行してみましょう。
import random
import time
# --- 第1回で作成したクラス群 ---
class Character:
# (ここに前回のCharacterクラスのコードを全て貼り付け)
def __init__(self, name, hp, attack_power):
self.name = name
self._hp = hp
self.max_hp = hp
self.attack_power = attack_power
@property
def hp(self): return self._hp
@hp.setter
def hp(self, new_hp): self._hp = max(0, min(new_hp, self.max_hp))
def is_alive(self): return self.hp > 0
def attack(self, target):
print(f"💥 {self.name} の攻撃!")
damage = self.attack_power
target.take_damage(damage)
def take_damage(self, damage):
print(f" {self.name} は {damage} のダメージを受けた!")
self.hp -= damage
if not self.is_alive(): print(f" {self.name} は倒れた...")
def show_status(self): print(f"[{self.name}] HP: {self.hp}/{self.max_hp}")
class Player(Character):
pass
class Enemy(Character):
pass
# --- 今回作成したBattleクラス ---
class Battle:
# (ここに今回のBattleクラスのコードを全て貼り付け)
def __init__(self, player, enemy):
self.player = player
self.enemy = enemy
def start(self):
print("\n--- BATTLE START ---")
turn = 1
while self.player.is_alive() and self.enemy.is_alive():
print(f"\n--- ターン {turn} ---")
self.player.show_status()
self.enemy.show_status()
action = input("どうする? (1: 攻撃, 2: 逃げる): ")
if action == '1': self.player.attack(self.enemy)
elif action == '2': print(f"{self.player.name}は逃げ出した!"); break
else: print("コマンドが認識できませんでした。")
if not self.enemy.is_alive(): break
print("\n敵のターン!")
time.sleep(1) # 敵の思考時間を表現
self.enemy.attack(self.player)
turn += 1
print("\n--- BATTLE END ---")
if self.player.is_alive() and not self.enemy.is_alive(): print(f"🎉 {self.player.name} は勝利した!")
elif not self.player.is_alive(): print(f"💀 {self.player.name} は敗北した...")
else: print("戦闘は引き分けに終わった。")
# --- ゲームの実行 ---
if __name__ == '__main__':
# 1. キャラクターを生成する
hero = Player("Tech Samurai", 100, 15)
monster = Enemy("ゴブリン", 50, 8)
# 2. 戦闘オブジェクトを生成し、戦闘を開始する
battle = Battle(hero, monster)
battle.start()
このスクリプトを実行すると、あなたのターミナル上で、ヒーローとゴブリンの壮絶な(?)戦いが繰り広げられます!
まとめと次回予告
今回は、テキストベースRPGの心臓部である、ターン制バトルシステムを構築しました。
- `while`ループを使い、ゲームのメインとなる戦闘ループを実装する方法。
- `input()`関数を使い、ループの中でプレイヤーの行動選択を受け付ける方法。
- 戦闘ロジックを独立した
Battle
クラスにまとめる、オブジェクト指向的な設計アプローチ。
あなたのプログラムは、もはや単なるコードの羅列ではありません。ルール(クラス)に従って相互作用し、一つの結果(勝敗)へと収束していく、小さな「世界」になったのです。
さて、基本的な戦闘はできるようになりましたが、キャラクターも敵もまだ個性がありません。次回、いよいよシリーズ完結編では、**継承**を本格的に活用して、
- 独自のスキルを持つ専門職「戦士」クラス
- 少し手強い中ボス「オーク」クラス
- 戦闘中に使える「回復薬」アイテム
などを追加し、このRPGの世界をより豊かで、より戦略的なものへと進化させていきます。お楽しみに!
コメント