1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pythonのarcadeでhexmapを作成してみた!

Last updated at Posted at 2024-10-31

コードの実行結果

  • ヘックスマップの描画
    スクリーンショット 2024-10-31 12.58.36.png

  • そのヘックスを押すと、周囲3hex分が薄い赤色で表示される
    スクリーンショット 2024-10-31 12.58.45.png


import arcade
import math

import arcade.key

WIDTH = 800
HEIGHT = 600
RADIUS = 30  # 半径
GRID_SIZE = 10  # hexの個数
TITLE = "test_hexmap"


class Hexmap:
    """
    六角形グリッドマップを生成・管理し、描画、クリック検出を行うためのクラス。

    初期化引数:
        radius: 六角形の半径 (int or float)
        grid_size: グリッドのサイズ (行と列の数) (int)
    """

    def __init__(self, radius, grid_size):
        """
        Hexmapオブジェクトを初期化します。

        引数:
            radius: 六角形の半径。
            grid_size: グリッドのサイズ(行と列の数)。
        """
        self.radius = radius
        self.grid_size = grid_size
        self.hex_centers = []

    def hexagon_vertices(self, x, y):
        """
        指定された中心座標(x, y)を持つ六角形の頂点座標リストを返します。

        引数:
            x: 六角形の中心 x 座標。
            y: 六角形の中心 y 座標。

        戻り値:
            [(x1, y1), (x2, y2), ..., (x6, y6)]: 六角形の頂点座標のリスト。
        """
        vertices = []  # verticesは頂点という意味
        for i in range(6):
            angle = i * math.pi / 3  # pi/3 * 0~5
            vx = x + self.radius * math.cos(angle)
            vy = y + self.radius * math.sin(angle)
            vertices.append((vx, vy))
        return vertices

    def draw_hexagon(self, clicked_hex=None):
        """
        grid_size で指定された個数のhexを描画します。
        クリックされたhexとその周囲3ヘックス分を赤色で描画します。

        引数:
            clicked_hex: クリックされた六角形の中心座標 (tuple)。
        """
        # 各六角形の位置を計算
        root_3 = math.sqrt(3)
        horizontal_spacing = 3 * self.radius / 2
        vertical_spacing = root_3 * self.radius

        for row in range(self.grid_size):  # 行(縦方向)
            for col in range(self.grid_size):  # 列(横方向)
                x = col * horizontal_spacing  # 列間隔⇨hori
                y = row * vertical_spacing  # 行間隔⇨vert

                # yが奇数の時は、縦方向で1.5倍の距離にする⇨これによって、ジグザグになる
                if col % 2 == 1:
                    y += vertical_spacing / 2
                self.hex_centers.append((x, y))
                points_list = self.hexagon_vertices(x, y)

                # クリックされたhexとその周囲3ヘックス分を赤色で描画
                """
                    ① かくhexの中心座標とクリックされた位置との距離を計算
                    ② その距離が 半径*5.5 という決め以内だったら、そのhexを塗りつぶす
                    ③ この5.5というのは、決めの部分なので、適宜調整する
                    ここの5.5の部分はいい感じに調整しなくてはいけない・・・
                """
                if clicked_hex:
                    dx = x - clicked_hex[0]
                    dy = y - clicked_hex[1]
                    distance = math.sqrt(dx**2 + dy**2)
                    if distance <= self.radius * 5.5:
                        arcade.draw_polygon_filled(point_list=points_list,
                                                    color=(255, 0, 0, 50))
                        arcade.draw_polygon_outline(point_list=points_list,
                                                    color=arcade.color.BLACK,
                                                    line_width=2)
                    # それ以外はいつもどりの描写をする
                    else:
                        arcade.draw_polygon_outline(point_list=points_list,
                                                    color=arcade.color.BLACK,
                                                    line_width=2)
                else:
                    arcade.draw_polygon_outline(point_list=points_list,
                                                color=arcade.color.BLACK,
                                                line_width=2)

    def get_clicked_hex(self, mouse_x, mouse_y):
        """
        クリックされた六角形の中心座標を返します。

        引数:
            mouse_x: マウスの x 座標。
            mouse_y: マウスの y 座標。

        戻り値:
            (center_x, center_y): クリックされた六角形の中心座標。
            None: クリックされた六角形がない場合。
        """
        for center in self.hex_centers:
            dx = mouse_x - center[0]
            dy = mouse_y - center[1]
            distance = math.sqrt(dx**2 + dy**2)
            if distance <= self.radius:
                return center
        return None


class MyHexMap(arcade.Window):

    def __init__(self, width, height, title):
        super().__init__(width, height, title)
        self.hex_map = Hexmap(radius=RADIUS, grid_size=GRID_SIZE)
        self.clicked_hex = None

    def setup(self):
        arcade.set_background_color(arcade.color.WHITE)

    def on_draw(self):
        arcade.start_render()
        self.hex_map.draw_hexagon(self.clicked_hex)

    def on_mouse_press(self, x, y, button, modifiers):
        self.clicked_hex = self.hex_map.get_clicked_hex(mouse_x=x,
                                                        mouse_y=y)
        if self.clicked_hex:
            print(f"Clicked hex point {self.clicked_hex}")

    def on_key_press(self, symbol, modifiers):
        if symbol == arcade.key.Q:
            arcade.close_window()


def main():
    myhexmap = MyHexMap(width=WIDTH, height=HEIGHT, title=TITLE)
    myhexmap.setup()
    arcade.run()


if __name__ == "__main__":
    main()

参考記事

最後に

もし、arcadeで何かしらのhexmapのゲームを作っている方の参考になれば幸いです。

他にもこんなことやってます

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?