コードの実行結果
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()
参考記事
- geminiやperplexityによるコード
- 計算方法や配置を理解するの参考になった良記事
最後に
もし、arcadeで何かしらのhexmapのゲームを作っている方の参考になれば幸いです。