概要
演習Ⅱではオブジェクト指向のクラス・継承・コンポジションを使って簡単なCLIのコマンドバトルを作成します。
ソースコード
import random
class Charactor:
def __init__(self, name, hp, atk):
self.name = name
self.hp = hp
self.atk = atk
def act_attack(self):
print(f"{self.name}の攻撃")
damage = self.atk
return damage
def cal_damage(self, damage):
self.hp -= damage
if damage > 0:
print(f"{self.name}に{damage}のダメージ")
elif damage < 0:
print(f"{self.name}は{-1*damage}回復した")
elif damage == 0:
pass
if self.hp <= 0:
self.hp = 0
print(f"{self.name}はたおれた")
enemy =
player1 =
player2 =
party = [player1, player2]
# ▲ 演習ではここより上部にコードを記述していきます
# ----------------------------------------------------------------------------
enemy.start_serif()
Game = True
while Game:
print("------------------------------------------------")
print(enemy.name, " hp:", enemy.hp)
print("------------------------------------------------")
print("\n")
print("------------------------------------------------")
for n in range(len(party)):
print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
print("------------------------------------------------")
# プレイヤーの行動
for m in range(len(party)):
if party[m].hp > 0:
party[m].command()
print("------------------------------------------------")
input_command = input()
if input_command == '1':
target = enemy
target.cal_damage(party[m].act_attack())
elif input_command == '2':
target = party[m]
target.cal_damage(party[m].act_use_item())
elif input_command == '3':
target = enemy
target.cal_damage(party[m].act_special())
else:
print("無効なコマンドです")
print("\n")
# エネミーの行動
if enemy.hp <= 0:
print("たたかいにしょうりした")
Game = False
break
target = party[random.randint(0, len(party)-1)]
target.cal_damage(enemy.act_attack())
death_count = 0
for k in range(len(party)):
if party[k].hp == 0:
death_count += 1
if death_count == len(party):
print("たたかいにやぶれた")
Game = False
break
演習Ⅱ- 1
- コマンドバトルでは敵キャラクターと味方キャラクターの存在が必要不可欠です。
-
まずはこれらのキャラクターを実装します。
- 既にバトルに必要不可欠な、「キャラクターの属性 [名前(name), ヒットポイント(hp), こうげきりょく(atk)]」「攻撃の処理 [act_attack()]」や「ダメージの処理 [cal_damage()]」は用意しました。
- しかし、敵キャラクターと味方キャラクターではバトル中の行動が異なりますので、Charactorクラスをそのまま使うのは面倒になりそうな気がします。ということで、Charactorクラスを継承した新しいクラス「enemyクラス」と「playerクラス」を作成してみましょう。
- 各クラスに必要な属性とメソッドは以下の通りです。
【コマンドを表示する処理】の例
def command(self):
print(f"{self.name} 1: こうげき 2: どうぐ 3: ひっさつ")
EnemyクラスとPlayerクラスが実装出来たら enemyとplayer1とplayer2のインスタンスを作成し、実行してみてください。
解答例
import random
class Character:
def __init__(self, name, hp, atk):
self.name = name
self.hp = hp
self.atk = atk
def act_attack(self):
print(f"{self.name}の攻撃")
damage = self.atk
return damage
def cal_damage(self, damage):
self.hp -= damage
if damage > 0:
print(f"{self.name}に{damage}のダメージ")
elif damage < 0:
print(f"{self.name}は{-1*damage}回復した")
elif damage == 0:
pass
if self.hp <= 0:
self.hp = 0
print(f"{self.name}はたおれた")
class Enemy(Character):
def start_serif(self):
print(f"{self.name}「かってもまけてもせかいのぜんぶをくれてやろう」")
class Player(Character):
def command(self):
print(f"{self.name} 1: こうげき 2: どうぐ 3: ひっさつ")
def act_use_item(self):
return 0
def act_special(self):
return 0
enemy = Enemy(name="大魔王かとう", hp=225, atk=25)
player1 = Player(name="勇者", hp=130, atk=16)
player2 = Player(name="魔女", hp=100, atk=11)
party = [player1, player2]
# ▲ 演習ではここより上部にコードを記述していきます
# ----------------------------------------------------------------------------
Game = True
while Game:
print("------------------------------------------------")
print(enemy.name, " hp:", enemy.hp)
print("------------------------------------------------")
print("\n")
print("------------------------------------------------")
for n in range(len(party)):
print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
print("------------------------------------------------")
# プレイヤーの行動
for m in range(len(party)):
if party[m].hp > 0:
party[m].command()
print("------------------------------------------------")
input_command = input()
if input_command == "1":
target = enemy
target.cal_damage(party[m].act_attack())
elif input_command == "2":
target = party[m]
target.cal_damage(party[m].act_use_item())
elif input_command == "3":
target = enemy
target.cal_damage(party[m].act_special())
else:
print("無効なコマンドです")
print("\n")
# エネミーの行動
if enemy.hp <= 0:
print("たたかいにしょうりした")
Game = False
break
target = party[random.randint(0, len(party) - 1)]
target.cal_damage(enemy.act_attack())
death_count = 0
for k in range(len(party)):
if party[k].hp == 0:
death_count += 1
if death_count == len(party):
print("たたかいにやぶれた")
Game = False
break
演習Ⅱ-2
プレイヤーキャラクターにはコマンドで"2"を選択した時、道具「ポーション」を使えるようにしたいと思います。
「プレイヤーキャラクター」と「ポーション」の関係を考え、「ポーション」のクラスを作成してコマンドで"2"を選択した時にプレイヤーキャラクターが回復できるようにしてみましょう。
【Potionのuseメソッド】の例
def use(self):
if self.num > 0:
self.num -= 1
damage = -30
else:
print("道具をもう持っていない")
damage = 0
return damage
解答例
import random
class Character:
def __init__(self, name, hp, atk):
self.name = name
self.hp = hp
self.atk = atk
def act_attack(self):
print(f"{self.name}の攻撃")
damage = self.atk
return damage
def cal_damage(self, damage):
self.hp -= damage
if damage > 0:
print(f"{self.name}に{damage}のダメージ")
elif damage < 0:
print(f"{self.name}は{-1*damage}回復した")
elif damage == 0:
pass
if self.hp <= 0:
self.hp = 0
print(f"{self.name}はたおれた")
class Enemy(Character):
def start_serif(self):
print(f"{self.name}「かってもまけてもせかいのぜんぶをくれてやろう」")
class Player(Character):
def __init__(self, name, hp, atk):
super().__init__(name, hp, atk)
self.item = Potion(3)
def command(self):
print(f"{self.name} 1: こうげき 2: どうぐ 3: ひっさつ")
def act_use_item(self):
return self.item.use()
def act_special(self):
return 0
class Potion:
def __init__(self, num):
self.num = num
def use(self):
if self.num > 0:
self.num -= 1
damage = -30
else:
print("道具をもう持っていない")
damage = 0
return damage
enemy = Enemy(name="大魔王かとう", hp=225, atk=25)
player1 = Player(name="勇者", hp=130, atk=16)
player2 = Player(name="魔女", hp=100, atk=11)
party = [player1, player2]
# ▲ 演習ではここより上部にコードを記述していきます
# ----------------------------------------------------------------------------
Game = True
while Game:
print("------------------------------------------------")
print(enemy.name, " hp:", enemy.hp)
print("------------------------------------------------")
print("\n")
print("------------------------------------------------")
for n in range(len(party)):
print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
print("------------------------------------------------")
# プレイヤーの行動
for m in range(len(party)):
if party[m].hp > 0:
party[m].command()
print("------------------------------------------------")
input_command = input()
if input_command == '1':
target = enemy
target.cal_damage(party[m].act_attack())
elif input_command == '2':
target = party[m]
target.cal_damage(party[m].act_use_item())
elif input_command == '3':
target = enemy
target.cal_damage(party[m].act_special())
else:
print("無効なコマンドです")
print("\n")
# エネミーの行動
if enemy.hp <= 0:
print("たたかいにしょうりした")
Game = False
break
target = party[random.randint(0, len(party)-1)]
target.cal_damage(enemy.act_attack())
death_count = 0
for k in range(len(party)):
if party[k].hp == 0:
death_count += 1
if death_count == len(party):
print("たたかいにやぶれた")
Game = False
break
演習Ⅱ-3
コマンドで「3: ひっさつ」コマンドを選択した時に発動するの必殺技をつくります。実装方法はいろいろあると思いますが、今回は各キャラクターのクラスに発動する必殺技を設定しようと思います。
現在、Playerクラスからキャラクター2人のインスタンスを作成していると思いますが、これでは2人とも同じ必殺技になってしまいます。そこで、プレイヤークラスを継承して新たなクラスを作成し、プレイヤーキャラクターによって違う必殺技が発動するようにしましょう。
新しいクラスが作成出来たら、先ほど説明したポリモーフィズムを思い出して必殺技の処理を書いていきましょう。下図ではプログラムの例を出していますが、returnがダメージ量となっていれば中身は何でもいいです。
【act_special】の例
def act_special(self):
print(f"{self.name}のこんしんのいちげき")
damage = int(self.atk * 2)
return damage
def act_special(self):
print(f"{self.name}のまほうこうげき")
damage = int((self.hp / 10) + self.atk)
return damage
プログラムを実行してみて、「3:ひっさつ」のコマンドを選択した時にキャラクターによって違うものが発動すれば成功です。
解答例
import random
class Charactor:
def __init__(self, name, hp, atk):
self.name = name
self.hp = hp
self.atk = atk
def act_attack(self):
print(f"{self.name}の攻撃")
damage = self.atk
return damage
def cal_damage(self, damage):
self.hp -= damage
if damage > 0:
print(f"{self.name}に{damage}のダメージ")
elif damage < 0:
print(f"{self.name}は{-1*damage}回復した")
elif damage == 0:
pass
if self.hp <= 0:
self.hp = 0
print(f"{self.name}はたおれた")
class Enemy(Charactor):
def start_serif(self):
print(f"{self.name}「かってもまけてもせかいのぜんぶをくれてやろう」")
class Player(Charactor):
def __init__(self, name, hp, atk):
super().__init__(name, hp, atk)
self.item = Potion(3)
def command(self):
print(f"{self.name} 1: こうげき 2: どうぐ 3: ひっさつ")
def act_use_item(self):
return self.item.use()
def act_special(self):
return 0
class Brave(Player):
def act_special(self):
print(f"{self.name}のこんしんのいちげき")
damage = int(self.atk * 2)
return damage
class Witch(Player):
def act_special(self):
print(f"{self.name}のまほうこうげき")
damage = int((self.hp / 10) + self.atk)
return damage
class Potion:
def __init__(self, num):
self.num = num
def use(self):
if self.num > 0:
self.num -= 1
damage = -30
else:
print("道具をもう持っていない")
damage = 0
return damage
# ----------------------------------------------------------------------------
enemy = Enemy(name="大魔王かとう", hp=225, atk=25)
player1 = Brave(name="勇者", hp=130, atk=16)
player2 = Witch(name="魔女", hp=100, atk=11)
party = [player1, player2]
# ----------------------------------------------------------------------------
enemy.start_serif()
# ----------------------------------------------------------------------------
Game = True
while Game:
print("------------------------------------------------")
print(enemy.name, " hp:", enemy.hp)
print("------------------------------------------------")
print("\n")
print("------------------------------------------------")
for n in range(len(party)):
print("■", party[n].name, " HP:", party[n].hp, " ATK:", party[n].atk)
print("------------------------------------------------")
# プレイヤーの行動
for m in range(len(party)):
if party[m].hp > 0:
party[m].command()
print("------------------------------------------------")
input_command = input()
if input_command == '1':
target = enemy
target.cal_damage(party[m].act_attack())
elif input_command == '2':
target = party[m]
target.cal_damage(party[m].act_use_item())
elif input_command == '3':
target = enemy
target.cal_damage(party[m].act_special())
else:
print("無効なコマンドです")
print("\n")
# エネミーの行動
if enemy.hp <= 0:
print("たたかいにしょうりした")
Game = False
break
target = party[random.randint(0, len(party)-1)]
target.cal_damage(enemy.act_attack())
death_count = 0
for k in range(len(party)):
if party[k].hp == 0:
death_count += 1
if death_count == len(party):
print("たたかいにやぶれた")
Game = False
break