テスト中
戦闘たたかう
同じ名前のモンスターがいるとうまくいきません。
✖スライム スライム
〇スライム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 = モンスターの矩形情報が入ったリスト