pygameでRPG（ダメージ計算）



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

参考にしたサイト
[頭が痛くならない「ダメージ計算式」の基本の話](https://note.com/daraneko_games/n/n9819dda2698a)

# ダメージ計算

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

```python:

import pygame
import sys
from pygame.locals import *
import random

# テキストを改行して描画する関数
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

pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("ダメージ計算")

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


# 勇者の初期ステータス
player_name = "ゆうしゃ"
player_power = 13

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

mon_images_dict = {nameA:monsterA_image,
                   nameB:monsterB_image,
                   nameC:monsterC_image}

mon_HP_dict = {nameA: 4,nameB: 6,nameC: 8}
mon_deffence_dict = {nameA: 4,nameB: 4,nameC: 8}

status_data = []

for i in range(len(mon_group_list)):  
    status_data.append({
        "name": f"{mon_group_list[i]}",
        "HP": mon_HP_dict[mon_group_list[i]],
        "deffence": mon_deffence_dict[mon_group_list[i]],
        "image": mon_images_dict[mon_group_list[i]],
    })

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

# モンスターの位置を設定
monster_rects = [
    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))
]

arrow_index = 0  # 選択カーソルの位置
window_rect = pygame.Rect(width * 0.4,height * 0.65,220,140)
rectx,recty = window_rect.topleft


# 色
black = (0, 0, 0)
white = (255,255,255)

battle_message = False
select = True
message = ""
phase = 0
damage = 0

clock = pygame.time.Clock()
running = True
while running:
    clock.tick(60)
    screen.fill(black)
    # メッセージウィンドゥ
    if battle_message:
        pygame.draw.rect(screen, white, Rect(20, 320, 600, 140), 3)
        # バトルメッセージ
        draw_text(screen,message,(40,350),font)
    # モンスター画像の描画
    for i in range(len(mon_group_list)):
        screen.blit(mon_images_dict[mon_group_list[i]], (monster_rects[i].topleft))

    # 魔物選択ウィンドゥ
    if select:
        pygame.draw.rect(screen,white,window_rect,3,5)
        # モンスター名の描画
        if mon_group_list:
            for i, mon in enumerate(mon_group_list):
                text = font.render(mon, True, white)
                screen.blit(text, ((rectx + 14) + 30, (recty + 14) + 34 * i))
            screen.blit(cursor_img, ((rectx + 14), (recty + 14) + 34 * arrow_index))  # カーソル描画

    pygame.display.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        elif event.type == KEYDOWN:
            if event.key == K_UP and mon_group_list:
                arrow_index = (arrow_index - 1) % len(mon_group_list)  # 上へ移動

            elif event.key == K_DOWN and mon_group_list:
                arrow_index = (arrow_index + 1) % len(mon_group_list)  # 下へ移動

            elif event.key == K_z and mon_group_list:
                if phase == 0:  
                    select = False
                    battle_message = True
                    message = f"{player_name}のこうげき！"
                    phase = 1
                elif phase == 1:  
                    damage = player_power // 2 - status_data[arrow_index]["deffence"] // 4
                    damage = random.randint(damage,int(damage * 1.5))
                    if damage <= 0:
                        damage = 1
                    status_data[arrow_index]["HP"] -= damage
                    message = f'{player_name}のこうげき！\n{status_data[arrow_index]["name"]}に　{damage}の ダメージ！'
                    if status_data[arrow_index]["HP"] <= 0: 
                        phase = 2
                    else:
                        phase = 3
                elif phase == 2:
                    message = f'{player_name}のこうげき！\n{status_data[arrow_index]["name"]}に　{damage}の ダメージ！\n{status_data[arrow_index]["name"]}をたおした！'
                    del mon_group_list[arrow_index]
                    del monster_rects[arrow_index]
                    del status_data[arrow_index]
                    if mon_group_list:
                        arrow_index = min(arrow_index, len(mon_group_list) - 1)  # 削除後のカーソル位置調整
                    else:
                        arrow_index = 0  # リストが空ならカーソルをリセット
                    phase = 3
                elif phase == 3:
                    select = True
                    battle_message = False
                    phase = 0
                    
            elif event.key == K_x:
                print(arrow_index,mon_group_list,monster_rects,status_data)

                    
```
</details>


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

```python

damage = player_power // 2 - mon_deffence // 4

```
ダメージ計算です。

---    
```python
damage = random.randint(damage,int(damage * 1.5))
```
ダメージに幅を持たせています。同じ数値だと、飽きてしまうからです。

---
```python
    if damage <= 0:
        damage = 1
```
ダメージが 0 以下にならないように調整
ダメージが0やマイナスだと違和感があるので最低値を1に設定

---
```python
    mon_HP -= damage
```
モンスターのHPを減少

---
```python
    message = f"{player_name}のこうげき！\n{mon_name}に　{damage}の ダメージ！"

    return mon_HP,message,damage
```
メッセージの更新

---
```python
elif phase == 1:  
    status_data[arrow_index]["HP"],message,damage = mon_damage(player_name,player_power,status_data[arrow_index]["name"],status_data[arrow_index]["HP"],status_data[arrow_index]["deffence"],damage,message)
```
mon_damage関数を実行し、値を更新

---
```python
    if status_data[arrow_index]["HP"] <= 0: 
        phase = 2
    else:
        phase = 3
```
モンスターを倒したかどうかでフェーズを分岐。
（単純にphase = 2　にすると、倒せなかった場合、
無駄に１回キー操作が増えるので、分岐させてます）

---


</details>