CODE Python RPG

初心者がPythonでRPGを作成する(第14回)倒した対象を消す

更新日:

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

前回はどのモンスターを攻撃するか選択できるようにしました。
ただ、倒したモンスターの名前が消えず、倒したモンスターにも攻撃ができてしまうので、
今回は倒したモンスターを消します。
また、同じ種類のモンスターが出現した時は名前の最後に「A」「B」・・を
付けるようにします。

目次

  1. 倒したモンスターの名前を消す
  2. モンスタークラスに位置を追加
  3. 同じ種類のモンスターの名前
  4. 最後に

倒したモンスターの名前を消す

倒したモンスターの名前を消します。
以下のようになります。

変更前

変更後

 

それでは変えて行きます。
消し方としては、リストになっているmonsterから、
倒したモンスターオブジェクトを削除します。
リストから消す為にpopを使います。
詳しくはこちら

def main(): # メイン処理
(省略)

            if tmr == 11:
                monster[btl_enemy].hp = monster[btl_enemy].hp - dmg
                if monster[btl_enemy].hp <= 0:
                    monster[btl_enemy].hp = 0
                    set_message(player.name + " は " + monster[btl_enemy].name + " をやっつけた!")
                    monster.pop(btl_enemy) # 追加
                if monster == []:
                    idx = 16 # 勝利
                    tmr = 0
                # for i, mon in enumerate(monster): # 消す
                #     if mon.hp != 0:
                #         break
                #     if i+1 == len(monster):
                #         idx = 16 # 勝利
                #         tmr = 0

消す対象はインデックス「btl_enemy」なので、
monster.pop(btl_enemy)を追加すると、最初の画像のように
倒したモンスターの名前が消えます。

また、勝利の確認方法を変えました。
変更前:モンスター全員のHPが0
変更後:リスト(monster)が空

あと、リスト(dead_monster)を追加して、
これに倒したモンスターを入れておきます。
今は特に意味はないです。

monster = [] # モンスターのオブジェクト
dead_monster = [] # 倒したモンスターのオブジェクト(追加)
def main(): # メイン処理
(省略)
            if tmr == 11:
                monster[btl_enemy].hp = monster[btl_enemy].hp - dmg
                if monster[btl_enemy].hp <= 0:
                    monster[btl_enemy].hp = 0
                    set_message(player.name + " は " + monster[btl_enemy].name + " をやっつけた!")
                    dead_monster.append(monster[btl_enemy]) # 追加
                    monster.pop(btl_enemy)
(省略)
        elif idx == 22: # 戦闘終了
            idx = 1
            monster.clear() # モンスターオブジェクトを削除
            dead_monster.clear() # 倒したモンスターオブジェクトを削除

 

もう一つ、レベルアップの箇所を消しました。

def main(): # メイン処理
(省略)
            if tmr == 28:
                idx = 22 # 戦闘終了
                # 消す
                # if random.randint(0, monster[0].maxhp) > random.randint(0, player.maxhp):
                #     idx = 17
                #     tmr = 0

モンスターを複数出現できるようにした時に
この箇所はとりあえずmonster[0]にしておいたのですが、
戦闘終了したらリスト(monster)を空に変更する関係上、
ここでエラーになってしまう為、消しました。
レベルアップについては、別の方法でいつか追加しようと思います。
※「モンスターを倒したら経験値を獲得して、所定の値になったらレベルアップ」
 するようにしたいと思っています。

 

 

モンスタークラスに位置を追加

モンスターの名前を消しましたが、リストからモンスターオブジェクトを消したので
左にいるモンスターから倒すとモンスターの画像の位置が変わってしまいます。

 

Green slimeを倒した後

 

なので、モンスタークラスに座標の変数を追加して、
モンスターごとに位置を持たせます。

(chara.py)
class Monster():
    def __init__(self, num):
(省略)
        self.x = 0 # 画像の表示位置
        self.y = 0 # 画像の表示位置
    def set_x(self, x):
        self.x = x
    def set_y(self, y):
        self.y = y

今まで、位置情報を持っていた変数emy_x、emy_yは消します。
emy_xがmonster[i].x、emy_yがmonster[i].yに変わります。

(one_hour_dungeon.py)
# emy_x = [] # 敵の表示位置(x座標) # 消す
# emy_y = [] # 敵の表示位置(y座標) # 消す

(省略)
def main(): # メイン処理
(省略)
        elif idx == 22: # 戦闘終了
            idx = 1
            monster.clear() # モンスターオブジェクトを削除
            dead_monster.clear() # 倒したモンスターオブジェクトを削除
            # emy_x.clear() # 消す
            # emy_y.clear() # 消す

emy_x、emy_yに値を入れていた箇所をset_x、set_yに変更します。
emy_x.append → monster[index].set_x
emy_y.append → monster[index].set_y

(変更前)
def init_battle(bg): # 戦闘に入る準備をする
global monster, emy_x, emy_y
(省略)

    for i in range(num_enemy):
        sum_x += monster[i].img.get_width() + 35 # 35はモンスターの間隔
        emy_y.append(bg.get_height()*0.6 - monster[i].img.get_height()) # どのモンスターも画面の7割が一番下に揃えられる
    sum_x -= 35 # 最後のモンスターは間隔を開ける必要がない
    x_i_i = bg.get_width()/2 - sum_x/2 # 一番左のモンスターのx座標
    emy_x.append(x_i_i)
    for i in range(num_enemy-1):
        x_i_i += monster[i].img.get_width() + 35 # 2匹目以降のモンスターの横幅+間隔
        emy_x.append(x_i_i) # 各モンスターのx座標
