pygameでRPG（パーティー）


[新RPGの目次](https://qiita.com/hijpa/items/31900e327315fa8e4eea)

# パーティー

<details><summary>ここにコードがあります</summary>

```python:

import pygame
from pygame import *
import sys
import time
import random

# 部分一致で値を取得する関数
def get_value_by_partial_key(dictionary, partial_key):
    for key in dictionary:
        if key in partial_key:
            return dictionary[key]
    return None

# 改行してテキストを描画する関数（バトルメッセージ）
def draw_text(surface, lines, pos, font, color=(255, 255, 255)):
    x, y = pos
    for i, line in enumerate(lines):
        if i <= 3:
            text_surface = font.render(line, True, color)
            surface.blit(text_surface, (x, y))
            y += int(text_surface.get_height() * 1.5)

# 2列×3行のテキストを描画する関数（ステータスウィンドウ・コマンドウィンドゥ）
def draw_text_grid(screen, text_list, start_x, start_y, spacing_x, spacing_y, font, white):
    for col_index, col in enumerate(text_list):  # 列ごとに処理
        for row_index, text in enumerate(col):  # 各行のテキストを描画
            text_surface = font.render(text, True, white)
            x = start_x + col_index * spacing_x  # 列ごとにX座標を調整
            y = start_y + row_index * spacing_y  # 行ごとにY座標を調整
            screen.blit(text_surface, (x, y))

# ここのpathはそのままにしておく(パスを貼り付けるところではない)
def bgm(path):
    pygame.mixer.music.load(path)
    pygame.mixer.music.play(-1)

def status_window(data):
    pygame.draw.line(screen, white, (data["x"], 58), (data["x"] + 98, 58))  # 横線
    pygame.draw.rect(screen, white, (data["x"], 20, 102, 134), 3, 5)  # 枠線
    
    text = font.render(data["name"], True, white)
    screen.blit(text, (data["x"] + 15, 35))  # 名前を表示
    
    # ステータスの表示
    text_list2 = [["H", "M", f"{data['first_letter']}"], [f"{data['HP']}", f"{data['MP']}", f"{data['level']}"]]
    draw_text_grid(screen, text_list2, start_x=data["x"] + 10, start_y=65, spacing_x=40, spacing_y=30, font=font, white = white)            

# セットアップ
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('パーティー')

# ここにフォントのパスを貼り付ける
font = pygame.font.Font(, 18)
# ここにカーソル画像のパスを貼り付ける
cursor = pygame.image.load()
# ここにモンスター画像のパスを貼り付ける
monsterA_image = pygame.image.load()
# ここにモンスター画像のパスを貼り付ける
monsterB_image = pygame.image.load()
# ここにモンスター画像のパスを貼り付ける
monsterC_image = pygame.image.load()

# SE
# ここにボタン音のパスを貼り付ける
sound = pygame.mixer.Sound()
# ここにダメージ音のパスを貼り付ける
sound2 = pygame.mixer.Sound()
# ここにレベルアップのパスを貼り付ける
sound3 = pygame.mixer.Sound()

# BGM
# ここに戦闘のBGMのパスを貼り付ける
battle_bgm = 
# ここに勝ったときのBGMのパスを貼り付ける
win_bgm = 
# ここに負けたときのBGMのパスを貼り付ける
lose_bgm = 

bgm(battle_bgm)    

# モンスター
nameA = ""
nameB = ""
nameC = ""
# モンスターのグループ
# 全角スペースで区切ります
# ex) "スライム　ウルフ"
# ひとグループ５体までです
groupA = ""
groupB = ""
groupC = ""
monster_list = [groupA,groupB,groupC]


# キャラの名前
player_nameA = "ゆうしゃ"
player_nameB = "せんし"
player_nameC = "まどうし"
player_nameD = "そうりょ"


# 色
white = (255, 255, 255)

# カーソル
alpha = 220
delta = 5

lines = ["モンスターが あらわれた！"]
text_up = False
text_up_num = 0


battle_message = True
command = False
mon_select = False
masic_select = False
defeat = False
item_select = False
# 戦闘準備の終了フラグ
all_select = False
# player_dataをstatus_dataに１回だけ追加するため(ターン数を数える)
turn_num = 1
# インデックス
actor_index = 0
mon_select_index = 0
masic_index = 0
chara_index = 0
item_index = 0
cmd_index = 0
cmd_num1 = 0
cmd_num2 = 0
# コマンド入力の順番
cmd_chara_index = 0

# フェーズ
phase = 0
masic_phase = 0
item_phase = 0

# 枠点滅
status_flash = 0
status_visible = 0
mon_flash = 0
mon_visible = 0
player_damage = 0
mon_damage = 0

# まほうエフェクト
masic_effect = 0
# まほうフレーム
masic_frame = 0
# まほうサーフェイス
damera_surface = pygame.Surface((width,height),SRCALPHA)
damera_surface.fill((255,201,14,128))
hoimun_surface = pygame.Surface((width,height),SRCALPHA)
hoimun_surface.fill((255,255,255,128))
# まほうリスト
damera = {"masic_name":"ダメラ","MP":2,"数値":10,"masic_effect":1,"masic_type":"攻撃まほう","surface":damera_surface}
hoimun = {"masic_name":"ホイムン","MP":3,"数値":30,"masic_effect":2,"masic_type":"補助まほう","surface":hoimun_surface}
masic_list = [damera,hoimun]
cmd_cursor = False
# キャラリスト
chara_group_list = [player_nameA,player_nameB,player_nameC,player_nameD]
# アイテムリスト
# _item = {"item_name":"","item_type":"アイテム","item_effect":,"数値":}
item_list = ["せいすい", "やくそう", "げんきのかけら", "まほうのしずく", "ひかりのたま"]
item_data = {"やくそう":{"item_effect":2,"item_parameter":30}}
item_effect = 0

# レクト
select_rect = pygame.Rect(width * 0.4,height * 0.67,220,140)
select_rectx,select_recty = select_rect.topleft
cmd_rect = pygame.Rect(20, height * 0.67, 220, 140)
cmd_rectx,cmd_recty = cmd_rect.topleft
message_rect = pygame.Rect(20, height * 0.67, 600, 140)
message_rectx,message_recty = message_rect.topleft

# 2列×3行のテキストデータ
text_list = [
    ["攻撃", "魔法", "ガード"],  # 1列目
    ["アイテム", "装備", "逃げる"]  # 2列目
]

status_data = []
player_data = []
# 勇者の初期ステータス
#player_name_dict = {chara_group_list[0]:,chara_group_list[1]:}
player_Max_HP_dict = {player_nameA:53, player_nameB:42,player_nameC:36,player_nameD:30}
player_HP_dict = {player_nameA:53, player_nameB:42,player_nameC:36,player_nameD:30}
player_Max_MP_dict = {player_nameA:5,player_nameB:0,player_nameC:10,player_nameD:9}
player_MP_dict = {player_nameA:5,player_nameB:0,player_nameC:10,player_nameD:9}
player_strength_dict = {player_nameA:33,player_nameB:3,player_nameC:2,player_nameD:1}
player_quick_dict = {player_nameA:6,player_nameB:3,player_nameC:5,player_nameD:4}
player_defence_dict = {player_nameA:2,player_nameB:6,player_nameC:3,player_nameD:2}
player_level_dict = {player_nameA:1,player_nameB:1,player_nameC:1,player_nameD:1}
player_first_letter_dict = {player_nameA:chara_group_list[0][0:1], player_nameB:chara_group_list[1][0:1],player_nameC:chara_group_list[2][0:1],player_nameD:chara_group_list[3][0:1]}
EXP_dict = {player_nameA:0, player_nameB:0,player_nameC:0,player_nameD:0}
status_x_dict = {player_nameA:20, player_nameB:140,player_nameC:260,player_nameD:380}
player_masic_dict = {player_nameA:[hoimun,damera],player_nameB:[],player_nameC:[damera],player_nameD:[hoimun]}
player_item_dict = {player_nameA:["やくそう","げんきのかけら", "まほうのしずく", "ひかりのたま"],
                    player_nameB:["やくそう"],
                    player_nameC:["やくそう","せいすい", "まほうのしずく"],
                    player_nameD:["やくそう","まほうのしずく"]}


for i in range(len(chara_group_list)):  
    player_data.append({
        "type": "player",
        "name": f"{chara_group_list[i]}",
        "Max_HP": player_Max_HP_dict[chara_group_list[i]],
        "HP": player_HP_dict[chara_group_list[i]],
        "Max_MP": player_Max_MP_dict[chara_group_list[i]],
        "MP":player_MP_dict[chara_group_list[i]],
        "strength": player_strength_dict[chara_group_list[i]],
        "defence": player_defence_dict[chara_group_list[i]],
        "quickness": player_quick_dict[chara_group_list[i]],
        "level": player_level_dict[chara_group_list[i]],
        "first_letter": player_first_letter_dict[chara_group_list[i]],
        "x":status_x_dict[chara_group_list[i]],
        "masic_list":player_masic_dict[chara_group_list[i]],
        "item_list":player_item_dict[chara_group_list[i]],
        "item_effect":0,
        "cmd_index":0,
        "masic_index":0,
        "mon_select_index":0,
        "item_index":0,
        "chara_index":0,
        "attack_on":0
    })

# レベルアップ
level_up_list = {player_nameA: [7, 23,47,110,220,50,800,1300,2000,2900,4000,5500],
                 player_nameB: [7,23,47,110,220,50,800,1300,2000,2900,4000,5500],
                 player_nameC: [7,23,47,110,220,50,800,1300,2000,2900,4000,5500],
                 player_nameD: [7,23,47,110,220,50,800,1300,2000,2900,4000,5500]}
level_up_index = {player_nameA: 0, player_nameB: 0,player_nameC:0,player_nameD:0}
# レベルアップに足りるEXPがあるか判定する順番
level_up_chara_num = 0
hit_and_miss = [0,1]
Gold = 0

# ステータスアップの種類
status_names = ["ちから", "すばやさ", "まもり", "最大HP", "最大MP"]
# ステータスの名称を辞書player_dataのキーに置き換えるための辞書
status_names_dict = {"ちから":"strength","すばやさ":"quickness","まもり":"defence","最大HP":"Max_HP","最大MP":"Max_MP"}
# ステータス上昇値のリスト
status_up_list = []


# モンスターの初期ステータス
mon_images_dict = {nameA: monsterA_image,
                   nameB: monsterB_image,
                   nameC: monsterC_image}
mon_HP_dict = {nameA: 4,nameB: 6,nameC: 8}
mon_strength_dict = {nameA: 34,nameB: 37,nameC: 6}
mon_defence_dict = {nameA: 4,nameB: 4,nameC: 8}
mon_quickness_dict = {nameA:8,nameB:2,nameC:8}
mon_EXP_dict = {nameA: 2,nameB: 5,nameC: 4}
mon_Gold_dict = {nameA: 4,nameB: 5,nameC: 10}
mon = random.choice(monster_list)
mon_group_list = mon.split()
mon_group_list2 = mon_group_list.copy()
mon_EXP = 0
mon_Gold = 0

for i in range(len(mon_group_list)):  
    status_data.append({
        "type": "monster",
        "name": f"{mon_group_list[i]}",
        "HP": get_value_by_partial_key(mon_HP_dict,mon_group_list[i]),
        "strength": get_value_by_partial_key(mon_strength_dict,mon_group_list[i]),
        "defence": get_value_by_partial_key(mon_defence_dict,mon_group_list[i]),
        "quickness": get_value_by_partial_key(mon_quickness_dict,mon_group_list[i]),
        "image": get_value_by_partial_key(mon_images_dict,mon_group_list[i]),
        "attack_on": 0
    })


# モンスターの位置を定義（奇数・偶数で異なる）
monster_positions = {
    1: [0.5],  # 1体
    2: [0.4, 0.6],  # 2体
    3: [0.3, 0.5, 0.7],  # 3体
    4: [0.2, 0.4, 0.6, 0.8],  # 4体
    5: [0.1, 0.3, 0.5, 0.7, 0.9]  # 5体
}

# モンスターの位置を設定
monster_rects = [
    get_value_by_partial_key(mon_images_dict,mon_group_list[i]).get_rect(center=(width * monster_positions[len(mon_group_list)][i], height * 0.5))
    for i in range(len(mon_group_list))
]

# 魔物がターゲットを決めるリスト
player_select_index_list = [0,1,2,3]
# 魔物がターゲットを決めたインデックス
player_select_index = 0

running = True
clock = pygame.time.Clock()

# メインループ
while running:
    clock.tick(60)
    # 画面を黒色に塗りつぶし
    screen.fill((0, 0, 0))
    for i, data in enumerate(player_data):
        if status_visible == 0 and player_select_index == i:
            status_window(data)
        if player_select_index != i:
            status_window(data)
        
    # モンスターの画像表示
    if mon_group_list:
        for i in range(len(mon_group_list)):
            if phase < 3: # current_indexがまだないからphaseを分ける
                screen.blit(get_value_by_partial_key(mon_images_dict,mon_group_list[i]), (monster_rects[i].topleft))
            elif phase >= 3: # モンスターに"mon_select_index"がないから"type"を分ける
                if current_actor["type"] == "monster" or mon_visible == 0 and current_actor["mon_select_index"] == i:
                    screen.blit(get_value_by_partial_key(mon_images_dict,mon_group_list[i]), (monster_rects[i].topleft))
                if current_actor["type"] == "player" and current_actor["mon_select_index"] != i:
                    screen.blit(get_value_by_partial_key(mon_images_dict,mon_group_list[i]), (monster_rects[i].topleft))
    # コマンドウィンドゥ
    if command:
        cursor.set_alpha(alpha)
        alpha += delta
        if alpha <= 120 or alpha >= 255:
            delta = -delta
        pygame.draw.line(screen, white, (20, 358),(236, 358))
        pygame.draw.rect(screen, white, cmd_rect, 3,5)
        text = font.render(chara_group_list[cmd_chara_index], True, white)
        screen.blit(text,((cmd_rectx + 14) + 60,(cmd_recty + 14)))
        draw_text_grid(screen, text_list, start_x=51, start_y=365, spacing_x=98, spacing_y=34, font=font, white = white)  # テキスト描画
        if cmd_cursor:
            screen.blit(cursor, ((cmd_rectx + 5) + 100 * cmd_num2, (cmd_recty + 40) + 34 * cmd_num1))  # カーソル描画
            cmd_index = cmd_num1 + (cmd_num2 * 3)
        # セレクトウィンドゥ
        if mon_select or masic_phase == 2 and player_data[cmd_chara_index]["masic_list"][player_data[cmd_chara_index]["masic_index"]]["masic_type"] == "攻撃まほう":
            pygame.draw.rect(screen,white,select_rect,3,5)
            # モンスター名の描画
            if mon_group_list:
                for i, mon in enumerate(mon_group_list):
                    text = font.render(mon, True, white)
                    screen.blit(text, ((select_rectx + 14) + 30, (select_recty + 14) + 24 * i))
                screen.blit(cursor, ((select_rectx + 14), (select_recty + 11) + 24 * mon_select_index))  # カーソル描画
        if masic_phase == 2 and player_data[cmd_chara_index]["masic_list"][player_data[cmd_chara_index]["masic_index"]]["masic_type"] == "補助まほう" or item_phase == 2:
            pygame.draw.rect(screen,white,select_rect,3,5)
            # キャラ選択
            # カーソル
            for i, chara in enumerate(chara_group_list):
                text = font.render(chara, True, white)
                screen.blit(text, ((select_rectx + 14) + 30, (select_recty + 14) + 24 * i))
            screen.blit(cursor, ((select_rectx + 14), (select_recty + 11) + 24 * chara_index))  # カーソル描画
        if masic_select and masic_phase <= 1:
            # まほうがある場合のみ描画
            pygame.draw.rect(screen,white,select_rect,3,5)
            if player_data[cmd_chara_index]["masic_list"]:
                for i, masic in enumerate([player_data[cmd_chara_index]["masic_list"][i]["masic_name"] for i in range(len(player_data[cmd_chara_index]["masic_list"]))]):
                    text = font.render(masic, True, white)
                    screen.blit(text, ((select_rectx + 14) + 30, (select_recty + 14) + 24 * i))
                screen.blit(cursor, ((select_rectx + 14), (select_recty + 11) + 24 * masic_index))  # カーソル描画
        if item_select and item_phase <= 1:
            # アイテムがある場合のみ描画
            pygame.draw.rect(screen,white,select_rect,3,5)
            if player_data[cmd_chara_index]["item_list"]:
                player_data[cmd_chara_index]["item_index"] = item_index
                player_data[cmd_chara_index]["item_effect"] = item_effect
                none_key = item_data.get(player_data[cmd_chara_index]["item_list"][player_data[cmd_chara_index]["item_index"]])  # 存在しない場合は None
                if none_key is not None:
                    item_effect = item_data[player_data[cmd_chara_index]["item_list"][player_data[cmd_chara_index]["item_index"]]]["item_effect"]
                elif none_key == None:
                    item_effect = 1
                for i, item in enumerate(player_data[cmd_chara_index]["item_list"]):
                    text = font.render(item, True, (255, 255, 255))
                    screen.blit(text, ((select_rectx + 14) + 30, (select_recty + 14) + 24 * i))
                screen.blit(cursor, ((select_rectx + 14), (select_recty + 11) + 24 * item_index))  # カーソル描画
    # メッセージウィンドゥ
    if battle_message:
        pygame.draw.rect(screen, white, message_rect, 3,5)
        # バトルメッセージ
        draw_text(screen,lines,((message_rectx + 24),(message_recty + 24) - text_up_num),font)
        if text_up and text_up_num < 27:
            text_up_num += 1
            if text_up_num == 27:
                text_up = not text_up
                text_up_num = 0
                del lines[0]
        

    # プレイヤーのダメージエフェクト
    if status_flash > 0:
        status_visible = pygame.time.get_ticks() // 90 % 2
        status_flash -= 1
        if status_flash == 19:
            sound2.play()
    if status_flash == 1:
        status_flash = 0
        status_visible = 0
        # キャラの死亡
        if player_data[player_select_index]["HP"] <= 0:
            if player_data[player_select_index]["attack_on"] == 1:
                actor_index -= 1
            del status_data[player_select_index_list.index(player_select_index) + len(mon_group_list)]
            del player_select_index_list[player_select_index_list.index(player_select_index)]
        if len(player_select_index_list) == 0:        
            bgm(lose_bgm)
            message = "そのあと\nゆうしゃのすがたをみたものはいない"
            phase = 4
        else:
            phase = 2
    # モンスターのダメージエフェクト
    if mon_flash > 0:
        mon_visible = pygame.time.get_ticks() // 90 % 2
        mon_flash -= 1
        if mon_flash == 19:
            sound2.play()
    if mon_flash == 1:
        mon_flash = 0
        mon_visible = 0
        if status_data[current_actor["mon_select_index"]]["HP"] <= 0: 
            defeat = True
        else:
            phase = 2
                
    # まほう（半透明レクト）
    if masic_frame > 0:
        if current_actor["type"] == "player":
            if current_actor["MP"] >= current_actor["masic_list"][current_actor["masic_index"]]["MP"]:
                screen.blit(current_actor["masic_list"][current_actor["masic_index"]]["surface"],(0,0))
                masic_frame -= 1

    pygame.display.update()
    
    # キーハンドラー
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_z and mon_flash == 0 and status_flash == 0:
                # あらわれた！を消してコマンドウィンドゥをひらく
                if phase == 0:
                    sound.play()                        
                    battle_message = False # あらわれた！を消す
                    command = True
                    cmd_cursor = True
                    phase = 1
                # コマンドウィンドゥを開いたまま、魔物選択ウィンドゥをひらく
                # 「たたかう」
                elif phase == 1 and cmd_index == 0:
                    sound.play()                        
                    mon_select = True
                    cmd_cursor = False
                    phase = 2
                # コマンドウィンドゥを開いたまま、まほう選択ウィンドゥをひらく
                # 「まほう」
                elif phase == 1 and cmd_index == 1 and chara_group_list[cmd_chara_index] != "せんし":
                    player_data[cmd_chara_index]["masic_index"] = masic_index
                    sound.play()                        
                    masic_select = True
                    cmd_cursor = False
                    masic_phase = min(2,masic_phase + 1)
                    if masic_phase == 2:
                        phase = 2
                # コマンドウィンドゥを開いたまま、アイテム選択ウィンドゥをひらく
                # 「アイテム」
                elif phase == 1 and cmd_index == 3 and item_effect != 1 and player_data[cmd_chara_index]["item_list"]:
                    sound.play()                        
                    item_select = True
                    cmd_cursor = False
                    item_phase = min(2,item_phase + 1)
                    if item_phase == 2:
                        phase = 2
                elif phase == 2 or phase == 1 and cmd_index == 2 or phase == 1 and cmd_index == 5 or phase == 1 and item_effect == 1:
                    # 死亡キャラのスキップ
                    if command:
                        for i, item in enumerate(player_data):
                            if i <= cmd_chara_index:
                                continue
                            if item["HP"] == 0:
                                cmd_chara_index += 1
                            else:
                                break
                    # コマンド入力のループ
                    if cmd_chara_index < len(chara_group_list) - 1:
                        player_data[cmd_chara_index]["cmd_index"] = cmd_index
                        player_data[cmd_chara_index]["mon_select_index"] = mon_select_index
                        player_data[cmd_chara_index]["chara_index"] = chara_index
                        cmd_chara_index += 1
                        mon_select_index = 0
                        masic_index = 0
                        item_index = 0
                        masic_phase = 0                        
                        item_phase = 0
                        masic_effect = 0
                        item_effect = 0
                        chara_index = 0
                        cmd_index, cmd_num1,cmd_num2 = 0, 0, 0
                        sound.play()
                        battle_message, command, masic_select, item_select, cmd_cursor, mon_select = False, True, False, False, True, False
                        phase = 1
                    # 魔物選択ウィンドゥを消して、メッセージの表示
                    elif cmd_chara_index == len(chara_group_list) - 1:
                        if not all_select:
                            player_data[cmd_chara_index]["cmd_index"] = cmd_index
                            player_data[cmd_chara_index]["masic_index"] = masic_index
                            player_data[cmd_chara_index]["mon_select_index"] = mon_select_index
                            player_data[cmd_chara_index]["chara_index"] = chara_index
                            if turn_num <= 1:
                                status_data += player_data
                            command = False
                            mon_select = False
                            masic_phase = 3
                            battle_message = True
                            all_select = True
                        status_data2 = sorted(status_data, key=lambda dictionary: dictionary["quickness"], reverse=True)
                        if actor_index < len(status_data2):
                            current_actor = status_data2[actor_index]
                            sound.play()
                            if current_actor["type"] == "player":
                                if current_actor["cmd_index"] == 0:
                                    lines = [f'{current_actor["name"]}の　こうげき！']
                                elif current_actor["cmd_index"] == 1:
                                    lines = [f'{current_actor["name"]}は　{current_actor["masic_list"][current_actor["masic_index"]]["masic_name"]}を　となえた！']
                                    masic_effect = current_actor["masic_list"][current_actor["masic_index"]]["masic_effect"]
                                    masic_frame = 10
                                elif current_actor["cmd_index"] == 2:
                                    lines = [f'{current_actor["name"]}は　ガードした']
                                    actor_index += 1
                                    current_actor["attack_on"] = 1
                                elif current_actor["cmd_index"] == 3:
                                    lines = [f'{current_actor["name"]}は　{current_actor["item_list"][current_actor["item_index"]]}を　つかった！']
                                elif current_actor["cmd_index"] == 5:
                                    lines = [f'{current_actor["name"]}は　にげだした']
                            else:
                                lines = [f'{current_actor["name"]}の　こうげき！']
                                
                            if current_actor["type"] == "player":
                                if current_actor["cmd_index"] == 2:
                                    pass
                                elif current_actor["cmd_index"] == 5:                                    
                                    phase = 4
                                else:
                                    phase= 3
                            else:
                                phase = 3
                        # ターン終了したら、コマンドウィンドゥをひらく
                        elif actor_index == len(status_data):
                            player_select_list = []
                            turn_num += 1
                            cmd_chara_index = 0
                            actor_index = 0
                            mon_select_index = 0
                            masic_index = 0
                            item_index = 0
                            masic_phase = 0                        
                            item_phase = 0
                            masic_effect = 0
                            item_effect = 0
                            cmd_index, cmd_num1,cmd_num2 = 0, 0, 0
                            sound.play()
                            battle_message, command, masic_select, item_select, cmd_cursor, all_select = False, True, False, False, True, False
                            phase = 1
                            for i in range(len(status_data)):
                                status_data[i]["attack_on"] = 0
                            for item in player_data:
                                if item["HP"] == 0:
                                    cmd_chara_index += 1
                                else:
                                    break
                # プレイヤーの攻撃(モンスターに与えるダメージ)
                elif phase == 3 and current_actor["type"] == "player" and not defeat:
                    if current_actor["cmd_index"] == 1 and current_actor["MP"] < current_actor["masic_list"][current_actor["masic_index"]]["MP"]:
                        message = "ＭＰが足りない…"
                        phase = 2
                    elif current_actor["cmd_index"] == 0 or current_actor["cmd_index"] == 1 and current_actor["masic_list"][current_actor["masic_index"]]["masic_type"] == "攻撃まほう":
                        if current_actor["cmd_index"] == 0:
                            mon_damage = current_actor["strength"] // 2 - status_data[current_actor["mon_select_index"]]["defence"] // 4
                        elif current_actor["cmd_index"] == 1:
                            mon_damage = current_actor["masic_list"][current_actor["masic_index"]]["数値"]
                            current_actor["MP"] -= current_actor["masic_list"][current_actor["masic_index"]]["MP"]
                        mon_damage = random.randint(mon_damage,int(mon_damage * 1.5))
                        if mon_damage <= 0:
                            mon_damage = 1
                        status_data[current_actor["mon_select_index"]]["HP"] -= mon_damage
                        lines.append(f'{status_data[current_actor["mon_select_index"]]["name"]}に　{mon_damage}の ダメージ！' )
                        mon_flash = 20
                    elif current_actor["cmd_index"] == 1 and current_actor["masic_list"][masic_index]["masic_type"] == "補助まほう":
                        # まほう（回復）
                        if masic_effect == 2:
                            if current_actor["MP"] >= current_actor["masic_list"][current_actor["masic_index"]]["MP"]:
                                recovery  = random.randint(current_actor["masic_list"][current_actor["masic_index"]]["数値"],int(current_actor["masic_list"][current_actor["masic_index"]]["数値"] * 1.5))
                                player_data[current_actor["chara_index"]]["HP"] = min(player_data[current_actor["chara_index"]]["Max_HP"],player_data[current_actor["chara_index"]]["HP"] + recovery)
                                lines.append(f'{chara_group_list[current_actor["chara_index"]]}の　きずが　かいふくした！') 
                        current_actor["MP"] -= current_actor["masic_list"][current_actor["masic_index"]]["MP"]
                        phase = 2
                    elif current_actor["cmd_index"] == 3:
                        # アイテム（回復）
                        if current_actor["item_effect"] == 2:
                            recovery  = random.randint(item_data[current_actor["item_list"][current_actor["item_index"]]]["item_parameter"],int(item_data[current_actor["item_list"][current_actor["item_index"]]]["item_parameter"] * 1.5))
                            player_data[current_actor["chara_index"]]["HP"] = min(player_data[current_actor["chara_index"]]["Max_HP"],player_data[current_actor["chara_index"]]["HP"] + recovery)
                            lines.append(f'{chara_group_list[current_actor["chara_index"]]}の　きずが　かいふくした！')
                            del current_actor["item_list"][current_actor["item_index"]]
                            # アイテムエフェクト
                        elif current_actor["item_effect"] == 1:
                            item_effect = 0
                            lines = ["しかし、なにもおこらなかった…"]
                        phase = 2
                    actor_index += 1
                    current_actor["attack_on"] = 1
                # モンスターを一体たおした時の処理
                elif defeat:
                    lines.append(f'{status_data[current_actor["mon_select_index"]]["name"]}をたおした！')
                    if status_data[current_actor["mon_select_index"]]["attack_on"] == 1:
                        actor_index -= 1
                    del mon_group_list[current_actor["mon_select_index"]]
                    del monster_rects[current_actor["mon_select_index"]]
                    del status_data[current_actor["mon_select_index"]]
                    defeat = False
                    phase = 2
                    # 自動送り
                    for data in status_data2:
                        if data["type"] == "player":
                            # 範囲外を防ぐ
                            if data["mon_select_index"] > len(mon_group_list) - 1:
                                data["mon_select_index"] = len(mon_group_list) - 1
                            # ターゲットがズレるのを防ぐ
                            elif data["attack_on"] == 0:
                                if current_actor["mon_select_index"] < data["mon_select_index"]:
                                    data["mon_select_index"] -= 1
                    # モンスターをすべてたおした時の処理
                    if len(mon_group_list) == 0:
                        bgm(win_bgm)
                        lines = ["モンスターたちをやっつけた！"]
                        phase = 5
                # モンスターの攻撃(プレイヤーに与えるダメージ)
                elif phase == 3:
                    sound.play()
                    for i in range(len(mon_group_list)):
                        if current_actor["name"] == status_data[i]["name"]:
                            # 毎回リストを初期化する
                            player_select_index = random.choice(player_select_index_list)
                            player_damage = status_data[i]["strength"] // 2 - player_data[player_select_index]["defence"] // 4
                            player_damage = random.randint(player_damage,int(player_damage * 1.5))
                            if player_data[player_select_index]["cmd_index"] == 2:
                                player_damage = int(player_damage * 0.6)
                            if player_damage <= 0:
                                player_damage = 1
                            player_data[player_select_index]["HP"] -= player_damage
                            lines.append(f'{player_data[player_select_index]["name"]}に　{player_damage}のダメージ！')
                            status_flash = 20
                            if player_data[player_select_index]["HP"] <= 0:
                                player_data[player_select_index]["HP"] = 0
                    current_actor["attack_on"] = 1
                    actor_index += 1
                # ワンテンポずらす
                elif phase == 4:
                    sound.play()
                    if len(player_select_index_list) == 0 or current_actor["cmd_index"] == 5: 
                        phase = 8
                    elif len(lines) >= 4:
                        text_up = True
                    elif level_up_chara_num == len(chara_group_list) - 1: # phase == 6とは終了の条件が違う（level_up_chara_num）
                        phase = 8
                    # 連続でレベルが上がるときのため
                    elif EXP_dict[chara_group_list[level_up_chara_num]] >= level_up_list[chara_group_list[level_up_chara_num]][level_up_index[chara_group_list[level_up_chara_num]]]:
                        phase = 6
                        status_up_list = []
                    else:
                        phase = 6
                        status_up_list = []
                        level_up_chara_num += 1
                        
                # 経験値とお金
                elif phase == 5:
                    sound.play()
                    for i in range(len(mon_group_list2)):
                        mon_EXP += get_value_by_partial_key(mon_EXP_dict,mon_group_list2[i])
                        mon_Gold += get_value_by_partial_key(mon_Gold_dict,mon_group_list2[i])
                    lines.append(f"けいけんち　{mon_EXP}かくとく")
                    lines.append(f"{mon_Gold}ゴールドを　てにいれた")
                    for key, value in EXP_dict.items():
                        EXP_dict[key] += mon_EXP
                    Gold += mon_Gold
                    mon_EXP = 0
                    mon_Gold = 0
                    phase = 6
                # レベルアップ
                elif phase == 6:
                    for i in range(len(chara_group_list)):
                        if EXP_dict[chara_group_list[level_up_chara_num]] >= level_up_list[chara_group_list[level_up_chara_num]][level_up_index[chara_group_list[level_up_chara_num]]]:
                            pygame.mixer.music.pause()
                            sound3.play()
                            level_up_index[chara_group_list[level_up_chara_num]] += 1
                            lines.append(f"{chara_group_list[level_up_chara_num]}の　レベルが上がった！")
                            phase = 7
                            break
                        else:
                            level_up_chara_num += 1
                    if level_up_chara_num == len(chara_group_list):
                        phase = 8
                elif phase == 7:
                    time.sleep(1)
                    pygame.mixer.music.unpause()
                    sound.play()

                    # 各ステータスの上昇値を決定
                    for _ in range(5):
                        loto = random.choice(hit_and_miss)
                        status_up_list.append(random.randint(1, 3) if loto == 1 else 0)

                    # ステータスアップのメッセージ作成
                    for i, value in enumerate(status_up_list):
                        if value != 0:
                            lines.append(f"{status_names[i]}が　{value}ポイント　上がった！")
                            status_data[level_up_chara_num][status_names_dict[status_names[i]]] += value

                    status_data[level_up_chara_num]["level"] += 1
                    phase = 4
                elif phase == 8:
                    sound.play()
                    pygame.quit()
                    sys.exit()
                        
            #方向キー
            if event.type == KEYDOWN:
                if command and not mon_select and not masic_select:
                    if event.key == K_DOWN:
                        cmd_num1 = (cmd_num1 + 1) % 3  # 下へ移動
                    if event.key == K_UP:
                        cmd_num1 = (cmd_num1 - 1) % 3  # 上へ移動
                    if event.key == K_RIGHT:
                        cmd_num2 = (cmd_num2 + 1) % 2  # 下へ移動
                    if event.key == K_LEFT:
                        cmd_num2 = (cmd_num2 - 1) % 2  # 下へ移動
                if mon_select or masic_phase == 2 and player_data[cmd_chara_index]["masic_list"][player_data[cmd_chara_index]["masic_index"]]["masic_type"] == "攻撃まほう":
                    if event.key == K_DOWN:
                        mon_select_index = (mon_select_index + 1) % len(mon_group_list)  # 下へ移動
                    if event.key == K_UP:
                        mon_select_index = (mon_select_index - 1) % len(mon_group_list)  # 上へ移動
                if masic_phase == 2 and player_data[cmd_chara_index]["masic_list"][player_data[cmd_chara_index]["masic_index"]]["masic_type"] == "補助まほう" or item_effect == 2:
                    if event.key == K_DOWN:
                        chara_index = (chara_index + 1) % len(chara_group_list)  # 下へ移動
                    if event.key == K_UP:
                        chara_index = (chara_index - 1) % len(chara_group_list)  # 上へ移動
                if masic_select and masic_phase <= 1:
                    if event.key == K_DOWN:
                        masic_index = (masic_index + 1) % len(player_data[cmd_chara_index]["masic_list"])  # 下へ移動
                    if event.key == K_UP:
                        masic_index = (masic_index - 1) % len(player_data[cmd_chara_index]["masic_list"])  # 上へ移動
                if item_select and item_phase <= 1:
                    if event.key == K_DOWN:                        
                        item_index = (item_index + 1) % len(player_data[cmd_chara_index]["item_list"])  # 下へ移動
                    if event.key == K_UP:
                        item_index = (item_index - 1) % len(player_data[cmd_chara_index]["item_list"])  # 上へ移動
                
```

</details>

[コードの説明](https://qiita.com/hijpa/items/c44c19ef9acb27ea21e4)