はじめに
この記事では、PythonのArcadeライブラリを使用して、スクロール可能な六角形マップを作成する方法を説明します。ゲーム開発などで、六角形グリッドマップを扱う際に役立つでしょう。
コード解説
scrolling.py
このファイルでは、ウィンドウの生成とスクロール機能の実装を行います。
import arcade
from components.hexmap import Hexmap
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Hex Map with Scrolling"
GRID_SIZE = 15
HEX_RADIUS = 30
SCROLL_SPEED = 25 # スクロール速度
class MyGame(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
arcade.set_background_color(arcade.color.AMAZON)
self.hexmap = Hexmap(HEX_RADIUS, GRID_SIZE)
self.view_x = 0
self.view_y = 0
self.last_key_press_time = 0
self.mouse_x = 0
self.mouse_y = 0
def on_draw(self):
arcade.start_render()
# ビューポートを設定 (スクロール)
arcade.set_viewport(self.view_x, SCREEN_WIDTH + self.view_x
, self.view_y, SCREEN_HEIGHT + self.view_y)
self.hexmap.draw_hexagon(on_mouse_coordinates=(self.mouse_x, self.mouse_y))
def on_key_press(self, key, modifiers):
dx = 0
dy = 0
if key == arcade.key.LEFT:
dx = -SCROLL_SPEED
elif key == arcade.key.RIGHT:
dx = SCROLL_SPEED
elif key == arcade.key.UP:
dy = SCROLL_SPEED
elif key == arcade.key.DOWN:
dy = -SCROLL_SPEED
new_view_x = self.view_x + dx
new_view_y = self.view_y + dy
# スクロール範囲の制限
self.view_x = min(400, max(-400, new_view_x)) # -400 ~ 400
self.view_y = min(400, max(-300, new_view_y)) # -300 ~ 400
print(f"view_x: {self.view_x}, view_y: {self.view_y}")
if key == arcade.key.Q:
arcade.close_window()
def on_mouse_motion(self, x, y, dx, dy):
"""
マウスの移動時座標をスクロールに合わせて補正
Args:
x: マウスのx座標
y: マウスのy座標
"""
self.mouse_x = x + self.view_x # 補正
self.mouse_y = y + self.view_y
def main():
game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
arcade.run()
if __name__ == "__main__":
main()
SCROLL_SPEED
変数でスクロールの速度を調整できます。on_key_press
関数で、矢印キーの入力に応じてview_x
、view_y
変数を更新し、スクロールを実現しています。スクロール範囲は-400~400、-300~400に制限されています。ここは適宜調節してください。
def on_key_press(self, key, modifiers):
# ... (コード省略)
# スクロール範囲の制限
self.view_x = min(400, max(-400, new_view_x)) # -400 ~ 400
self.view_y = min(400, max(-300, new_view_y)) # -300 ~ 400
print(f"view_x: {self.view_x}, view_y: {self.view_y}")
if key == arcade.key.Q:
arcade.close_window()
on_mouse_motion
関数では、マウスの移動時座標をスクロールに合わせて補正し取得します。
def on_mouse_motion(self, x, y, dx, dy):
"""
マウスの移動時座標をスクロールに合わせて補正
Args:
x: マウスのx座標
y: マウスのy座標
"""
self.mouse_x = x + self.view_x # 補正
self.mouse_y = y + self.view_y
components/hexmap.py
このファイルでは、六角形グリッドの生成と描画、ハイライト表示、マウス座標の取得、距離計算を行います。
import arcade
import math
class Hexmap:
"""
六角形グリッドマップを生成、描画するクラス。
ハイライト表示は、3hex分
Attributes:
radius (float): 六角形の半径。
grid_size (int): グリッドのサイズ (行と列の数)。
hex_centers (list): 各六角形の中心座標を格納するリスト。
"""
def __init__(self, radius, grid_size):
"""
Hexmapクラスのコンストラクタ。
Args:
radius (float): 六角形の半径。
grid_size (int): グリッドのサイズ。
"""
self.radius = radius
self.grid_size = grid_size
self.hex_centers = []
# 頂点の計算
def hexagon_vertices(self, x, y):
"""
六角形の頂点座標を計算する。
Args:
x (float): 六角形の中心x座標。
y (float): 六角形の中心y座標。
Returns:
vertices: 六角形の頂点座標のリスト。
"""
vertices = []
for i in range(6):
angle = i * math.pi / 3
vx = x + self.radius * math.cos(angle)
vy = y + self.radius * math.sin(angle)
vertices.append((vx, vy))
return vertices
# ヘックスマップの描画
def draw_hexagon(self
, highlight_coordinates=None
, attack_coordinates = None
, on_mouse_coordinates=None):
"""
六角形グリッドマップを描画する。
Args:
highlight_coordinates (tuple): ハイライトを表示するために必要なX,Y座標 例)クリックした位置から3hex分の周囲をハイライト表示したい場合は、クリックした位置のX,Y座標
on_mouse_coordinates (tuple): マウスのX,Y座標
"""
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
y = row * vertical_spacing
if col % 2 == 1:
y += vertical_spacing / 2
self.hex_centers.append((x, y))
hex_vertices_list = self.hexagon_vertices(x, y)
self.draw_single_hexagon(x, y, hex_vertices_list, highlight_coordinates, attack_coordinates, on_mouse_coordinates)
# ハイライトの表示
def draw_single_hexagon(self, x, y, hex_vertices_list, highlight_coordinates, attack_coordinates, on_mouse_coordinates):
"""
個々の六角形を描画する。ハイライトの有無を判断。
Args:
x (float): 六角形の中心x座標。
y (float): 六角形の中心y座標。
hex_vertices_list (list): 六角形の頂点座標リスト。
clicked_hex (tuple): クリックされた六角形の中心座標。
highlight_trigger (bool): ハイライトを有効にするかどうか。
on_mouse_point(): マウスの位置座標
"""
if highlight_coordinates:
distance = self.calcutate_distance(x, y, highlight_coordinates)
if distance <= self.radius * 5.5: # ハイライト範囲内
self.draw_highlighted_hexagon(hex_vertices_list)
else:
self.draw_normal_hexagon(hex_vertices_list)
else:
self.draw_normal_hexagon(hex_vertices_list)
if attack_coordinates:
distance = self.calcutate_distance(x, y, attack_coordinates)
if distance <= self.radius*2.0:
self.attack_highlighted_draw(hex_vertices_list)
else:
self.draw_normal_hexagon(hex_vertices_list)
else:
self.draw_normal_hexagon(hex_vertices_list)
if on_mouse_coordinates:
distance = self.calcutate_distance(x, y, on_mouse_coordinates)
if distance <= self.radius:
self.draw_hex_on_mouse(hex_vertices_list)
else:
self.draw_normal_hexagon(hex_vertices_list)
else:
self.draw_normal_hexagon(hex_vertices_list)
# ハイライトヘックスを表示
def draw_highlighted_hexagon(self, hex_vertices_list):
"""
移動範囲のハイライトされた六角形を描画する。
Args:
hex_vertices_list (list): 六角形の頂点座標リスト。
"""
arcade.draw_polygon_filled(point_list=hex_vertices_list, color=(0, 0, 255, 50))
arcade.draw_polygon_outline(point_list=hex_vertices_list, color=arcade.color.BLACK, line_width=2)
def attack_highlighted_draw(self, hex_vertices_list):
"""
攻撃範囲のハイライトされた六角形を描画する。
Args:
hex_vertices_list (list): 六角形の頂点座標リスト。
"""
arcade.draw_polygon_filled(point_list=hex_vertices_list, color=(255, 0, 0, 50))
arcade.draw_polygon_outline(point_list=hex_vertices_list, color=arcade.color.BLACK, line_width=2)
# マウスがどこのhexにいるかを表示
def draw_hex_on_mouse(self, hex_vertices_list):
"""
hexmap上のhexにマウスが置かれた時に白色に描画する
Args:
hex_vertices_list (list): 六角形の頂点座標リスト。
"""
arcade.draw_polygon_filled(point_list=hex_vertices_list, color=(255, 255, 255, 100))
arcade.draw_polygon_outline(point_list=hex_vertices_list, color=arcade.color.BLACK, line_width=2)
# 通常のヘックスを表示
def draw_normal_hexagon(self, hex_vertices_list):
"""
通常の六角形を描画する。
Args:
hex_vertices_list (list): 六角形の頂点座標リスト。
"""
arcade.draw_polygon_outline(point_list=hex_vertices_list, color=arcade.color.BLACK, line_width=2)
def get_hex_center_position(self, mouse_x, mouse_y):
"""
マウス座標から最も近い六角形の中心座標を取得する。
Args:
mouse_x (float): マウスのx座標。
mouse_y (float): マウスのy座標。
Returns:
tuple: 最も近い六角形の中心座標。見つからない場合はNone。
"""
for center in self.hex_centers:
distance = self.calcutate_distance(mouse_x, mouse_y, center)
if distance <= self.radius:
return center
return None
def calcutate_distance(self, hex_center_x, hex_center_y, point):
"""
現在地の座標と、ヘックスの中心座標との距離を算出する
Args:
hex_center_x (float): hexmapの中心x座標
hex_center_y (float): hexmapの中心y座標
hex_center_point(tuple): tuple形式のx, y座標
Returns:
tuple: 最も近い六角形の中心座標。見つからない場合はNone。
"""
# 距離の計算ロジックを入れる
dx = hex_center_x - point[0]
dy = hex_center_y - point[1]
distance = math.sqrt(dx**2 + dy**2)
return distance
実行方法
- 必要なライブラリをインストールします。実装するときは仮想環境を作成することをお勧めします。
pip install arcade
-
scrolling.py
を実行します。python scrolling.py
まとめ
この記事では、PythonとArcadeライブラリを用いてスクロール可能な六角形マップを作成する方法を紹介しました。ゲーム開発などに応用できるでしょう。
今後の展望
- スクロール機能の改善
- より高度なマップ生成アルゴリズムの実装
ほかにもこんなのやってます
- pythonのarcadeでhexmapを作成してみた!
- Python&arcadeで簡単!レトロ風シューティングゲームを作ろう!🚀
- pythonのarcadeを使って、ユニット選択とボタンの表示をやってみた
- PythonのArcadeでHexmap上のユニットを移動させる
シューティングを作成してみました!ぜひ遊んでみてください^^
参考文献
-
The Python Arcade Library
- arcade公式サイト
-
Hexagonal Grids
- Hexmapの計算方法や配置を理解するの参考になった良記事
- Gemini
- コードをよりよくするときにいいです
-
perplexity
- 初期コードを書かせる時にいいです
- pythonのarcadeでhexmapを作成してみた!