0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pygameでRPG(戦闘たたかう)

Last updated at Posted at 2025-06-02

テスト中

新RPGの目次

戦闘たたかう

同じ名前のモンスターがいるとうまくいきません。
✖スライム スライム
〇スライムA スライムB

ここにコードがあります

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, message, pos, font, color=(255, 255, 255)):
    lines = message.split('\n')
    x, y = pos
    for line in lines:
        text_surface = font.render(line, True, color)
        surface.blit(text_surface, (x, y))
        y += text_surface.get_height() * 2

# 2列×3行のテキストを描画する関数(ステータスウィンドウ・コマンドウィンドゥ)
def draw_text_grid(screen, text_list, start_x, start_y, spacing_x, spacing_y):
    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)

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()

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

bgm(battle_bgm)    

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

# 色
white = (255, 255, 255)

# カーソル
alpha = 220
delta = 5

message = "モンスターが あらわれた!"

battle_message = True
command = False
select = False
defeat = False

actor_index = 0
select_index = 0
cmd_index = 0
cmd_num1 = 0
cmd_num2 = 0

phase = 0

# 枠点滅
status_flash = 0
status_visible = 0
mon_flash = 0
mon_visible = 0
player_damage = 0
mon_damage = 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_name = "ゆうしゃ"
player_Max_HP = 53
player_HP = 53
player_Max_MP = 0
player_MP = 0
player_power = 23
player_quick = 6
player_deffence = 10
player_level = 1

# 2列×3行のテキストデータ
text_list2 = [
    ["H", "M", ""],  # 1列目
    [f"{player_HP}", f"{player_MP}", f"{player_level}"]  # 2列目
]

# モンスターの初期ステータス
mon_images_dict = {nameA: monsterA_image,
                   nameB: monsterB_image,
                   nameC: monsterC_image}
mon_HP_dict = {nameA: 4,nameB: 6,nameC: 8}
mon_power_dict = {nameA: 3,nameB: 7,nameC: 6}
mon_deffence_dict = {nameA: 4,nameB: 4,nameC: 8}
mon_quickness_dict = {nameA:3,nameB:4,nameC:8}
mon = random.choice(monster_list)
mon_group_list = mon.split()

for i in range(len(mon_group_list)):  
    status_data.append({
        "name": f"{mon_group_list[i]}",
        "HP": get_value_by_partial_key(mon_HP_dict,mon_group_list[i]),
        "power": get_value_by_partial_key(mon_power_dict,mon_group_list[i]),
        "deffence": get_value_by_partial_key(mon_deffence_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
    })

status_data.append({"name": f"{player_name}","HP":player_HP,"MP":player_MP,"power":player_power,"deffence":player_deffence,"quickness": player_quick,})


# モンスターの位置を定義(奇数・偶数で異なる)
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))
]


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

