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

# 概要
Pygameには、メニューを実装しておらず、当然PopUpみたい機能がなく、Buttonすら用意されていないため、かなり下位レベルから作りこむ必要があった。
たたし、今回はChatGPTを借りて、Buttonグループを一元管理することで簡単に切り替えることが可能。
PopUpを一所懸命につくろうとしたが、なんだかあったり、ChatGPTちゃんが簡単にできてしまった。

あと、Alpha表示において、残像が残る問題があって、未だに解決していない。
以下は、これまでの完成画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/e0ca5566-edba-7a32-d8b0-676bcd575b71.png)

今回は作り途中のソースが整理されていない状態なので、Battleクラスは、スキップする

# Buttonクラス
今回は、マウス操作によるメニューを作っているの、Buttonクラスを整理しました。

このコードは、**Pygame** を用いてボタンを描画し、ホバーやクリックなどの動作を実現するクラス `Button` の実装です。以下で各部分を詳しく説明します。

---

### コンストラクタ `__init__(self, x, y, width, height, text, action)`

このメソッドは、ボタンオブジェクトを初期化します。

- **`x, y, width, height`**: ボタンの位置とサイズを指定します。
  - `self.rect` はボタンの矩形領域を表します。

- **`text`**: ボタンに表示するテキスト。
  - `self.text` に保存します。

- **`action`**: ボタンがクリックされたときに実行される関数。
  - これを `self.action` に保存します。

- **`self.color, self.hover_color`**:
  - `self.color`: 通常時のボタンの背景色 (青)。
  - `self.hover_color`: マウスホバー時のボタンの背景色 (赤)。

- **`self.font`**: ボタンに表示するテキストのフォント。
  - 外部フォント `Meiryo.ttf` を使用しています。

- **`self.text_surface`**:
  - 指定されたテキストを描画するための `Surface` オブジェクト。
  - フォントを使用して白色で描画しています。

- **`self.text_rect`**:
  - テキストの位置をボタンの中央に配置するための矩形。

- **`self.current_color`**:
  - ボタンの現在の色を保持します。通常時は `self.color` を初期値とします。

---

### `draw(self, screen)`

このメソッドは、ボタンを画面に描画します。

1. **マウス位置の取得**:
   ```python
   mouse_pos = pg.mouse.get_pos()
   ```

2. **ホバー判定**:
   - マウスがボタン領域（`self.rect`）に重なっているかを判定します。
     ```python
     if self.rect.collidepoint(mouse_pos):
         self.current_color = self.hover_color
     else:
         self.current_color = self.color
     ```

3. **ボタン背景の描画**:
   - 判定結果に基づき、`self.current_color` を背景色としてボタンの矩形を描画します。
     ```python
     pg.draw.rect(screen, self.current_color, self.rect, border_radius=5)
     ```
     - `border_radius=5` によりボタンの角が少し丸くなります。

4. **テキストの描画**:
   - テキストは事前に生成した `self.text_surface` を使い、矩形 `self.text_rect` の位置に描画します。
     ```python
     screen.blit(self.text_surface, self.text_rect)
     ```

---

### `check_click(self, mouse_pos)`

このメソッドは、指定されたマウスの位置（クリックされた位置）がボタン内にあるかを判定します。

- **マウス位置判定**:
  ```python
  return self.rect.collidepoint(mouse_pos)
  ```
  - `self.rect.collidepoint(mouse_pos)` は、`mouse_pos` がボタンの矩形領域内に含まれている場合に `True` を返します。
  - この結果を返すことで、ボタンがクリックされたかどうかを判定します。

---

### 動作フロー

1. **初期化時**:
   - ボタンの位置、サイズ、テキスト、背景色などが設定されます。

2. **描画時**:
   - `draw` メソッドが呼ばれると、現在のマウス位置に基づいてボタンの色が変更され、テキストと背景が描画されます。

3. **クリック判定**:
   - `check_click` を使用して、クリック位置がボタン内にあるかを判定します。
   - クリック位置がボタン内にあれば、`self.action()` を実行する仕組みと組み合わせることで動作を実現します。

---

### 例: ボタンの利用

以下のようにボタンを生成し、イベントループで `draw` や `check_click` を呼び出して動作させます。

```python
# ボタンの生成
button = Button(100, 100, 150, 50, "Click Me", lambda: print("Button Clicked!"))

# ゲームループ
running = True
while running:
    screen.fill((0, 0, 0))  # 背景をクリア

    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False
        elif event.type == pg.MOUSEBUTTONDOWN:
            if button.check_click(pg.mouse.get_pos()):
                button.action()  # ボタンのアクションを実行

    button.draw(screen)  # ボタンを描画
    pg.display.flip()

pg.quit()
```

---

### ポイント

- **テキストの中央揃え**:
  - `self.text_rect` を使用して、テキストをボタンの中心に配置しています。

- **ホバーの視覚効果**:
  - `self.current_color` を切り替えることで、ホバー時に色が変わる視覚効果を実現しています。

- **クリック判定の分離**:
  - ボタン内部のクリック判定 (`check_click`) を独立させることで、柔軟なイベント処理が可能になります。

このクラスは、シンプルで柔軟なボタン機能を提供します。