pythonのarcadeを使って、ユニット選択とボタンの表示をやってみた

# コードの処理結果
ユニットの表示
![スクリーンショット 2024-11-03 12.33.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3769985/a8e15de4-f363-d098-4b10-b9595e3b7aa2.png)

ユニット選択後
![スクリーンショット 2024-11-03 12.35.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3769985/95047229-206b-2793-b60a-8bf1d5873687.png)
![スクリーンショット 2024-11-03 12.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3769985/770ef27e-183c-e720-3801-e627a872f092.png)
![スクリーンショット 2024-11-03 12.34.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3769985/43e597e3-71d1-86d8-bff5-443eaced3ada.png)

# コードの内容
pythonのarcadeというライブラリを用いて作成しました。
ユニットを選択するとユニットの位置がターミナルに画面上にボタンが表示されます。
移動および停止ボタンをクリックするとターミナルに表示されます。

以下がコード全体です。
ポイントとしては、ボタンのレイアウトを行う際の各種設定を載せています。
ユニットの画像は各自で自由にレイアウトしてください。

もし、arcadeを使ってゲームを作成する人の中で、ボタンの設定どうすればいいのか・・・といった悩み事がある方の参考になれば嬉しいです。

# コード
```python
import arcade
import arcade.color
import arcade.color
import arcade.gui

WIDTH = 800
HEIGHT = 600
TITILE = "test_hexmap on Button"
UNIT_FILEPATH = "hogehoge.png"
UNIT_SCALE = 0.3

"""
    arcade.gui.UIFlatButtonのstyle引数では、以下のような要素をカスタマイズできます:
    font_name: フォント名（文字列またはリスト）。日本語の場合は、「Hiragino Sans」がおすすめ
    font_size: フォントサイズ（整数）
    font_color: テキストの色
    border_width: ボーダーの幅（ピクセル）
    border_color: ボーダーの色
    bg_color: ボタンの背景色
    bg_color_pressed: ボタンが押されたときの背景色
    border_color_pressed: ボタンが押されたときのボーダー色
    font_color_pressed: ボタンが押されたときのテキスト色
"""
default_style = {
    "font_name": ("calibri", "Hiragino Sans")
    , "font_size": 15
    , "font_color": arcade.color.WHITE
    , "border_width": 2
    , "border_color": None
    , "bg_color": (21, 19, 21),

    # used if button is pressed
    "bg_color_pressed": arcade.color.WHITE,
    "border_color_pressed": arcade.color.WHITE,  # also used when hovered
    "font_color_pressed": arcade.color.BLACK,
}

class UnitControlButtons:
    def __init__(self, window):
        self.manager = arcade.gui.UIManager(window)
        self.manager.enable()

        # Create "Move" button
        # default width = 100, height = 50はボタンの大きさを制御
        move_button = arcade.gui.UIFlatButton(text="移動", style=default_style)
        move_button.on_click = self.on_move_click

        # Create "Stop" button
        stop_button = arcade.gui.UIFlatButton(text="停止", style=default_style)
        stop_button.on_click = self.on_stop_click

        # Add buttons to a vertical box layout
        v_box = arcade.gui.UIBoxLayout()
        v_box.add(move_button.with_space_around(bottom=10))
        v_box.add(stop_button)

        # Add the layout to the UI manager
        self.manager.add(arcade.gui.UIAnchorWidget(anchor_x="left", anchor_y="center_y", child=v_box))

    def on_move_click(self, event):
        print("ユニット移動")

    def on_stop_click(self, event):
        print("ユニット停止")

class MyUnit(arcade.Sprite):
    def __init__(self, x, y):
        super().__init__(center_x=x, center_y=y, scale=UNIT_SCALE, filename=UNIT_FILEPATH)

class MyGame(arcade.Window):
    def __init__(self, width, height, title):
        super().__init__()
        self.unit_list = arcade.SpriteList()
        self.unit_selected = False
        self.buttons = None
    
    def setup(self):
        arcade.set_background_color(arcade.color.AMAZON)
        
        # ユニットを複数配置
        unit1 = MyUnit(x=self.width / 2, y=self.height / 2)
        self.unit_list.append(unit1)

    def on_draw(self):
        arcade.start_render()
        self.unit_list.draw()

        # unit_selectedがTrueだったら
        if self.unit_selected:
            self.buttons.manager.draw()

    def on_mouse_press(self, x, y, button, modifiers):
        unit_hit = arcade.get_sprites_at_point(point=(x, y), sprite_list=self.unit_list)
        if unit_hit:
            print("ユニット選択", unit_hit[0].center_x, unit_hit[0].center_y)
            self.unit_selected = True
            self.buttons = UnitControlButtons(self) # self ⇨ MyGameを返している
    
    def on_key_press(self, symbol, modifiers):
        if symbol == arcade.key.Q:
            print("Q key press")
            arcade.close_window()

def main():
    window = MyGame(width=WIDTH, height=HEIGHT, title=TITILE)
    window.setup()
    arcade.run()

if __name__ == "__main__":
    main()

```

# 参考文献
- [Arcade: A Primer on the Python Game Framework](https://realpython.com/arcade-python-game-framework/)
    - このサイトをほぼ模写しました。arcadeを理解するのに非常に有益なサイトです
- [The Python Arcade Library](https://api.arcade.academy/en/latest/index.html)
    - arcade公式サイト
- Gemini

# 他にもこんなことやってます
- [pythonのarcadeでhexmapを作成してみた！
](https://qiita.com/nami_fumi/items/12904d2572d7f5f3fe23)

- [Python&arcadeで簡単！レトロ風シューティングゲームを作ろう！🚀](https://qiita.com/nami_fumi/items/dc679b47f57fa5a18f68)