(変更後)
def init_battle(bg): # 戦闘に入る準備をする
global monster # emy_x, emy_yは消す
(省略)

    for i in range(num_enemy):
        sum_x += monster[i].img.get_width() + 35 # 35はモンスターの間隔
        monster[i].set_y(bg.get_height()*0.6 - monster[i].img.get_height()) # どのモンスターも画面の7割が一番下に揃えられる
    sum_x -= 35 # 最後のモンスターは間隔を開ける必要がない
    x_i_i = bg.get_width()/2 - sum_x/2 # 一番左のモンスターのx座標
    monster[0].set_x(x_i_i) # 1匹目
    for i in range(num_enemy-1): # 2匹目以降
        x_i_i += monster[i].img.get_width() + 35 # 2匹目以降のモンスターの横幅+間隔
        monster[i+1].set_x(x_i_i) # 各モンスターのx座標

 

次に、emy_x、emy_yをmonster[index].x、monster[index].yに変更します。

(変更前)
def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)
        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座標
(変更後)
def draw_battle(bg, fnt): # 戦闘画面の描画
(省略)
        if display_flg:
            bg.blit(mon.img, [monster[i].x, monster[i].y+emy_step])

            # 敵の体力を表示するバー
            x_i = monster[i].x + mon.img.get_width()/2 - 100 # 体力バーのx座標

 

これで左からモンスターを倒しても位置が変わらなくなりました!

 

Green slimeを倒した後

 

 

同じ種類のモンスターの名前

他にもう少し変更します。

今は同じ種類のモンスターが出現した時も全て同じ名前になりますが
名前の最後に「A」「B」・・を付けて区別します。
また、同じ種類のモンスターは位置をまとめます。
以下のような感じです。

変更前

変更後

 

まず、モンスタークラスに「A」「B」・・を
付けるメソッドを追加します。

(chara.py)
class Monster():
    def __init__(self, num):
(省略)

    def set_name(self, num):
        if num == 0:
            self.name += " A"
        elif num == 1:
            self.name += " B"
        elif num == 2:
            self.name += " C"
        elif num == 3:
            self.name += " D"

出現するモンスターは最大4匹なので、Dまで用意します。
引数のnumで、同種のモンスターの何匹目かを指定します。

 

次に同種のモンスターを取得します。
その為には重複(同じ)モンスターの抽出が必要なので、
collectionsのCounterを使います。
詳しくはこちら

Counter:ハッシュ可能なオブジェクトを数え上げる辞書のサブクラス
とありますが、あまり理解できていません。。(ノ∀`#)
けど、とりあえず手探りで使って行きます。

Counterを使う為にcollectionsをimportします。

(one_hour_dungeon.py)
import collections

 

そして、出現モンスターの種類をリストに入れて、それにCounterを使います。

(変更前)
def init_battle(bg): # 戦闘に入る準備をする
(省略)

   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はモンスターの間隔
        monster[i].set_y(bg.get_height()*0.6 - monster[i].img.get_height()) # どのモンスターも画面の7割が一番下に揃えられる
(変更後)
def init_battle(bg): # 戦闘に入る準備をする
(省略)

    list_typ = []
    for _ in range(num_enemy):
        typ = random.randint(1, floor+1)
        list_typ.append(typ)
        # モンスターの位置を指定するのは後にする

    dic_typ = collections.Counter(list_typ) # 重複を抽出
    print(dic_typ)
    # Counter({1: 3, 2: 1})

Counterの結果をdic_typに入れましたが、この結果は
Counter({1: 3, 2: 1})
で、辞書型が出てきました。

これは、1(Green slime)が3つ、2(Red slime)が1つなので、
同種のモンスターとその数を取得できたようです。

辞書型の値を取得する為に、items()を使います。
詳しくはこちら

    for k, v in dic_typ.items():
        print(f"k:{k}, v:{v}")
        # k:1, v:3
        # k:2, v:1
        # k:typ、v:数(typがvの数だけ存在)

typ(同種のモンスター)がv匹いる。

というわけで以下のようにしました。

(変更後)
def init_battle(bg): # 戦闘に入る準備をする
(省略)

    list_typ = []
    for _ in range(num_enemy):
        typ = random.randint(1, floor+1)
        list_typ.append(typ)
    dic_typ = collections.Counter(list_typ) # 重複を抽出

    i = 0
    for k, v in dic_typ.items(): # k:typ、v:数(typの種類がvの数だけ存在)
        for j in range(v):
            monster.append(chara.Monster(k)) # モンスターオブジェクトを生成(モンスターの種類はk)
            if v != 1: # 同じ種類が複数いる時は名前に「A」「B」・・を付ける
                monster[i].set_name(j) # j匹目(0ならA、1ならBが名前に付く)
            sum_x += monster[i].img.get_width() + 35 # 35はモンスターの間隔
            monster[i].set_y(bg.get_height()*0.6 - monster[i].img.get_height()) # どのモンスターも画面の7割が一番下に揃えられる
            i += 1

 

これで名前に「A」「B」・・が付きました。
同じ種類のモンスターオブジェクトを順番に作ることになるので、
同じ種類のモンスターは位置がまとまって出現するようになります。

 

という感じで、今回は以上です!(`・ω・´)

 

 

最後に

今回は倒したモンスターの名前を消すようにしました。
また、同じ種類のモンスターの名前に「A」「B」・・を付けて
区別するようにしました。

次にモンスターの攻撃について、今はモンスターが何匹出現しても
攻撃するのは全体で1回だけなので、この辺りを次回から変えていこうと思います。

まとめサイトへ

 

 

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

 

 

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

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