今回は、Pythonを使った オブジェクト指向プログラミング の練習として、簡易RPGゲームのソースコードを解説します。このプログラムでは、キャラクター、プレイヤー、モンスター というクラス設計を通して、オブジェクト指向の基礎を学ぶことができます。
プログラム概要
このRPGゲームでは、プレイヤーがモンスターと戦います。以下の要素が含まれています。
- Character クラス:基底クラスとしてキャラクターの基本情報を管理
- Player クラス:プレイヤー専用の機能(回復や逃げる機能など)
- Monster クラス:モンスターの特殊攻撃を含む派生クラス(炎、氷、風)
- Game ロジック:攻撃、回復、逃げる、特殊攻撃などのアクション
プログラムの構成
1. クラスの構成図
Character (基底クラス)
├── Player (Character を継承)
└── Monster (Character を継承)
├── FireMonster (Monster を継承)
├── IceMonster (Monster を継承)
└── WindMonster (Monster を継承)
Character クラス:基底クラス
character.py
class Character:
def __init__(self, name: str, hp: int, attack_power: int) -> None:
self.__name = name
self.__hp = hp
self.__attack_power = attack_power
@property
def name(self) -> str:
return self.__name
@property
def attack_power(self) -> int:
return self.__attack_power
@property
def hp(self) -> int:
return self.__hp
@hp.setter
def hp(self, value: int) -> None:
self.__hp = max(0, value) # HPが負にならないようにする
@attack_power.setter
def attack_power(self, value: int) -> None:
self.__attack_power = value
"""攻撃"""
def attack(self, target: 'Character') -> None:
damage = self.__attack_power
target.hp -= damage
print(f"{self.name} は {target.name} に {damage} ダメージを与えた!")
"""生存確認"""
def is_alive(self) -> bool:
return self.__hp > 0
"""ステータス表示"""
def show_status(self) -> None:
print(f"{self.name}: HP {self.__hp}")
"""逃げる"""
def escape(self) -> bool:
return(1 if self.__hp > 30 else 0)
クラス概要
Character
クラスは、プレイヤーとモンスターの共通の属性とメソッドを持っています。名前、HP、攻撃力 を管理し、以下の機能を提供します。
- 攻撃 (attack)
- 生存確認 (is_alive)
- ステータス表示 (show_status)
- 逃げる (escape)
class Character:
def __init__(self, name: str, hp: int, attack_power: int) -> None:
self.__name = name
self.__hp = hp
self.__attack_power = attack_power
@property
def name(self) -> str:
return self.__name
@property
def attack_power(self) -> int:
return self.__attack_power
@property
def hp(self) -> int:
return self.__hp
@hp.setter
def hp(self, value: int) -> None:
self.__hp = max(0, value) # HPが負にならないようにする
ポイント解説
- カプセル化(プライベート変数)
self.__name
,self.__hp
,self.__attack_power
はプライベート変数として定義されています。- 外部から直接変更できないようにすることで、不正なデータ操作を防ぎます。
- プロパティ(@property)
@property
を使用して、ゲッターとセッターを定義。hp
のセッターでは、max(0, value)
でHPがマイナスにならないように制御しています。
- 攻撃メソッド (attack)
def attack(self, target: 'Character') -> None:
damage = self.__attack_power
target.hp -= damage
print(f"{self.name} は {target.name} に {damage} ダメージを与えた!")
- 他の
Character
クラスをターゲットにして攻撃します。 - ターゲットのHPが減少 する仕組みです。
- 逃げる (escape)
def escape(self) -> bool:
return(1 if self.__hp > 30 else 0)
- HPが30以上の場合に 逃げることが成功 します。
Monster クラス:モンスターの基底クラスと派生クラス
monster.py
from character import Character
# モンスタークラス(基底)
class Monster(Character):
def special_attack(self, target: Character) -> None:
pass # サブクラスで実装
# 派生モンスタークラス(特殊攻撃あり)
class FireMonster(Monster):
def special_attack(self, target: Character) -> None:
damage = self.attack_power + 10
target.hp -= damage
print(f"{self.name} の火炎攻撃! {target.name} に {damage} ダメージ!")
class IceMonster(Monster):
def special_attack(self, target: Character) -> None:
damage = self.attack_power + 5
target.hp -= damage
print(f"{self.name} の氷結攻撃! {target.name} に {damage} ダメージ!")
class WindMonster(Monster):
def special_attack(self, target: 'Character') -> None:
damage = self.attack_power + 40
target.hp -= damage
print(f"{self.name} の風の刃攻撃! {target.name} に {damage} ダメージ!")
クラス概要
Monster
クラスは Character
クラスを継承し、以下の 特殊攻撃 を持つ派生クラスを作成しています。
- FireMonster:火炎攻撃
- IceMonster:氷結攻撃
- WindMonster:風の刃攻撃
基底クラス: Monster
class Monster(Character):
def special_attack(self, target: Character) -> None:
pass # サブクラスで実装
special_attack()
はサブクラスでオーバーライドされます。
派生クラス: FireMonster, IceMonster, WindMonster
class FireMonster(Monster):
def special_attack(self, target: Character) -> None:
damage = self.attack_power + 10
target.hp -= damage
print(f"{self.name} の火炎攻撃! {target.name} に {damage} ダメージ!")
attack_power
に 10ポイント のボーナスを追加した火炎攻撃を行います。
Player クラス:プレイヤー専用の機能
player.py
クラス概要
Player
クラスは Character
を継承し、プレイヤー専用の以下の機能を追加しています。
- 回復 (heal)
- 逃げる (escape)
回復メソッド
def heal(self) -> None:
self.hp += self.heal_amount
print(f"{self.name} は {self.heal_amount} HPを回復した!")
heal_amount
分だけHPを回復します。
ゲームの流れ
game.py
import random
from player import Player
from monster import FireMonster, IceMonster, WindMonster
# ゲームロジック
def main():
print("=== 簡易RPGゲーム ===")
player = Player("プレイヤー", 100, 15)
monsters = [
FireMonster("炎の魔物", 50, 10),
IceMonster("氷の魔物", 60, 8),
WindMonster("風の魔物", 100, 10),
]
current_monster = random.choice(monsters)
print(f"{current_monster.name} が現れた!")
while player.is_alive() and current_monster.is_alive():
print("\nあなたのターン")
player.show_status()
current_monster.show_status() # 現在のモンスターを表示1
print("1: 攻撃する 2: 防御する 3: 回復する 4: 逃げる")
match choice := str(input("行動を選んでください: ")):
case "1":
player.attack(current_monster)
case "2":
print(f"{player.name} は防御した! ダメージを軽減!")
case "3":
player.heal()
case "4":
if player.escape():
print('逃げ切れた!')
break
else:
print('逃げられない...')
case _:
print("無効な選択です。")
# モンスターのターン
if current_monster.is_alive():
print("\nモンスターのターン")
if random.choice([True, False]):
current_monster.special_attack(player)
else:
current_monster.attack(player)
# 状態チェック
if not player.is_alive():
print("\nあなたは倒されました…ゲームオーバー。")
break
elif not current_monster.is_alive():
print(f"\n{current_monster.name} を倒した!勝利!")
if __name__ == "__main__":
main()
概要
- プレイヤーとモンスターの生成
- プレイヤーのターン:攻撃、防御、回復、逃げる
- モンスターのターン:通常攻撃または特殊攻撃
- 勝利・敗北の判定
ゲームループ
while player.is_alive() and current_monster.is_alive():
print("\nあなたのターン")
player.show_status()
current_monster.show_status() # 現在のモンスターを表示1
print("1: 攻撃する 2: 防御する 3: 回復する 4: 逃げる")
match choice := str(input("行動を選んでください: ")):
case "1":
player.attack(current_monster)
case "2":
print(f"{player.name} は防御した! ダメージを軽減!")
case "3":
player.heal()
case "4":
if player.escape():
print('逃げ切れた!')
break
else:
print('逃げられない...')
case _:
print("無効な選択です。")
- プレイヤーは、攻撃、防御、回復、逃げる の選択肢から行動を選択できます。
モンスターのターン
if current_monster.is_alive():
print("\nモンスターのターン")
if random.choice([True, False]):
current_monster.special_attack(player)
else:
current_monster.attack(player)
- 50% の確率 でモンスターは特殊攻撃を使用します。
ポリモーフィズムの動作例
以下のコードは、ポリモーフィズム を利用して、異なるモンスターオブジェクト を 共通のインターフェース で操作しています。
# モンスターのインスタンス生成
monsters = [
FireMonster("炎の魔物", 50, 10),
IceMonster("氷の魔物", 60, 8),
WindMonster("風の魔物", 100, 10),
]
# プレイヤーのインスタンス
player = Character("プレイヤー", 100, 15)
# ポリモーフィズムの実現:すべてのモンスターに対して special_attack を実行
for monster in monsters:
monster.special_attack(player)
monsters
リストには、FireMonster
、IceMonster
、WindMonster
の 異なるオブジェクト が含まれています。
すべてのオブジェクトは、Monster
クラスを 継承 しているため、共通のインターフェース (special_attack()
) を持っています。
special_attack()
メソッドは、各クラスでオーバーライド されているため、実行される動作が異なります。
オブジェクト指向のポイント
- 継承:
Character
→Player
、Monster
の継承関係 - カプセル化:プライベート変数によるデータ保護
- ポリモーフィズム:
special_attack()
のオーバーライド
まとめ
このプログラムは、オブジェクト指向プログラミングの基礎 を学ぶのに最適な構成です。
- クラス設計の考え方 を理解する
- 継承 や カプセル化、ポリモーフィズム を実践的に学ぶ
- ゲームロジックの設計 を通してプログラムの流れを理解する