こんにちは。
「Pythonでつくる ゲーム開発 入門講座」のChapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。
前回はコマンドを選択する時にモンスターの名前を表示するようにしました。
この表示させた名前を選択して、どのモンスターを攻撃するか
指定できるようにしたいと思っていますが、
出現するモンスターが今のように1匹だけですと、あまり意味がないので
今回はモンスターを1匹から複数出現するように変更します。
目次
モンスターを複数出現
モンスターを複数出現するように変更します。
具体的な数としては1〜4匹にします。
以下のような感じです。
変更後

変更後(4匹の場合)

それでは変更して行きます。
最初に変数です。
(変更前)
monster = ""
emy_x = 0 # モンスターの表示位置(x座標)
emy_y = 0 # モンスターの表示位置(y座標)
(変更後)
monster = [] # モンスターのオブジェクト
emy_x = [] # モンスターの表示位置(x座標)
emy_y = [] # モンスターの表示位置(y座標)
btl_enemy = 0 # モンスター選択の時の"▶︎"の位置(攻撃対象)
出現するモンスターを複数にする為、オブジェクトや表示位置をリスト型に変更します。
また、攻撃するモンスターを指定する為に「btl_enemy」を追加しました。
次にinit_battle関数です。
(変更前)
def init_battle(bg): # 戦闘に入る準備をする
global monster, emy_x, emy_y
typ = random.randint(1, floor+1)
if floor >= 10:
typ = random.randint(1, 10)
monster = chara.Monster(typ)
emy_x = bg.get_width()/2 - monster.img.get_width()/2
emy_y = bg.get_height()*0.6 - monster.img.get_height()
(変更後)
def init_battle(bg): # 戦闘に入る準備をする
global monster, emy_x, emy_y
# num_enemy = random.randint(1, 4) # 出現モンスターの数を1〜4のランダム
num_enemy = 4 # テスト用に4に固定
sum_x = 0 # 出現モンスター全部の横幅の合計
# if floor >= 10:
# typ = random.randint(1, 10)
for i in range(num_enemy): # モンスターの数にあわせて生成
typ = random.randint(1, floor+1)
monster.append(chara.Monster(typ)) # モンスター生成して、リストに追加
sum_x += monster[i].img.get_width() + 35 # 35はモンスターの間隔
emy_y.append(bg.get_height()*0.6 - monster[i].img.get_height())
sum_x -= 35 # 最後のモンスターは間隔を開ける必要がない
x_i_i = bg.get_width()/2 - sum_x/2 # 一番左のモンスターのx座標
emy_x.append(x_i_i) # emy_x[0]のx座標
for i in range(num_enemy-1): # (モンスターが2匹以上いる場合は)2匹目以降のx座標
x_i_i += monster[i].img.get_width() + 35 # 2匹目以降のモンスターの横幅+間隔
emy_x.append(x_i_i) # 各モンスターのx座標
変更点です。
num_enemy = random.randint(1, 4)
で、出現モンスターの数を1〜4のランダムにしています。
その後の
num_enemy = 4
で4に固定しているのはテスト用の為です。
余談ですが、テスト用に値を時々変えています。
今回ですと他にもモンスターがすぐに出てきて欲しいので
if r < 50: # モンスター出現(move_player関数)
のように、50%の確率でモンスターと遭遇するようにしたりしています。
次にfloorが10階以上の時は10にしている部分ですが面倒なので消しました。
# if floor >= 10:
# typ = random.randint(1, 10)
なので、この状態で10階以上に行くとエラーになってしまいます。
これは用意されているモンスターの種類が10の為です。
(そのうちfloorの概念は消そうとも思ってたりしています)
そして、次のfor文でmonsterリストに生成するモンスターをリストに入れて行っています。
monster.append(chara.Monster(typ)) # モンスター生成して、リストに追加
(リスト追加のappendについてはこちら)
あとは変数sum_xを追加したりして、モンスターの表示位置(x,y)を指定しています。
以下のような感じです。(便宜上、パラメータやコマンドなどを消しています)


これでモンスターを複数出現させることが出来ました!
(体力バーについては次項です)
各モンスターの表示
次に、出現モンスターを表示させるかどうかです。
攻撃でやっつけたかどうかを判定して、やっつけたモンスターは
表示しないようにします。
↓は2匹目をやっつけた図です。

