using System; using System.Diagnostics; using System.Linq; using Godot; using Array = Godot.Collections.Array; public class HexCell : Resource { public static readonly Vector2 size = new Vector2(1, Mathf.Sqrt(3) / 2); public static readonly Vector3 DIR_N = new Vector3(0, 1, -1); public static readonly Vector3 DIR_NE = new Vector3(1, 0, -1); public static readonly Vector3 DIR_SE = new Vector3(1, -1, 0); public static readonly Vector3 DIR_S = new Vector3(0, -1, 1); public static readonly Vector3 DIR_SW = new Vector3(-1, 0, 1); public static readonly Vector3 DIR_NW = new Vector3(-1, 1, 0); public static readonly Array DIR_ALL = new Array() { DIR_N, DIR_NE, DIR_SE, DIR_S, DIR_SW, DIR_NW }; public HexCell() { } public HexCell(float cubeX, float cubeY, float cubeZ) { CubeCoords = RoundCoords(new Vector3(cubeX, cubeY, cubeZ)); } public static bool operator==(HexCell cellA, HexCell cellB) { return cellA.AxialCoords == cellB.AxialCoords; } public static bool operator!=(HexCell cellA, HexCell cellB) { return cellA.AxialCoords != cellB.AxialCoords; } public HexCell(Vector3 cubeCoords) { CubeCoords = cubeCoords; } public HexCell(float axialX, float axialY) { AxialCoords = new Vector2(axialX, axialY); } public HexCell(Vector2 axialCoords) { AxialCoords = axialCoords; } public HexCell(HexCell other) { CubeCoords = other.CubeCoords; } public static HexCell FromOffsetCoords(Vector2 offsetCoords) { HexCell result = new HexCell(); result.OffsetCoords = offsetCoords; return result; } private Vector3 _cubeCoords; public Vector3 CubeCoords { get { return _cubeCoords; } set { if (Mathf.Abs(value.x + value.y + value.z) > 0.0001) { GD.Print("Warning: Invalid cube coordinates for hex (x + y + z != 0): ", value.ToString()); } _cubeCoords = RoundCoords(value); } } public Vector2 AxialCoords { get => new Vector2(CubeCoords.x, CubeCoords.y); set { CubeCoords = AxialToCubeCoords(value); } } public Vector2 OffsetCoords { get { int x = (int)CubeCoords.x; int y = (int)CubeCoords.y; int off_y = y + (x - (x & 1)) / 2; return new Vector2(x, off_y); } set { int x = (int)value.x; int y = (int)value.y; int cube_y = y - (x - (x & 1)) / 2; AxialCoords = new Vector2(x, cube_y); } } public Vector3 AxialToCubeCoords(Vector2 axialCoords) { return new Vector3(axialCoords.x, axialCoords.y, -axialCoords.x - axialCoords.y); } public Vector3 RoundCoords(Vector2 coords) { Vector3 cubeCoords = AxialToCubeCoords(coords); return RoundCoords(cubeCoords); } public Vector3 RoundCoords(Vector3 cubeCoords) { Vector3 rounded = new Vector3( Mathf.Round(cubeCoords.x), Mathf.Round(cubeCoords.y), Mathf.Round(cubeCoords.z)); Vector3 diffs = (rounded - cubeCoords).Abs(); if (diffs.x > diffs.y && diffs.x > diffs.z) { rounded.x = -rounded.y - rounded.z; } else if (diffs.y > diffs.z) { rounded.y = -rounded.x - rounded.z; } else { rounded.z = -rounded.x - rounded.y; } return rounded; } public HexCell GetAdjacent(Vector3 dir) { return new HexCell(this.CubeCoords + dir); } public HexCell[] GetAllAdjacent() { return new[] { GetAdjacent(DIR_NE), GetAdjacent(DIR_SE), GetAdjacent(DIR_S), GetAdjacent(DIR_SW), GetAdjacent(DIR_NW), GetAdjacent(DIR_N) }; } public int DistanceTo(HexCell target) { return (int)( Mathf.Abs(_cubeCoords.x - target.CubeCoords.x) + Mathf.Abs(_cubeCoords.y - target.CubeCoords.y) + Mathf.Abs(_cubeCoords.z - target.CubeCoords.z) ) / 2; } public HexCell[] LineTo(HexCell target) { HexCell nudgedTarget = new HexCell(); nudgedTarget.CubeCoords = target.CubeCoords + new Vector3(1.0e-6f, 2.0e-6f, -3.0e-6f); int steps = DistanceTo(target); HexCell[] path = new HexCell[steps + 1]; foreach (int dist in Enumerable.Range(0, steps)) { path[dist] = new HexCell(); path[dist].CubeCoords = CubeCoords.LinearInterpolate(nudgedTarget.CubeCoords, (float)dist / steps); } path[steps] = target; return path; } }