Pygameを使って RPGを作る（14. 戦闘画面（その２））

# 概要
戦闘画面を作るのにあたり、Alpha指定のメッセージ画面の実現を目指しているが、残像が残る問題を約数時間をつぶしていた。結果的にフェードテキストを使用して、約1秒ほどにし、残像がほぼ残らないようになった。

ChatGPTやGoogleに聞いてもなかなか答えがなく。
描画のバッファを持っているから、どうしようもない問題かもしれません。

以下の解説は機械的に生成していますが、ほぼ実装内容を反映しています。

# ゲーム画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/f98191d4-a375-9599-4e1f-26e1399f0434.png)

メッセージ部分を半透明にし、少し高級感があるので、満足しています。

# ソース解説
このコードは、`pygame` を用いてバトル画面の描画を管理するクラス `Battle` を実装したものです。それぞれのメソッドがどのように動作するかを順番に解説します。

---

### **クラスの全体構造**

- `Battle` クラスは、バトルシーンを描画・制御する役割を持っています。
- 主に以下を管理しています:
  1. 背景画像や敵キャラクターの描画。
  2. テキストエリアの更新とクリア。
  3. プレイヤーの選択肢（ボタン）を管理。
  4. アニメーション（フェードインやテキストの描画効果）。

---

### **コンストラクタ: `__init__`**
```python
def __init__(self):
    self.display_surface = pg.display.get_surface()
    self.back_ground_img = pg.image.load('../battle/bg.png').convert()
    ...
```

- バトル画面の初期設定を行います。
  - `self.display_surface`: ゲームの描画対象となるスクリーン。
  - `self.back_ground_img`: バトル背景画像の読み込み。
  - `self.font`: メッセージ描画に使うフォントを設定。
  - `self.battle_message`: 表示するメッセージのリスト。
  - `self.mob_surface`: 敵キャラクターの画像を格納。

---

### **`draw` メソッド**
```python
def draw(self, player):
    enemy = player.collided_enemy
    self.mob_pos =  ((WIDTH - 128) / 2, HEIGHT / 8)
    self.mob_surface = enemy.battle_surface.copy()
    self.display_surface.blit(enemy.battle_surface, self.mob_pos)

    self.action_command()
    ...
```

- バトル画面全体を描画します。
  - 敵キャラクターを中央に配置して描画。
  - プレイヤーの行動選択肢（ボタン）を描画。
  - 最初のメッセージ（敵が出現したことを通知）を設定し、描画します。

---

### **`fade_text` メソッド**
```python
def fade_text(self):
    for alpha in range(0, 70, 5):
        temp_surface = self.back_ground_img.copy()
        temp_surface.set_alpha(alpha)
        self.display_surface.blit(temp_surface, self.rect.topleft + self.off_set)
        pg.display.flip()
        pg.time.delay(1)
    self.display_surface.blit(self.mob_surface, self.mob_pos)
```

- テキストを描画する前に、背景画像を段階的にフェード表示します。
  - `set_alpha(alpha)`: 透明度を調整してフェード効果を実現。
  - 一定間隔で `pg.display.flip()` を呼び出すことでアニメーション効果を実現しています。

---

### **`clear_text_area` メソッド**
```python
def clear_text_area(self):
    self.text_area_rect = pg.Rect(250, 430, self.bg_size[0] * 0.95, self.bg_size[1] * 0.3)

    semi_transparent_surface = pg.Surface(self.text_area_rect.size, pg.SRCALPHA)
    semi_transparent_surface.fill((0, 0, 255, 128))

    self.display_surface.blit(semi_transparent_surface, self.text_area_rect.topleft)
    pg.draw.rect(self.display_surface, (255, 255, 255), self.text_area_rect, 3, border_radius=5)
```

- テキストエリアを更新するための背景をクリアします。
  - 半透明の青い背景を描画。
  - 枠線を描画してエリアを区切ります。

---

### **`action_command` メソッド**
```python
def action_command(self):
    px = 100
    py = 300
    ...
    for button in self.action_buttons:
        button.draw(self.display_surface)
```

- プレイヤーの行動選択肢（「攻撃」「魔法」「逃げる」）のボタンを描画します。
- 各ボタンには、対応するアクション関数（`attack`, `magic`, `escape`）が紐づけられています。

---

### **`handle_mouse_event` メソッド**
```python
def handle_mouse_event(self, event):
    if event.type == pg.MOUSEBUTTONDOWN:
        mouse_pos = event.pos
        for button in self.action_buttons:
            if button.check_click(mouse_pos):
                button.action()
```

- マウスのクリックイベントを処理します。
  - クリックされた位置がどのボタンの上にあるかを判定。
  - 該当ボタンのアクション（`attack`, `magic`, `escape`）を実行。

---

### **`attack`, `magic`, `escape` メソッド**
```python
def attack(self):
    self.initial_action()
    self.battle_message.append('攻撃')
    self.draw_text()
    pg.display.update()
```

- 各アクション共通の処理を以下の順序で実行します。
  1. `initial_action`: フェードとクリア処理。
  2. 対応するメッセージを `battle_message` に追加。
  3. テキストを描画。
  4. 画面を更新。

---

### **`fade_in` メソッド**
```python
def fade_in(self):
    for alpha in range(0, 125, 5):
        temp_surface = self.back_ground_img.copy()
        temp_surface.set_alpha(alpha)
        self.display_surface.blit(temp_surface, self.rect.topleft + self.off_set)
        pg.display.flip()
        pg.time.delay(30)
```

- バトル画面全体をフェードインで表示するアニメーションを実現します。
- `set_alpha` で透明度を調整し、`pg.time.delay` で描画間隔を調整しています。

---

### **まとめ**

このクラスは `pygame` を使って、バトル画面での描画・更新・操作を実現するための便利な仕組みを提供しています。

- **フェード処理**: `fade_in` や `fade_text` で視覚的な演出を追加。
- **メッセージ描画**: `draw_text` で動的にメッセージを表示。
- **アクションボタン**: マウスクリックで対応するアクションを実行。