Files
back_cantanBuilding/Assets/Scripts/HexGrid/Math/HexMath.cs
2026-05-26 16:15:54 +08:00

121 lines
4.0 KiB
C#

using System.Numerics;
using PlayFab.Internal;
using UnityEngine;
using Vector3 = UnityEngine.Vector3;
// 项目中主要采用的是尖顶的 pointy-top ,平顶的 Flat-top 后续在考虑
namespace HexGrid.Math
{
public static class HexMath {
//
private static float _gridSize;
private static Vector3 _originPos = Vector3.zero;
// size = hex radius (distance center->corner)
// pointy-top axial coordinates on XZ plane
// Arial坐标 ->World
public static Vector3 AxialToPixel(int q, int r )
{
var x = _gridSize * Mathf.Sqrt(3f) * (q + r / 2f);
var z = _gridSize * 1.5f * r;
return new Vector3(x, 0, z) + _originPos;
}
//Arial -> World
public static Vector2Int PixelToAxial(Vector3 pos)
{
var posRelative = pos - _originPos;
Debug.Log($"posRelative->{pos}-> {posRelative}");
var q = (Mathf.Sqrt(3f) / 3f * posRelative.x - 1f / 3f * posRelative.z) / _gridSize;
var r = (2f / 3f * posRelative.z) / _gridSize;
return HexRound(q, r);
}
private static Vector2Int HexRound(float q, float r)
{
float x = q;
float z = r;
float y = -x - z;
int rx = Mathf.RoundToInt(x);
int ry = Mathf.RoundToInt(y);
int rz = Mathf.RoundToInt(z);
float x_diff = Mathf.Abs(rx - x);
float y_diff = Mathf.Abs(ry - y);
float z_diff = Mathf.Abs(rz - z);
if (x_diff > y_diff && x_diff > z_diff)
{
rx = -ry - rz;
}
else if (y_diff > z_diff)
{
ry = -rx - rz;
}
else
{
rz = -rx - ry;
}
return new Vector2Int(rx, rz);
}
public static Vector3 HexToWorld(HexCoord h, float size, float height=0f) {
float x = size * (Mathf.Sqrt(3f) * h.q + Mathf.Sqrt(3f) / 2f * h.r);
float z = size * (3f/2f * h.r);
return new Vector3(x, height, z);
}
// worldPos: arbitrary world point (x,y,z). We project onto XZ plane and compute axial coords.
public static HexCoord WorldToHexXZ(Vector3 worldPos, float size) {
float x = worldPos.x;
float z = worldPos.z;
float qf = (Mathf.Sqrt(3f)/3f * x - 1f/3f * z) / size;
float rf = (2f/3f * z) / size;
return CubeRound(AxialToCube(qf, rf));
}
private struct Cube { public float x,y,z; public Cube(float x,float y,float z){this.x=x;this.y=y;this.z=z;} }
private static Cube AxialToCube(float q, float r) {
float x = q;
float z = r;
float y = -x - z;
return new Cube(x,y,z);
}
private static HexCoord CubeRound(Cube c) {
int rx = Mathf.RoundToInt(c.x);
int ry = Mathf.RoundToInt(c.y);
int rz = Mathf.RoundToInt(c.z);
float x_diff = Mathf.Abs(rx - c.x);
float y_diff = Mathf.Abs(ry - c.y);
float z_diff = Mathf.Abs(rz - c.z);
if (x_diff > y_diff && x_diff > z_diff) rx = -ry - rz;
else if (y_diff > z_diff) ry = -rx - rz;
else rz = -rx - ry;
return new HexCoord(rx, rz); // axial q = x, r = z
}
public static int Distance(HexCoord a, HexCoord b) {
int ax = a.q, az = a.r, ay = -ax - az;
int bx = b.q, bz = b.r, by = -bx - bz;
return Mathf.Max(Mathf.Abs(ax - bx), Mathf.Abs(ay - by), Mathf.Abs(az - bz));
}
public static void SetGridSize(float gridSize)
{
_gridSize = gridSize;
}
public static float GetGridSize() => _gridSize;
public static void SetHexMapOrigin(Vector3 zero)
{
_originPos = new Vector3(zero.x,0,zero.z);
}
public static void Log(object t)
{
}
}
}