CODE Python RPG

初心者がPythonでRPGを作成する(第12回)モンスター複数出現

更新日:

こんにちは。
「Pythonでつくる ゲーム開発 入門講座」のChapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。

前回はコマンドを選択する時にモンスターの名前を表示するようにしました。

この表示させた名前を選択して、どのモンスターを攻撃するか
指定できるようにしたいと思っていますが、
出現するモンスターが今のように1匹だけですと、あまり意味がないので
今回はモンスターを1匹から複数出現するように変更します。

目次

  1. モンスターを複数出現
  2. 各モンスターの表示
  3. 画像の大きさ
  4. 最後に

モンスターを複数出現

モンスターを複数出現するように変更します。
具体的な数としては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を使って、攻撃対象を指定します。

まとめサイトへ

 

 

【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。

 

 

-CODE, Python, RPG
-, , , , ,

Copyright© kerublog , 2021 All Rights Reserved Powered by STINGER.