while running:
    clock.tick(60)
    # 画面を黒色に塗りつぶし
    screen.fill((0, 0, 0))
    # ステータスウィンドゥ
    if status_visible == 0:
        pygame.draw.line(screen, white, (20, 58),(118, 58))
        pygame.draw.rect(screen, white, (20, 20, 102, 134), 3)
        text = font.render("ゆうしゃ", True, white)
        screen.blit(text,(35, 35))
        draw_text_grid(screen, text_list2, start_x=32, start_y=65, spacing_x=40, spacing_y=30)  # テキスト描画
        text_list2 = [["H", "M", ""],[f"{player_HP}", f"{player_MP}", f"{player_level}"]]
    # モンスターの画像表示
    if mon_group_list:
        for i in range(len(mon_group_list)):
            if select_index == i and mon_visible == 0:
                screen.blit(get_value_by_partial_key(mon_images_dict,mon_group_list[i]), (monster_rects[i].topleft))
            if 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("ゆうしゃ", 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)  # テキスト描画
        if not select:
            screen.blit(cursor, ((cmd_rectx + 5) + 100 * cmd_num2, (cmd_recty + 40) + 34 * cmd_num1))  # カーソル描画
            cmd_index = cmd_num1 + (cmd_num2 * 3)
        # セレクトウィンドゥ
        if select:
            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 * select_index))  # カーソル描画
    # メッセージウィンドゥ
    if battle_message:
        pygame.draw.rect(screen, white, message_rect, 3,5)
        # バトルメッセージ
        draw_text(screen,message,((message_rectx + 24),(message_recty + 24)),font)

    # プレイヤーのダメージエフェクト
    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_HP <= 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[select_index]["HP"] <= 0: 
            defeat = True
        else:
            phase = 2
                
    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
                    phase = 1
                # コマンドウィンドゥを開いたまま、魔物選択ウィンドゥをひらく
                elif phase == 1:
                    sound.play()                        
                    select = True
                    phase = 2
                # 魔物選択ウィンドゥを消して、メッセージの表示
                elif phase == 2:
                    command = False
                    select = False
                    battle_message = 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()
                        message = f'{current_actor["name"]}の こうげき!'
                        phase = 3
                    # ターン終了したら、コマンドウィンドゥをひらく
                    elif actor_index == len(status_data):
                        actor_index = 0
                        select_index = 0
                        cmd_index, cmd_num1,cmd_num2 = 0, 0, 0
                        sound.play()
                        battle_message, command = False, True
                        phase = 1
                        for i in range(len(mon_group_list)):
                            status_data[i]["attack_on"] = 0
                # プレイヤーの攻撃(モンスターに与えるダメージ)
                elif phase == 3 and current_actor["name"] == "ゆうしゃ" and not defeat:
                    mon_damage = player_power // 2 - status_data[select_index]["deffence"] // 4
                    mon_damage = random.randint(mon_damage,int(mon_damage * 1.5))
                    if mon_damage <= 0:
                        mon_damage = 1
                    status_data[select_index]["HP"] -= mon_damage
                    message = f'{player_name}の こうげき!\n{status_data[select_index]["name"]}に {mon_damage}の ダメージ!' 
                    mon_flash = 20
                    actor_index += 1
                    if status_data[select_index]["attack_on"] == 1:
                        actor_index -= 1
                elif defeat:
                    message = f'{player_name}の こうげき!\n{status_data[select_index]["name"]}に {mon_damage}の ダメージ!\n{status_data[select_index]["name"]}をたおした!'
                    del mon_group_list[select_index]
                    del monster_rects[select_index]
                    del status_data[select_index]
                    defeat = False
                    phase = 2
                    # モンスターをすべてたおした時の処理
                    if len(mon_group_list) == 0:
                        bgm(win_bgm)
                        message = "モンスターたちをやっつけた!"
                        phase = 4
                # モンスターの攻撃(プレイヤーに与えるダメージ)
                elif phase == 3:
                    sound.play()
                    for i in range(len(mon_group_list)):
                        if current_actor["name"] == status_data[i]["name"]:
                            player_damage = status_data[i]["power"] // 2 - player_deffence // 4
                            player_damage = random.randint(player_damage,int(player_damage * 1.5))
                            if player_damage <= 0:
                                player_damage = 1
                            player_HP -= player_damage
                            message = f'{current_actor["name"]}の こうげき!\n{player_name}に {player_damage}のダメージ!'
                            status_flash = 20
                            if player_HP <= 0:
                                player_HP = 0
                    current_actor["attack_on"] = 1
                    actor_index += 1
                # ワンテンポずらす
                elif phase == 4:
                    sound.play()
                    phase = 5
                elif phase == 5:
                    sound.play()
                    pygame.quit()
                    sys.exit()
                        
            #方向キー
            if event.type == KEYDOWN:
                if command:
                    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 select:
                    if event.key == K_DOWN:
                        select_index = (select_index + 1) % len(mon_group_list)  # 下へ移動
                    if event.key == K_UP:
                        select_index = (select_index - 1) % len(mon_group_list)  # 上へ移動

                    
ここにコードの説明があります

コードの概要

1.インポート
 

2.関数
 部分一致で値を取得する関数 改行してテキストを描画する関数、2列×3行のテキストを描画する関数
 BGMの関数

3.セットアップ
 パス、各種変数、レクト、コマンドテキスト、勇者のステータス
 ステータステキスト、モンスター関連

4.描画
 ステータスウィンドウ、モンスター画像、コマンドウィンドゥ、魔物選択ウィンドゥ、
 バトルメッセージウィンドゥ、
 プレイヤーのダメージエフェクト + 敗北判定
 モンスターのダメージエフェクト + 倒したかどうかの判定

5.キーハンドラー
 Zキー 
 コマンドの方向キー、魔物選択の方向キー


Zキー詳細

1.phase == 0
 あらわれた!を消してコマンドウィンドゥをひらく

2.phase == 1
 コマンドウィンドゥを開いたまま、魔物選択ウィンドゥをひらく

3.phase == 2
 魔物選択ウィンドゥを消して、バトルメッセージの表示
 順番の判定 + ~のこうげきメッセージ
 ターン終了の処理

4.phase == 3
 モンスターに与えるダメージ計算

5.defeat
 モンスターをたおした時の処理
 モンスターの全滅の判定

6.phase == 3
 プレイヤーに与えるダメージ計算

7.phase == 4
 敗北した時の処理 or 勝利した時の処理

8.phase == 5
 画面閉じる


コードの説明

部分一致で値を取得する関数

(関数の目的 同じ名前のモンスターを区別するため)

def get_value_by_partial_key(dictionary, partial_key):

"""
   - dictionary: 辞書オブジェクト(キー: モンスター名, 値: 画像データなど)
- partial_key: モンスター名の一部を含む検索用文字列(例: "スライムA")

処理:
1. 辞書のすべてのキーを順番にチェックする
2. `if key in partial_key:` で部分一致を判定(完全一致でもOK)
3. 一致した場合は、対応する辞書の値を返す(`return` により関数終了)
4. どのキーとも一致しなかった場合は `None` を返す
"""

