实现鼠标点击时 按照六边形tilemap格子移动

在开始做一个基于系统自带的六边形tilemap和网格做一款战棋游戏

img

我已经知道了网格坐标鼠标也能正确点击显示六边形格子的坐标,但不知道怎么实现鼠标点击时 人物也按照六边形tilemap格子移动,人物是按照四边形网格来确定移动位置的

img

额外的 如果熟悉用自带的六边形网格来做一些范围检测、A*寻路等功能的话,务必加我qq:857233825

这个相当于一个六叉树,可以使用启发类算法,进行路径的测试。

该回答引用GPTᴼᴾᴱᴺᴬᴵ
如果你的人物是按照四边形网格来确定移动位置的,那么需要一些转换来将鼠标点击的六边形格子坐标转换成对应的四边形网格坐标。

首先,将六边形格子坐标转换成对应的正方形格子坐标。可以通过以下方法实现:

def hex_to_square(q, r):
    x = q
    z = r - (q - (q & 1)) // 2
    y = -x - z
    return x, y


其中 q 和 r 分别表示六边形格子坐标中的 q 和 r 值,返回的 x 和 y 分别表示对应的正方形格子坐标中的 x 和 y 值。

然后,将正方形格子坐标转换成对应的像素坐标。可以通过以下方法实现:

def square_to_pixel(x, y, tile_size):
    px = (x - y) * tile_size
    py = (x + y) * tile_size // 2
    return px, py


其中,x 和 y 分别表示正方形格子坐标中的 x 和 y 值,tile_size 表示每个格子的大小(比如像素),返回的 px 和 py 分别表示对应的像素坐标。
·
最后,你需要将鼠标点击的六边形格子坐标转换成对应的像素坐标,然后再将其转换成对应的正方形格子坐标。假设你已经有了鼠标点击的六边形格子坐标 (q, r),那么可以按照以下步骤来实现:

# 将六边形格子坐标转换成正方形格子坐标
x, y = hex_to_square(q, r)

# 将正方形格子坐标转换成像素坐标
px, py = square_to_pixel(x, y, tile_size)

# 根据像素坐标来移动人物
move_character_to(px, py)


其中,tile_size 表示每个格子的大小,move_character_to(px, py) 表示将人物移动到对应的像素坐标 (px, py)。
·
需要注意的是,在转换坐标时,可能会出现精度误差,因此建议在比较坐标时,使用一些容差值来判断两个坐标是否相等,比如:

def is_close(a, b, tol=1e-6):
    return abs(a - b) < tol


使用 is_close(a, b, tol) 函数来比较两个坐标是否相等,tol 表示容差值。

参考GPT和自己的思路,首先,需要定义一个函数,将鼠标点击的屏幕坐标转换为对应的六边形网格坐标。该函数应该包含以下步骤:

1.将屏幕坐标转换为世界坐标
2.将世界坐标转换为六边形网格坐标
可以参考下面的代码实现这个函数:

import math

def screen_to_hex(screen_x, screen_y, tile_size):
    # 将屏幕坐标转换为世界坐标
    world_x = screen_x - tile_size/2
    world_y = screen_y - tile_size/2

    # 将世界坐标转换为六边形网格坐标
    q = (math.sqrt(3)/3 * world_x - 1/3 * world_y) / tile_size
    r = (2/3 * world_y) / tile_size

    # round to nearest integer hex coordinates
    x, y, z = round(q), round(-q-r), round(r)
    x_diff, y_diff, z_diff = abs(x-q), abs(-q-r-y), abs(r-z)

    if x_diff > y_diff and x_diff > z_diff:
        x = -y-z
    elif y_diff > z_diff:
        y = -x-z
    else:
        z = -x-y

    return (x, y, z)

接下来,需要为地图上的每个六边形网格创建一个相应的游戏对象,这里我们称之为 Tile。每个 Tile 都应该有一个 position 属性,表示其在六边形网格中的坐标。可以创建一个 Tile 类来实现这个功能:

class Tile:
    def __init__(self, position, is_passable=True):
        self.position = position
        self.is_passable = is_passable

class HexGrid:
    def __init__(self, size):
        self.size = size
        self.tiles = {}

        # 初始化每个六边形网格的位置,并将其添加到字典中
        for q in range(-size, size+1):
            for r in range(-size, size+1):
                if -q-r <= size:
                    position = (q, -q-r, r)
                    tile = Tile(position)
                    self.tiles[position] = tile

    def get_tile(self, position):
        return self.tiles.get(position)

在游戏中,每个角色都应该有一个当前位置属性。我们可以使用一个 Character 类来表示每个角色:

class Character:
    def __init__(self, position):
        self.position = position

最后,我们需要将鼠标点击事件与人物移动操作相结合。在鼠标点击事件发生时,需要将鼠标点击的屏幕坐标转换为六边形网格坐标,并检查该位置是否可通行。如果该位置不可通行,则不应该将角色移动到该位置。否则,将角色移动到该位置并更新其当前位置属性。可以使用以下代码实现:

import pygame

# 定义常量
TILE_SIZE = 64
GRID_SIZE = 10

# 初始化 Pygame
pygame.init()

# 创建 Pygame 窗口和画布
screen = pygame.display.set_mode((800, 600))
canvas = pygame.Surface((800, 600))

# 创建 HexGrid 和 Character 对象
hex_grid = HexGrid(GRID_SIZE)
character = Character((0, 0, 0))

# 游戏循环
running = True
while running:
    # 处理事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            # 将鼠标点击的屏幕坐标转换为六边形网格坐标
            mouse_x, mouse_y = pygame.mouse.get_pos()
            q, r, s = screen_to_hex(mouse_x, mouse_y, TILE_SIZE)

            # 检查该位置是否可通行
            tile = hex_grid.get_tile((q, r, s))
            if tile and tile.is_passable:
                # 更新角色位置
                character.position = (q, r, s)

    # 绘制场景
    canvas.fill((255, 255, 255))

    for tile in hex_grid.tiles.values():
        # 将六边形网格坐标转换为屏幕坐标
        x, y = hex_to_pixel(tile.position, TILE_SIZE)
        x += TILE_SIZE/2
        y += TILE_SIZE/2

        # 绘制六边形
        draw_hexagon(canvas, x, y, TILE_SIZE)

    # 将角色位置转换为屏幕坐标
    x, y = hex_to_pixel(character.position, TILE_SIZE)
    x += TILE_SIZE/2
    y += TILE_SIZE/2

    # 绘制角色
    pygame.draw.circle(canvas, (255, 0, 0), (x, y), TILE_SIZE/4)

    # 将画布绘制到 Pygame 窗口
    screen.blit(canvas, (0, 0))

    # 更新 Pygame 窗口
    pygame.display.flip()

# 退出 Pygame
pygame.quit()

需要注意的是,在这个示例中,我们没有对角色的移动进行动画处理。如果需要实现动画效果,可以使用 Pygame 中的帧率控制和渐变动画技术。
回答不易,还请采纳!!!