こんにちは、Tech Samuraiです!
これまでの冒険で、私たちはオブジェクト指向プログラミング(OOP)の三大要素、クラス、継承、カプセル化という強力な武器を手に入れました。さあ、その全ての武器を手に、壮大なプロジェクトに挑戦する時が来ました!
今回から始まる新シリーズでは、Pythonを使って、シンプルなテキストベースのRPG(ロールプレイングゲーム)をゼロから開発していきます。
このプロジェクトは、これまでのOOPの知識を総動員する最高の舞台です。自分で設計したクラス(設計図)からキャラクター(オブジェクト)を生み出し、彼らが互いに影響を与え合い、一つの物語を紡いでいく… そんな創造の喜びを、ぜひ一緒に体験しましょう。
記念すべき第1回は、この世界の基礎となる**キャラクターの設計図(クラス)**を構築します。英雄もモンスターも、ここから生まれるのです!
1. ゲームの設計図:クラス階層を考える
いきなりコードを書き始める前に、どのようなクラスが必要で、それらがどのような関係にあるのか、設計図を描きましょう。今回は、**継承**の考え方を最大限に活かします。
クラス階層図:
Character(全てのキャラクターの親クラス)
├── Player(プレイヤーキャラクター)
│ └── Warrior(戦士などの専門職)
└── Enemy(敵キャラクター)
└── Slime(スライムなどの具体例)
- まず、プレイヤーにも敵にも共通する能力(名前、HP、攻撃力、攻撃する、ダメージを受けるなど)を持つ、大元となる**
Character
クラス**を親として定義します。 - 次に、
Character
クラスを継承して、プレイヤー専用の**Player
クラス**と、敵専用の**Enemy
クラス**を作ります。 - 将来的には、さらに
Player
を継承して専門職を作ったり、Enemy
を継承して様々なモンスターを作ったりと、世界を拡張していきます。
この階層構造が、私たちのRPGの骨格となります。
2. すべての基礎:「Character」親クラスの実装
まずは、全てのキャラクターの基礎となるCharacter
クラスを実装します。ここでは、HPがマイナスにならないように**カプセル化**の知識も活用します。
import random
class Character:
"""
全てのキャラクターの基礎となる親クラス
"""
def __init__(self, name, hp, attack_power):
self.name = name
self._hp = hp # HPは内部変数として扱う(カプセル化)
self.max_hp = hp # 最大HPを記憶しておく
self.attack_power = attack_power
# @property を使って、HPの読み取りを簡単にする(ゲッター)
@property
def hp(self):
return self._hp
# HPへの書き込みを制御する(セッター)
@hp.setter
def hp(self, new_hp):
# HPは0未満にも、最大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}")
ポイント:
HPを@property
と@hp.setter
を使って実装することで、player.hp = 100
のように自然に値を設定しつつも、裏側では「HPが0未満にならない」という重要なルールを自動で守らせることができます。これぞカプセル化の力です。
3. 継承で作る「Player」と「Enemy」クラス
基礎となるCharacter
クラスができたので、それを継承してPlayer
とEnemy
クラスを作るのは、驚くほど簡単です。
class Player(Character):
"""
プレイヤーキャラクターのクラス
"""
# 今は特別な機能はないので、passで中身は空にしておく
# しかし、Characterクラスの能力は全て引き継いでいる!
pass
class Enemy(Character):
"""
敵キャラクターのクラス
"""
# 同じく、今は特別な機能はない
pass
たったこれだけです! 中身は空っぽですが、この2つのクラスは、親であるCharacter
が持つ全ての属性とメソッドを、まるごと受け継いでいます。
4. 命を吹き込む:オブジェクトの生成とテスト
それでは、作成したクラス(設計図)から、キャラクター(オブジェクト)を生成して、簡単なやり取りをさせてみましょう。
# --- メインの処理 ---
# キャラクターを生成
hero = Player("Tech Samurai", 100, 15)
slime = Enemy("スライム", 30, 5)
print("冒険の始まりだ!")
hero.show_status()
slime.show_status()
print("\n--- BATTLE START ---")
# ヒーローがスライムを攻撃
hero.attack(slime)
print("-" * 20)
hero.show_status()
slime.show_status() # HPが減っているはず!
print("\n--- ENEMY'S TURN ---")
# スライムがヒーローを攻撃
slime.attack(hero)
print("-" * 20)
hero.show_status() # HPが減っているはず!
slime.show_status()
実行結果(例):
冒険の始まりだ!
[Tech Samurai] HP: 100/100
[スライム] HP: 30/30
--- BATTLE START ---
💥 Tech Samurai の攻撃!
スライム は 15 のダメージを受けた!
--------------------
[Tech Samurai] HP: 100/100
[スライム] HP: 15/30
--- ENEMY'S TURN ---
💥 スライム の攻撃!
Tech Samurai は 5 のダメージを受けた!
--------------------
[Tech Samurai] HP: 95/100
[スライム] HP: 15/30
完璧です! これで、私たちのRPGの世界の住人たちが生まれ、互いに影響を与え合う準備が整いました。
まとめと次回予告
今回は、実践OOPプロジェクトとしてテキストベースRPGの開発を開始し、その土台となるキャラクタークラスを設計・実装しました。
- RPGの世界観を、**クラスの階層構造**として設計する方法。
- 全てのキャラクターの共通機能を持つ、**親クラス `Character`** の実装。
- HP管理に**カプセル化(@property)**を使い、データの安全性を高める方法。
- **継承**を使い、
Player
とEnemy
クラスを効率的に作成する方法。
私たちの手で、RPGの登場人物たちが生まれました。しかし、彼らはまだ、私たちが手動で動かしているだけの人形にすぎません。
次回、第2回では、いよいよゲームの心臓部である**「ターン制の戦闘ループ」**を実装します! プレイヤーと敵が交互に自動で攻撃し合い、どちらかのHPが0になるまで戦いが続く… そんな、手に汗握るバトルシステムを構築していきましょう。お楽しみに!
コメント