for key in dictionary:  # 辞書内のすべてのキーをチェック
    if key in partial_key:  # キーが partial_key に含まれていれば一致
        return dictionary[key]  # 一致したキーの値を返して終了

return None  # 一致するキーがなければ None を返す

#モンスターリスト
mon_group_list = ["スライムA", "スライムB"]

#モンスター情報
mon_images_dict = {
"スライム": monsterA_image,
"ウルフ": monsterB_image,
"バード": monsterC_image
}

#モンスター画像を取得
for i in range(len(mon_group_list)):
get_value_by_partial_key(mon_images_dict,mon_group_list[i])
mon_images_dictのスライムの画像を取得。


if not select:
screen.blit(cursor, ((cmd_rectx + 5) + 100 * cmd_num2, (cmd_recty + 40) + 34 * cmd_num1)) # カーソル描画
cmd_index = cmd_num1 + (cmd_num2 * 3)
コマンドのカーソルと魔物選択のカーソルを分けて描画。

if event.type == KEYDOWN:
if event.key == K_z and mon_flash == 0 and status_flash == 0:
ダメージエフェクト中のキー操作を停止する。

if status_data[select_index]["attack_on"] == 1:
actor_index -= 1

current_actor["attack_on"] = 1
モンスターに先に攻撃されてから、倒すとターン終了の条件が満たされないので調整する。


変数の説明

#色
white = 白のRGB値のタプル

#カーソル
alpha = カーソルのアルファ値の初期値
delta = カーソルのアルファ値の増減

message = バトルメッセージ

battle_message = バトルメッセージのフラグ
command = コマンドウィンドゥのフラグ
select = 魔物選択ウィンドゥのフラグ
defeat = モンスターを倒した時のフラグ

actor_index = キャラの行動を管理
select_index = 魔物の選択を管理
cmd_index = コマンドの選択を管理(使用されてない)
cmd_num1 = カーソルのタテ移動を管理
cmd_num2 = カーソルのヨコ移動を管理

phase = 戦闘状態を管理

#枠点滅
status_flash = ステータスウィンドウの点滅時間を管理
status_visible = ステータスウィンドウの表示非表示を管理
mon_flash = モンスター画像の点滅時間を管理
mon_visible = モンスター画像の表示非表示を管理
player_damage = プレイヤーのダメージを管理
mon_damage = モンスターのダメージを管理

#レクト
select_rect = 魔物選択ウィンドゥの矩形情報
select_rectx,select_recty = 魔物選択ウィンドゥの座標
cmd_rect = コマンドウィンドゥの矩形情報
cmd_rectx,cmd_recty = コマンドウィンドゥの座標

#2列×3行のテキストデータ
text_list = コマンドテキストの2次元配列

status_data = プレイヤーとモンスターのステータスが入った辞書のリスト
(初期値は空のリスト)
status_data2 = すばやさが高い順に並び変えられたstatus_dataのコピー
current_actor = status_data2からactor_indexを使って選ばれたひとつの辞書

#勇者の初期ステータス
player_name = プレイヤーの名前テキスト
player_Max_HP = 最大HP
player_HP = HP
player_Max_MP = 最大MP
player_MP = MP
player_power = ちから
player_quick = すばやさ
player_deffence = 防御力
player_level = レベル

#2列×3行のテキストデータ
text_list2 = ステータステキストの2次元配列

#モンスター
nameA = モンスターの名前
nameB = モンスターの名前
nameC = モンスターの名前
groupA = モンスターグループ
(モンスター名が空白で区切られたひとつの文字列)
groupB = モンスターグループ
(モンスター名が空白で区切られたひとつの文字列)
groupC = モンスターグループ
(モンスター名が空白で区切られたひとつの文字列)
monster_list = groupA,groupB,groupCが入ったリスト

#モンスターの初期ステータス
mon_images_dict = モンスター名がキー、モンスター画像が値の辞書
mon_HP_dict = モンスター名がキー、モンスターのHPが値の辞書
mon_power_dict = モンスター名がキー、モンスターのちからが値の辞書
mon_deffence_dict = モンスター名がキー、モンスターの防御力が値の辞書
mon_quickness_dict = モンスター名がキー、モンスターのすばやさが値の辞書
mon = monster_listからランダムで選ばれた、ひとつのモンスターグループを表した文字列

mon_group_list = モンスターグループのリスト
(要素は文字列、数は選ばれたグループによって変わる)

"attack_on":  モンスターが攻撃した時のフラグ(save_dataのキー)

#モンスターの位置を定義(奇数・偶数で異なる)
monster_positions = ヨコ座標を決めるのに使われる、数値が入った辞書

#モンスターの位置を設定
monster_rects = モンスターの矩形情報が入ったリスト


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?