From 74266c8a9a7511230c7b793f2e7d85e3256c6b42 Mon Sep 17 00:00:00 2001 From: tejon Date: Fri, 30 May 2014 02:18:46 -0700 Subject: [PATCH] Merge from HexKit 1.2 HexCoord: - Added PolarNeighbor(), gets next/previous hex in same ring from origin, faster than static AtPolar() - Added AngleToHalfSextant(), HalfSextantToAngle() - Improved behavior of CartesianBoundingRectangle(), bounds were unnecessarily large in some cases. - Unity 4.5.0 can serialize structs! HexCoord is now serializable. - Readonly fields aren't exposed to the Inspector, so HexCoord is no longer immutable. - Updated Scale() to modify in-place. (Still returns, to avoid code breakage.) HexCoordinate: - Deprecated for Unity 4.5.0+. --- HexCoord.cs | 95 ++++++++++++++++++++++++++++++++++-------------- HexCoordinate.cs | 6 ++- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/HexCoord.cs b/HexCoord.cs index 68ffa55..7441204 100644 --- a/HexCoord.cs +++ b/HexCoord.cs @@ -11,16 +11,19 @@ namespace Settworks.Hexagons { /// These are "pointy topped" hexagons. The q axis points right, and the r axis points up-right. /// When converting to and from Unity coordinates, the length of a hexagon side is 1 unit. /// + [Serializable] public struct HexCoord { /// /// Position on the q axis. /// - public readonly int q; + [SerializeField] + public int q; /// /// Position on the r axis. /// - public readonly int r; + [SerializeField] + public int r; /// /// Initializes a new instance of the struct. @@ -71,7 +74,7 @@ public int AxialLength() { if (q == 0 && r == 0) return 0; if (q > 0 && r >= 0) return q + r; if (q <= 0 && r > 0) return (-q < r)? r: -q; - if (q < 0) return Z; + if (q < 0) return -q - r; return (-r > q)? -r: q; } @@ -118,6 +121,30 @@ public int PolarIndex() { public HexCoord Neighbor(int index) { return NeighborVector(index) + this; } + + public HexCoord PolarNeighbor(bool CCW = false) { + if (q > 0) { + if (r < 0) { + if (q > -r) return this + neighbors[CCW? 1: 4]; + if (q < -r) return this + neighbors[CCW? 0: 3]; + return this + neighbors[CCW? 1: 3]; + } + if (r > 0) return this + neighbors[CCW? 2: 5]; + return this + neighbors[CCW? 2: 4]; + } + if (q < 0) { + if (r > 0) { + if (r > -q) return this + neighbors[CCW? 3: 0]; + if (r < -q) return this + neighbors[CCW? 4: 1]; + return this + neighbors[CCW? 4: 0]; + } + if (r < 0) return this + neighbors[CCW? 5: 2]; + return this + neighbors[CCW? 5: 1]; + } + if (r > 0) return this + neighbors[CCW? 3: 5]; + if (r < 0) return this + neighbors[CCW? 0: 2]; + return this; + } /// /// Enumerate this hex's six neighbors. @@ -196,6 +223,7 @@ public Vector2 PolarBoundingCorner(bool CCW = false) { /// The two polar bounding corners are those whose polar angles form the widest arc. /// /// If set to true, gets the counterclockwise bounding corner. + /// If set to true, gets the other corner shared by the same ring-neighbor as normal return. public int PolarBoundingCornerIndex(bool CCW = false) { if (q == 0 && r == 0) return 0; if (q > 0 && r >= 0) return CCW? @@ -215,7 +243,7 @@ public int PolarBoundingCornerIndex(bool CCW = false) { CCW? (r < -2 * q)? 5: 0: (r > -2 * q)? 3: 2: - CCW? + CCW? (q < -2 * r)? 0: 1: (q > -2 * r)? 4: 3; } @@ -302,15 +330,21 @@ public HexCoord Mirror(int axis = 1) { /// /// Scale as a vector, truncating result. /// - /// A new representing this one after scaling. - public HexCoord Scale(float factor) - { return new HexCoord((int)(q * factor), (int)(r * factor)); } + /// This after scaling. + public HexCoord Scale(float factor) { + q = (int)(q * factor); + r = (int)(r * factor); + return this; + } /// /// Scale as a vector. /// - /// A new representing this one after scaling. - public HexCoord Scale(int factor) - { return new HexCoord(q * factor, r * factor); } + /// This after scaling. + public HexCoord Scale(int factor) { + q *= factor; + r *= factor; + return this; + } /// /// Scale as a vector. /// @@ -436,23 +470,18 @@ public static HexCoord NeighborVector(int index) /// /// Index of the first neighbor vector to enumerate. public static IEnumerable NeighborVectors(int first = 0) { - if (first == 0) { - foreach (HexCoord hex in neighbors) - yield return hex; - } else { - first = NormalizeRotationIndex(first, 6); - for (int i = first; i < 6; i++) - yield return neighbors[i]; - for (int i = 0; i < first; i++) - yield return neighbors[i]; - } + first = NormalizeRotationIndex(first, 6); + for (int i = first; i < 6; i++) + yield return neighbors[i]; + for (int i = 0; i < first; i++) + yield return neighbors[i]; } /// /// Neighbor index of 0,0 through which a polar angle passes. /// public static int AngleToNeighborIndex(float angle) - { return (int)Math.Round(angle / SEXTANT); } + { return Mathf.RoundToInt(angle / SEXTANT); } /// /// Polar angle for a neighbor of 0,0. @@ -495,13 +524,26 @@ public static IEnumerable CornerVectors(int first = 0) { /// Corner of 0,0 closest to a polar angle. /// public static int AngleToCornerIndex(float angle) - { return (int)Math.Floor(angle / SEXTANT); } + { return Mathf.FloorToInt(angle / SEXTANT); } /// /// Polar angle for a corner of 0,0. /// public static float CornerIndexToAngle(int index) { return (index + 0.5f) * SEXTANT; } + + /// + /// Half sextant of 0,0 through which a polar angle passes. + /// + public static int AngleToHalfSextant(float angle) + { return Mathf.RoundToInt(2 * angle / SEXTANT); } + + /// + /// Polar angle at which a half sextant begins. + /// + public static float HalfSextantToAngle(int index) + { return index * SEXTANT / 2; } + /// /// containing a Unity position. @@ -540,7 +582,6 @@ public static HexCoord AtPolar(int radius, int index) { /// Hex distance from 0,0. /// Desired polar angle. public static int FindPolarIndex(int radius, float angle) { - if (radius == 0) return 0; return (int)Math.Round(angle * radius * 3 / Mathf.PI); } @@ -605,14 +646,14 @@ public static HexCoord[] CartesianRectangleBounds(Vector2 cornerA, Vector2 corne HexCoord.AtPosition(max) }; Vector2 pos = results[0].Position(); - if ((pos + corners[0]).y <= min.y || (pos + corners[5]).y >= min.y) + if (pos.y - 0.5f >= min.y) results[0] += neighbors[4]; - else if ((pos + corners[1]).x <= min.x) + else if (pos.x >= min.x) results[0] += neighbors[3]; pos = results[1].Position(); - if ((pos + corners[2]).y <= max.y || (pos + corners[3]).y >= max.y) + if (pos.y + 0.5f <= max.y) results[1] += neighbors[1]; - else if ((pos + corners[1]).x >= max.x) + else if (pos.x <= max.x) results[1] += neighbors[0]; return results; } diff --git a/HexCoordinate.cs b/HexCoordinate.cs index 2de8a9d..d8d3e8f 100644 --- a/HexCoordinate.cs +++ b/HexCoordinate.cs @@ -1,10 +1,12 @@ -using UnityEngine; +// If you are using Unity 4.5.0 or higher this class is NOT needed. + +using UnityEngine; using System; namespace Settworks.Hexagons { /// Serializable hexagon grid coordinate. - /// is a struct for performance reasons, but Unity does not support serialization of structs. This serializable class is easily converted to and from , allowing it to be used in places where serialization is needed without affecting the performance of other logic. + /// is a struct for performance reasons, but Unity before v4.5.0 did not support serialization of structs. This serializable class is easily converted to and from , allowing it to be used in places where serialization is needed without affecting the performance of other logic. [Serializable] public class HexCoordinate { [SerializeField]