これは、draw_battle関数を変えて行きます。
(変更前)
def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)
bg.blit(imgBtlBG, [bx, by])
if monster.hp > 0 and emy_blink%2 == 0:
bg.blit(monster.img, [emy_x, emy_y+emy_step])
(変更後)
def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)
bg.blit(imgBtlBG, [bx, by])
for i, mon in enumerate(monster): # 各モンスター
display_flg = False # 表示させるか(True:表示する、False:表示しない)
if mon.hp> 0 and btl_enemy != i: # 生存 かつ 攻撃対象ではない
display_flg = True # 表示
elif mon.hp> 0 and btl_enemy == i: # 生存 かつ 攻撃対象
if emy_blink%2 == 0: # 点滅
display_flg = True # emy_blinkが偶数の時だけ表示
if display_flg: # 表示
bg.blit(mon.img, [emy_x[i], emy_y[i]+emy_step])
変更前はモンスターが1匹だけでしたが、変更後は複数いる為、
for文で各モンスターに対して表示するか確認します。
enumerateはリストの要素と一緒にインデックス番号も取得できます。
(詳しくはこちら)
表示位置のemy_x,emy_y(リスト型)などにインデックス番号を利用します。
変数display_flgに対象のモンスターを表示するかどうかを入れます。
True:表示する、False:表示しない
デフォルトはFalseにして、表示すると判断したらTrueにしています。
Trueにならなかったモンスターは表示しない、ことになります。
変数btl_enemyは攻撃対象です。
値の指定は次回にします(∀`*ゞ)
hpが1以上なら表示(mon.hp>0)、
点滅用にemy_blinkを使う(emy_blink%2==0)ところは変更前と同じなので
for文になっただけで、やっていることはあまり変わっていません。
あと、前項で触れなかった体力バーです。
こちらも各モンスターに対して対処します。
(変更後)
def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)
for i, mon in enumerate(monster):
(省略)
if display_flg:
bg.blit(mon.img, [emy_x[i], emy_y[i]+emy_step])
# モンスターの体力を表示するバー
x_i = emy_x[i] + mon.img.get_width()/2 - 100 # 体力バーのx座標(インデックス番号を利用)
x_w = 200 # 体力バーの幅
y_i = bg.get_height()*0.6 + 10 # モンスターの下の位置 + 10
y_h = 10 # 体力バーの高さ
pygame.draw.rect(bg, WHITE, [x_i-2, y_i-2, x_w+4, y_h+4])
pygame.draw.rect(bg, BLACK, [x_i, y_i, x_w, y_h])
if mon.hp > 0: # 各モンスターのhp
pygame.draw.rect(bg, (0,128,255), [x_i, y_i, x_w*mon.hp/mon.maxhp, y_h]) # 残り体力
変更点はemy_xをリストにしています(emy_x[i])。
あと、オブジェクトをfor文のmonに変更ています。(monster → mon)
体力バーの[x_i, y_i, x_w, y_h](位置(x,y), 幅, 高さ)は以下のような感じです。

これでやっつけたモンスターは表示されなくなりました!
画像の大きさ
今回は画像の大きさは変えずに使っています。
この為、他のモンスターで画像が大きいと画面から出てしまいます。

画像の大きさはpygame.transform.scaleで変えられます。
(詳しくはこちら)
(chara.py)
class Monster():
def __init__(self, num):
self.img = pygame.image.load("image/enemy"+str(num)+".png")
if num == 5:
# enemy5.pngのデフォルトの大きさは(300,460)
self.img = pygame.transform.scale(self.img, (175, 240)) # 画像の大きさを(175, 240)にする
enemy5.pngの大きさを(300,460)から(175,240)に変えています。

また、出現するモンスターの数は最大で4にしましたが、
画像を小さくするとさらに増やせます。
num_enemy = 8の時

体力バーの調整が必要ですけどね・・・(ノ∀`*)
ひとまず最大数は4で作成していこうと思っています。
また、プログラムの中でモンスターごとに画像の大きさを変えるのは大変そうなので
画像ファイルの大きさを変えようと思っています。
(プログラムでは画像を読み込むだけ)
将来モンスター自体も変えようと思っているので、
作成段階では画像はデフォルトで読み込みます。
(↓は追加しません)
if num == 5:
self.img = pygame.transform.scale(self.img, (175, 240))
今回は以上です!(`・ω・´)
最後に
今回はモンスターを複数出現するようにしました。
次回は新しく追加した変数btl_enemyを使って、攻撃対象を指定します。
【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。