/// <summary> /// Initialize a new hex map /// </summary> /// <param name="orientation">Flat topped or pointy topped orientation</param> /// <param name="ringCount">The number of rings around the hex in the center</param> /// <param name="hexSize">The size (distance from center to vertex) of a hex</param> public HexMap(HexOrientation orientation, int ringCount, double hexSize = 1) { if (ringCount < 0) { throw new ArgumentOutOfRangeException("ringCount", "The ringCount param must be >= 0"); } Rings = ringCount; Map = new List <HexMapItem <T> >(); // Generate the map items. Loop over x, y, and z coordinates from -ringCount // to +ringCount, but skipping any cases where x + y + z != 0 for (int x = -1 * ringCount; x <= ringCount; x++) { for (int y = -1 * ringCount; y <= ringCount; y++) { for (int z = -1 * ringCount; z <= ringCount; z++) { if (x + y + z == 0) { Map.Add(new HexMapItem <T>(orientation, hexSize, x, y, z)); } } } } }
private Canvas GetPieceInHandCanvas(Piece piece, double size, HexOrientation hexOrientation, bool disabled) { Point center = new Point(size, size); HexType hexType = (piece.Color == Core.Color.White) ? HexType.WhitePiece : HexType.BlackPiece; Shape hex = GetHex(center, size, hexType, hexOrientation); UIElement hexText = GetHexText(center, size, piece.PieceName, disabled); Canvas pieceCanvas = new Canvas { Height = size * 2, Width = size * 2, Margin = new Thickness(PieceCanvasMargin), Background = (piece.Color == Core.Color.White) ? WhiteHandStackPanel.Background : BlackHandStackPanel.Background, Name = EnumUtils.GetShortName(piece.PieceName) }; pieceCanvas.Children.Add(hex); pieceCanvas.Children.Add(hexText); // Add highlight if the piece is selected if (VM.AppVM.EngineWrapper.TargetPiece == piece.PieceName) { Shape highlightHex = GetHex(center, size, HexType.SelectedPiece, hexOrientation); pieceCanvas.Children.Add(highlightHex); } pieceCanvas.MouseLeftButtonUp += PieceCanvas_MouseLeftButtonUp; pieceCanvas.MouseRightButtonUp += CancelClick; return(pieceCanvas); }
/// <summary> /// Create a HexMap of type SolidColorBrush and set the value to a different colored /// brush for each ring in the map /// </summary> /// <param name="orientation">Flat or pointy topped</param> /// <param name="ringCount">Number of rings around the center hex</param> private static HexMap <SolidColorBrush> CreateHexMapWithRingColors(HexOrientation orientation, int ringCount) { // Set up some colors for hex fills var ringColors = new[] { new SolidColorBrush(Colors.Red), new SolidColorBrush(Colors.Yellow), new SolidColorBrush(Colors.Blue), new SolidColorBrush(Colors.Orange), new SolidColorBrush(Colors.Green) }; var hexGrid = new HexMap <SolidColorBrush>(orientation, ringCount, 45); // Set the value of each item to a solid color brush which varies per ring for (int i = 0; i <= Math.Min(ringCount, ringColors.Length - 1); i++) { foreach (var hex in hexGrid.Ring(i)) { hex.Value = ringColors[i]; } } return(hexGrid); }
public void SaveConfig(Stream outputStream) { if (null == outputStream) { throw new ArgumentNullException("outputStream"); } XmlWriterSettings settings = new XmlWriterSettings { Indent = true }; using (XmlWriter writer = XmlWriter.Create(outputStream, settings)) { writer.WriteStartElement("Mzinga.Viewer"); writer.WriteAttributeString("version", AppViewModel.FullVersion); writer.WriteAttributeString("date", DateTime.UtcNow.ToString()); writer.WriteElementString("EngineType", EngineType.ToString()); writer.WriteElementString("EngineCommandLine", EngineCommandLine); writer.WriteElementString("HexOrientation", HexOrientation.ToString()); writer.WriteElementString("NotationType", NotationType.ToString()); writer.WriteElementString("DisablePiecesInHandWithNoMoves", DisablePiecesInHandWithNoMoves.ToString()); writer.WriteElementString("DisablePiecesInPlayWithNoMoves", DisablePiecesInPlayWithNoMoves.ToString()); writer.WriteElementString("HighlightTargetMove", HighlightTargetMove.ToString()); writer.WriteElementString("HighlightValidMoves", HighlightValidMoves.ToString()); writer.WriteElementString("HighlightLastMovePlayed", HighlightLastMovePlayed.ToString()); writer.WriteElementString("BlockInvalidMoves", BlockInvalidMoves.ToString()); writer.WriteElementString("RequireMoveConfirmation", RequireMoveConfirmation.ToString()); writer.WriteEndElement(); } }
public virtual void Init(Transform root, HexGridShape shape, int lines, int columns, float radius, HexOrientation orientation) { this.root = root; this.shape = shape; this.lines = lines; this.columns = columns; this.radius = radius; this.orientation = orientation; //Generating a new grid, clear any remants and initialise values Clear(); //Generate the grid shape switch (shape) { case HexGridShape.Hexagon: GenerateHexShape(); break; case HexGridShape.Rectangle: GenerateRectShape(); break; default: break; } }
private Point GetPoint(Position position, double size, HexOrientation hexOrientation, bool stackShift = false) { if (null == position) { throw new ArgumentNullException("position"); } if (size <= 0) { throw new ArgumentOutOfRangeException("size"); } double x = hexOrientation == HexOrientation.FlatTop ? size * 1.5 * position.Q : size *Math.Sqrt(3.0) * (position.Q + (0.5 * position.R)); double y = hexOrientation == HexOrientation.FlatTop ? size * Math.Sqrt(3.0) * (position.R + (0.5 * position.Q)) : size * 1.5 * position.R; if (stackShift && position.Stack > 0) { x += hexOrientation == HexOrientation.FlatTop ? size * 1.5 * StackShiftRatio * position.Stack : size *Math.Sqrt(3.0) * StackShiftRatio * position.Stack; y -= hexOrientation == HexOrientation.FlatTop ? size * Math.Sqrt(3.0) * StackShiftRatio * position.Stack : size * 1.5 * StackShiftRatio * position.Stack; } return(new Point(x, y)); }
public HexTile(HexCoordinates coordinates, float outerRadius, HexOrientation orientation, Vector3 center) { Coords = coordinates; Center = center; Corners = new Vector3[CornerCount]; CalculateCorners(coordinates, orientation, outerRadius); }
public Vector2 hex_corner_offset(HexLayout layout, int corner) { HexOrientation M = layout.orientation; Vector2 size = layout.size; double angle = 2 * System.Math.PI * (corner + M.start_angle) / 6; return(new Vector2(size.x * (float)System.Math.Cos(angle), size.y * (float)System.Math.Sin(angle))); }
/// <summary> /// Sets internal fields and calls CalculateVertices() /// </summary> private void Initialize(float x, float y, float side, HexOrientation orientation) { this.x = x; this.y = y; this.side = side; this.orientation = orientation; this.hexState = new HexState(); CalculateVertices(); }
// Use this for initialization public static float AngleOfCorner(int corner, HexOrientation orientation) { float angle = 210 - 60 * corner; if (orientation == HexOrientation.Flat) { angle += 30; } return(angle); }
public HexMapItem(HexOrientation orientation, double size, int x, int y, int z) : base(x, y, z) { Orientation = orientation; Size = size; CalculateCetnerPoint(); CalculateVerticies(); SetVerticieDirections(); DeriveFacesFromVerticies(); SetFaceDirections(); }
public Vector2 hex_to_pixel(HexLayout layout, Hex h) { HexOrientation M = layout.orientation; Vector2 size = layout.size; Vector2 origin = layout.origin; double x = (M.f0 * h.q + M.f1 * h.r) * size.x; double y = (M.f2 * h.q + M.f3 * h.r) * size.y; return(new Vector2((x + origin.x), (y + origin.y))); }
/// <summary> /// Sets internal fields and calls CalculateVertices() /// </summary> private void Initialize(float x, float y, float side, float? apotema, HexOrientation orientation) { this.x = x; this.y = y; this.side = side; this.orientation = orientation; this.colors[0] = Color.White; if (apotema.HasValue) { CalculateVertices(side/2, apotema.Value); } else CalculateVertices(); }
public static Vector3 Corner(Vector3 origin, float radius, int corner, HexOrientation orientation) { float angle = 60 * corner; if (orientation == HexOrientation.Pointy) { angle += 30; } angle *= Mathf.PI / 180; return(new Vector3(origin.x + radius * Mathf.Cos(angle), 0.0f, origin.z + radius * Mathf.Sin(angle))); }
public Hex pixel_to_hex(HexLayout layout, Vector2 p) { HexOrientation M = layout.orientation; Vector2 size = layout.size; Vector2 origin = layout.origin; Vector2 pt = new Vector2((p.x - origin.x) / size.x, (p.y - origin.y) / size.y); double q = M.b0 * pt.x + M.b1 * pt.y; double r = M.b2 * pt.x + M.b3 * pt.y; return(new Hex(q, r, -q - r)); }
/// <summary> /// Sets internal fields and calls CalculateVertices() /// </summary> private void Initialize(float x, float y, int i, int j, float side, Hexagonal.HexOrientation orientation, Color hexColor) { this.x = x; this.y = y; this.i = i; this.j = j; this.side = side; this.orientation = orientation; this.hexState = new HexState(); this.hexState.BackgroundColor = hexColor; this.astar = new AStar(); CalculateVertices(); }
public Vector3 GetDirection(HexDirection dir, HexOrientation mode) { Vector3 vec = Vector3.zero; if (mode == HexOrientation.PointySides) { if (dir == HexDirection.N || dir == HexDirection.S) { vec = height * locUnits[idx[1]]; } else if (dir == HexDirection.NE || dir == HexDirection.SW) { vec = 1.5f * radius * locUnits[idx[0]] + 0.5f * height * locUnits[idx[1]]; } else if (dir == HexDirection.E || dir == HexDirection.W) { vec = 1.5f * radius * locUnits[idx[0]]; } else if (dir == HexDirection.SE || dir == HexDirection.NW) { vec = 1.5f * radius * locUnits [idx[0]] - 0.5f * height * locUnits [idx[1]]; } } else { if (dir == HexDirection.N || dir == HexDirection.S) { vec = 1.5f * radius * locUnits[idx[1]]; } else if (dir == HexDirection.NE || dir == HexDirection.SW) { vec = 0.5f * height * locUnits[idx[0]] + 1.5f * radius * locUnits[idx[1]]; } else if (dir == HexDirection.E || dir == HexDirection.W) { vec = height * locUnits[idx[0]]; } else if (dir == HexDirection.SE || dir == HexDirection.NW) { vec = 0.5f * height * locUnits [idx[0]] - 1.5f * radius * locUnits [idx[1]]; } } if (dir == HexDirection.S || dir == HexDirection.SW || dir == HexDirection.W || dir == HexDirection.NW) { vec *= -1.0f; } return(vec); }
void CalculateCorners(HexCoordinates coordinates, HexOrientation orientation, float outerRadius) { for (int i = 0; i < CornerCount; i++) { float angle = 60 * i; if (orientation == HexOrientation.POINTY) { angle += 30; } angle *= Mathf.PI / 180; Corners[i].x = Center.x + outerRadius * Mathf.Cos(angle); Corners[i].y = Center.y; Corners[i].z = Center.z + outerRadius * Mathf.Sin(angle); } }
public static Mesh GenerateHexMesh(float radius, HexOrientation orientation) { Mesh mesh = new Mesh(); List <Vector3> verts = new List <Vector3>(); List <int> tris = new List <int>(); List <Vector2> uvs = new List <Vector2>(); for (int i = 0; i < 6; i++) { verts.Add(Corner(Vector3.zero, radius, i, orientation)); } tris.Add(0); tris.Add(2); tris.Add(1); tris.Add(0); tris.Add(5); tris.Add(2); tris.Add(2); tris.Add(5); tris.Add(3); tris.Add(3); tris.Add(5); tris.Add(4); //UVs are wrong, I need to find an equation for calucalting them uvs.Add(new Vector2(0.5f, 1f)); uvs.Add(new Vector2(1, 0.75f)); uvs.Add(new Vector2(1, 0.25f)); uvs.Add(new Vector2(0.5f, 0)); uvs.Add(new Vector2(0, 0.25f)); uvs.Add(new Vector2(0, 0.75f)); mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.uv = uvs.ToArray(); mesh.name = "Hexagonal Plane"; mesh.RecalculateNormals(); return(mesh); }
/// <summary> /// Sets internal fields and calls CalculateVertices() /// </summary> private void Initialize(float x, float y, float side, float?apotema, HexOrientation orientation) { this.x = x; this.y = y; this.side = side; this.orientation = orientation; this.colors[0] = Color.White; if (apotema.HasValue) { CalculateVertices(side / 2, apotema.Value); } else { CalculateVertices(); } }
public void SaveConfig(Stream outputStream) { if (null == outputStream) { throw new ArgumentNullException(nameof(outputStream)); } XmlWriterSettings settings = new XmlWriterSettings { Indent = true }; using (XmlWriter writer = XmlWriter.Create(outputStream, settings)) { writer.WriteStartElement("Mzinga.Viewer"); writer.WriteAttributeString("version", AppVM.FullVersion); writer.WriteAttributeString("date", DateTime.UtcNow.ToString()); writer.WriteElementString("EngineType", EngineType.ToString()); writer.WriteElementString("EngineCommandLine", EngineCommandLine); writer.WriteElementString("HexOrientation", HexOrientation.ToString()); writer.WriteElementString("NotationType", NotationType.ToString()); writer.WriteElementString("PieceStyle", PieceStyle.ToString()); writer.WriteElementString("PieceColors", PieceColors.ToString()); writer.WriteElementString("DisablePiecesInHandWithNoMoves", DisablePiecesInHandWithNoMoves.ToString()); writer.WriteElementString("DisablePiecesInPlayWithNoMoves", DisablePiecesInPlayWithNoMoves.ToString()); writer.WriteElementString("HighlightTargetMove", HighlightTargetMove.ToString()); writer.WriteElementString("HighlightValidMoves", HighlightValidMoves.ToString()); writer.WriteElementString("HighlightLastMovePlayed", HighlightLastMovePlayed.ToString()); writer.WriteElementString("BlockInvalidMoves", BlockInvalidMoves.ToString()); writer.WriteElementString("RequireMoveConfirmation", RequireMoveConfirmation.ToString()); writer.WriteElementString("AddPieceNumbers", AddPieceNumbers.ToString()); writer.WriteElementString("StackPiecesInHand", StackPiecesInHand.ToString()); writer.WriteElementString("PlaySoundEffects", PlaySoundEffects.ToString()); writer.WriteElementString("ShowBoardHistory", ShowBoardHistory.ToString()); writer.WriteElementString("ShowMoveCommentary", ShowMoveCommentary.ToString()); writer.WriteElementString("FirstRun", FirstRun.ToString()); writer.WriteElementString("CheckUpdateOnStart", CheckUpdateOnStart.ToString()); InternalGameEngineConfig?.SaveGameAIConfig(writer, "InternalGameAI", ConfigSaveType.BasicOptions); writer.WriteEndElement(); } }
/// <summary> /// Create a HexMap of type SolidColorBrush and set the value to a different colored /// brush for each ring in the map /// </summary> /// <param name="orientation">Flat or pointy topped</param> /// <param name="ringCount">Number of rings around the center hex</param> private static HexMap<SolidColorBrush> CreateHexMapWithRingColors(HexOrientation orientation, int ringCount) { // Set up some colors for hex fills var ringColors = new[] { new SolidColorBrush(Colors.Red), new SolidColorBrush(Colors.Yellow), new SolidColorBrush(Colors.Blue), new SolidColorBrush(Colors.Orange), new SolidColorBrush(Colors.Green) }; var hexGrid = new HexMap<SolidColorBrush>(orientation, ringCount, 45); // Set the value of each item to a solid color brush which varies per ring for (int i = 0; i <= Math.Min(ringCount, ringColors.Length - 1); i++) foreach (var hex in hexGrid.Ring(i)) hex.Value = ringColors[i]; return hexGrid; }
public override void Init(Transform root, HexGridShape shape, int lines, int columns, float radius, HexOrientation orientation) { base.Init(root, shape, lines, columns, radius, orientation); initialized = true; BattleGridEntity entity = ObjectPool.GetInstance <BattleGridEntity>(); entity.id = 1; entity.heroid = 1; entity.campflag = 1; entity.type = 1; entity.grid = BattleGrid.Hex; BattleHexTile tile = TileAt(0, 0); entity.position = tile.position; BattleManager.Instance.AddEntity(entity); entity.active = true; }
public static void CreateMap(EntityManager entityManager) { HexOrientation orientation = Defines.orientation; Vector3 pos = new Vector3(0, -1, 0); int mapSize = 10; float hexRadius = Defines.TileRadius; for (int q = -mapSize; q <= mapSize; q++) { int r1 = Mathf.Max(-mapSize, -q - mapSize); int r2 = Mathf.Min(mapSize, -q + mapSize); for (int r = r1; r <= r2; r++) { var entity = entityManager.CreateEntity(); // Place the instantiated entity in a grid with some noise pos.x = hexRadius * 3.0f / 2.0f * q; pos.z = hexRadius * Mathf.Sqrt(3.0f) * (r + q / 2.0f); entityManager.AddComponentData(entity, new LocalToWorld { }); entityManager.AddComponentData(entity, new Translation { Value = pos }); entityManager.AddComponentData(entity, new Rotation { Value = Quaternion.identity }); var index = new CubeIndex(q, r, -q - r); entityManager.AddComponentData(entity, new HexTileComponent { index = index }); } } }
private void CalculateContentPresenterTransforms(HexOrientation orientation, int verticeIndex, out double angle, out double translateX, out double translateY) { if (Orientation == HexOrientation.FlatTopped) { switch (verticeIndex) { case 0: translateX = -0.125 * VertexRadius; translateY = -0.22 * VertexRadius; angle = -60d; break; case 1: translateX = 0; translateY = 0; angle = 0d; break; case 2: translateX = 0.125 * VertexRadius; translateY = -0.22 * VertexRadius; angle = 60d; break; case 3: translateX = 0.125 * VertexRadius; translateY = 0.22 * VertexRadius; angle = 120; break; case 4: translateX = 0; translateY = 0; angle = 180d; break; case 5: default: translateX = -0.125 * VertexRadius; translateY = 0.22 * VertexRadius; angle = -120d; break; } } else { switch (verticeIndex) { case 0: translateX = -0.32 * VertexRadius; translateY = -0.18 * VertexRadius; angle = -30d; break; case 1: translateX = 0.18 * VertexRadius; translateY = -0.18 * VertexRadius; angle = 30d; break; case 2: translateX = 0; translateY = 0; angle = 90; break; case 3: translateX = 0.18 * VertexRadius; translateY = 0.18 * VertexRadius; angle = 150d; break; case 4: translateX = -0.32 * VertexRadius; translateY = 0.18 * VertexRadius; angle = -150d; break; case 5: default: translateX = -0.13 * VertexRadius; translateY = 0; angle = -90; break; } } }
/// <param name="width">Board width</param> /// <param name="height">Board height</param> /// <param name="side">Hexagon side length</param> /// <param name="orientation">Orientation of the hexagons</param> /// <param name="xOffset">X coordinate offset</param> /// <param name="yOffset">Y coordinate offset</param> public HexagonalMap(int width, int height, int side, HexOrientation orientation, int xOffset, int yOffset) { Initialize(width, height, side, orientation, xOffset, yOffset); InitHexPos(); }
/// <param name="width">Board width</param> /// <param name="height">Board height</param> /// <param name="side">Hexagon side length</param> /// <param name="orientation">Orientation of the hexagons</param> public HexagonalMap(int width, int height, int side, HexOrientation orientation) { Initialize(width, height, side, orientation, 0, 0); InitHexPos(); }
public static Position FromCursor(double cursorX, double cursorY, double hexRadius, HexOrientation hexOrientation) { if (hexRadius < 0) { throw new ArgumentOutOfRangeException("hexRadius"); } else if (double.IsInfinity(cursorX) || double.IsInfinity(cursorY) || hexRadius == 0) // No hexes on board { return(Position.Origin); } // Convert cursor to axial double q = hexOrientation == HexOrientation.FlatTop ? (cursorX * (2.0 / 3.0)) / hexRadius : ((-cursorY / 3.0) + (Math.Sqrt(3.0) / 3.0) * cursorX) / hexRadius; double r = hexOrientation == HexOrientation.FlatTop ? ((-cursorX / 3.0) + (Math.Sqrt(3.0) / 3.0) * cursorY) / hexRadius : (cursorY * (2.0 / 3.0)) / hexRadius; // Convert axial to cube double x = q; double z = r; double y = -x - z; // Round cube double rx = Math.Round(x); double ry = Math.Round(y); double rz = Math.Round(z); double xdiff = Math.Abs(rx - x); double ydiff = Math.Abs(ry - y); double zdiff = Math.Abs(rz - z); if (xdiff > ydiff && xdiff > zdiff) { rx = -ry - rz; } else if (ydiff > zdiff) { ry = -rx - rz; } else { rz = -rx - ry; } return(new Position((int)rx, (int)ry, (int)rz, 0)); }
public Hex(PointF point, float side, float apotema, HexOrientation orientation) { Initialize(point.X, point.Y, side, apotema, orientation); }
public Hex(int x, int y, float side, float apotema, HexOrientation orientation) { Initialize((float)(x), (float)(y), side, apotema, orientation); }
public static Vector3 Corner(Vector3 origin, float radius, int corner, HexOrientation orientation) { float angle = 60 * corner; if(orientation == HexOrientation.Pointy) angle += 30; angle *= Mathf.PI / 180; return new Vector3(origin.x + radius * Mathf.Cos(angle), 0.0f, origin.z + radius * Mathf.Sin(angle)); }
public Vector3 GetDirection (HexDirection dir, HexOrientation mode) { Vector3 vec = Vector3.zero; if (mode == HexOrientation.PointySides) { if (dir == HexDirection.N || dir == HexDirection.S) { vec = height * locUnits[idxS[1]]; } else if (dir == HexDirection.NE || dir == HexDirection.SW){ vec = 1.5f * radius * locUnits[idxS[0]] + 0.5f * height * locUnits[idxS[1]]; } else if (dir == HexDirection.E || dir == HexDirection.W) { vec = 1.5f * radius * locUnits[idxS[0]]; } else if (dir == HexDirection.SE || dir == HexDirection.NW) { vec = 1.5f * radius * locUnits [idxS[0]] - 0.5f * height * locUnits [idxS[1]]; } } else{ if (dir == HexDirection.N || dir == HexDirection.S) { vec = 1.5f * radius * locUnits[idxS[1]]; } else if (dir == HexDirection.NE || dir == HexDirection.SW){ vec = 0.5f * height * locUnits[idxS[0]] + 1.5f * radius * locUnits[idxS[1]]; } else if (dir == HexDirection.E || dir == HexDirection.W) { vec = height * locUnits[idxS[0]]; } else if (dir == HexDirection.SE || dir == HexDirection.NW) { vec = 0.5f * height * locUnits [idxS[0]] - 1.5f * radius * locUnits [idxS[1]]; } } if (dir == HexDirection.S || dir == HexDirection.SW || dir == HexDirection.W || dir == HexDirection.NW) vec *= -1.0f; return vec; }
public static void GetHexMesh(float radius, HexOrientation orientation, ref Mesh mesh) { mesh = new Mesh(); List<Vector3> verts = new List<Vector3>(); List<int> tris = new List<int>(); List<Vector2> uvs = new List<Vector2>(); for (int i = 0; i < 6; i++) verts.Add(Corner(Vector3.zero, radius, i, orientation)); tris.Add(0); tris.Add(2); tris.Add(1); tris.Add(0); tris.Add(5); tris.Add(2); tris.Add(2); tris.Add(5); tris.Add(3); tris.Add(3); tris.Add(5); tris.Add(4); //UVs are wrong, I need to find an equation for calucalting them uvs.Add(new Vector2(0.5f, 1f)); uvs.Add(new Vector2(1, 0.75f)); uvs.Add(new Vector2(1, 0.25f)); uvs.Add(new Vector2(0.5f, 0)); uvs.Add(new Vector2(0, 0.25f)); uvs.Add(new Vector2(0, 0.75f)); mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.uv = uvs.ToArray(); mesh.name = "Hexagonal Plane"; mesh.RecalculateNormals(); }
private void drawPointsCalculateCircle(Vector3[][][] points, int[] amount, Vector3 from, Vector3 to) { // NOTE: The computations work for flat sides the same as for pointy // sides, except every direction vector is rotated 30 degrees clockwise // (330 degrees counter-clockwise) ///<summary>The local origin transformed to world space.</summary> Vector3 origin; int maxDepth, minDepth; int iterator_x = 0, iterator_y = 0, iterator_z = 0; ///<summary>Current hex.</summary> Vector3 cHex; ///<summary>Vectors from hex to vertices (world space).</summary> Vector3[] verts; ///<summary>Vectors from origin to radial hexes (world space).</summary> Vector3[] radials; ///<summary>Vectors from one layer to the next (world space).</summary> Vector3 forward = depth * locUnits[idxS[2]]; ///<summary>Maps cardinal direction to direction origin hex to hex.</summary> Func<int, Vector3> cardinalToHex; ///<summary>Maps cardinal direction to direction hex to vertex.</summary> Func<int, Vector3> cardinalToVert; ///<summary>Contributes a hex line.</summary> Func<int, Vector3, int, int, int> contribute; /// <summary>Contributes a layer line.</summary> Action<Vector3, int, int> contributeL; ///<summary>Contribute connecting line of hex at angle.</summary> Action<Vector3, int> connecting; ///<summary>Contribute bottom line of hex at angle.</summary> Action<Vector3, int> bottom; ///<summary>Contribute both side lines of hex at angle.</summary> Action<Vector3, int> sides; ///<summary>Contribute closing line of hex at angle.</summary> Action<Vector3, int> closing; ///<summary>Contribute inner line of hex at angle.</summary> Action<Vector3, int> inner; origin = lwMatrix.MultiplyPoint(Vector3.zero); maxDepth = Mathf.FloorToInt(to[idxS[2]]); minDepth = Mathf.CeilToInt(from[idxS[2]]); cardinalToHex = (d) => { Vector3 result = Vector3.zero; switch (d) { case 0: result[idx[0]] = 1f; result[idx[1]] = 0f; break; case 1: result[idx[0]] = 0f; result[idx[1]] = 1f; break; case 2: result[idx[0]] = -1f; result[idx[1]] = 0f; break; case 3: result[idx[0]] = -1f; result[idx[1]] = -1f; break; case 4: result[idx[0]] = 0f; result[idx[1]] = -1f; break; case 5: result[idx[0]] = 1f; result[idx[1]] = -1f; break; } // The conversion has to be applied in pointy side mode if (hexSideMode == HexOrientation.FlatSides) { _hexSideMode = HexOrientation.PointySides; result = HerringUToWorld(result) - origin; _hexSideMode = HexOrientation.FlatSides; return result; } return HerringUToWorld(result) - origin; }; cardinalToVert = (d) => { Vector3 result = Vector3.zero; switch (d) { case 0 : result[idx[0]] = 2f/3f; result[idx[1]] = -1f/3f; break; case 1 : result[idx[0]] = 1f/3f; result[idx[1]] = 1f/3f; break; case 2 : result[idx[0]] = -1f/3f; result[idx[1]] = 1f/3f; break; case 3 : result[idx[0]] = -2f/3f; result[idx[1]] = -1f/3f; break; case 4 : result[idx[0]] = -1f/3f; result[idx[1]] = -2f/3f; break; case 5 : result[idx[0]] = 1f/3f; result[idx[1]] = -2f/3f; break; } // The conversion has to be applied in pointy side mode if (hexSideMode == HexOrientation.FlatSides) { _hexSideMode = HexOrientation.PointySides; result = HerringUToWorld(result) - origin; _hexSideMode = HexOrientation.FlatSides; return result; } return HerringUToWorld(result) - origin; }; verts = new Vector3[] { cardinalToVert(0), // [-] 2_____1 cardinalToVert(1), // [/] / \ cardinalToVert(2), // [\] / \ cardinalToVert(3), // [-] 3 # 0 cardinalToVert(4), // [/] \ / cardinalToVert(5), // [\] \_____/ // 4 5 }; radials = new Vector3[] { cardinalToHex(0), // [/] _____ cardinalToHex(1), // [|] / 1 \ cardinalToHex(2), // [\] 2 0 cardinalToHex(3), // [/] ( # ) cardinalToHex(4), // [|] 3 5 cardinalToHex(5), // [\] \__4__/ }; // The directions from a radial hex to an adjacent inner // hex are the same, except shifted by 2 indices. // If the sides are flat rotate every direction 330 degrees if (hexSideMode == HexOrientation.FlatSides) { Vector3 around = (gridPlane == GridPlane.XY ? 1 : -1) * locUnits[idx[2]]; Matrix4x4 mat = Matrix4x4.TRS(Vector3.zero, Quaternion.AngleAxis(330f, around), Vector3.one); for (int i = 0; i < 6; ++i) { verts[i] = mat.MultiplyVector(verts[i]); radials[i] = mat.MultiplyVector(radials[i]); } } contribute = (lineSet, hex, i, iterator) => { points[idxS[lineSet]][iterator][0] = hex + verts[(i + 0) % 6]; points[idxS[lineSet]][iterator][1] = hex + verts[(i + 1) % 6]; return ++iterator; }; contributeL = (hex, a, indx) => { points[idxS[2]][iterator_z][0] = hex + verts[(indx+a)%6] + from[idxS[2]] * forward; points[idxS[2]][iterator_z][1] = hex + verts[(indx+a)%6] + to[idxS[2]] * forward; ++iterator_z; }; sides = (hex, a) => { a %= 6; int ix1 = (a == 1 || a == 4) ? 0 : 1; int ix2 = (a == 0 || a == 3) ? 0 : 1; if (ix1 == 0) { iterator_x = contribute(ix1, hex, a + 0, iterator_x); } else { iterator_y = contribute(ix1, hex, a + 0, iterator_y); } if (ix2 == 0) { iterator_x = contribute(ix2, hex, a + 1, iterator_x); } else { iterator_y = contribute(ix2, hex, a + 1, iterator_y); } }; closing = (hex, a) => { a %= 6; int ix = (a == 2 || a == 5) ? 0 : 1; if (ix == 0) { iterator_x = contribute(ix, hex, a + 2, iterator_x); } else { iterator_y = contribute(ix, hex, a + 2, iterator_y); } }; inner = (hex, a) => { a %= 6; int ix = (a == 1 || a == 4) ? 0 : 1; if (ix == 0) { iterator_x = contribute(ix, hex, a + 3, iterator_x); } else { iterator_y = contribute(ix, hex, a + 3, iterator_y); } }; connecting = (hex, a) => { a %= 6; int ix = (a == 0 || a == 3) ? 0 : 1; if (ix == 0) { iterator_x = contribute(ix, hex, a + 4, iterator_x); } else { iterator_y = contribute(ix, hex, a + 4, iterator_y); } }; bottom = (hex, a) => { a %= 6; int ix = (a == 2 || a == 5) ? 0 : 1; if (ix == 0) { iterator_x = contribute(ix, hex, a + 5, iterator_x); } else { iterator_y = contribute(ix, hex, a + 5, iterator_y); } }; // Now move the origin over to the renderAround origin = GridToWorld(new Vector3(renderAround[0], renderAround[1], renderAround[2])); cHex = origin + minDepth * forward; int[] radius = {Mathf.RoundToInt(from[idx[0]]), Mathf.RoundToInt(to[idx[0]])}; // inner and outer radius int[] angle = {Mathf.RoundToInt(from[idx[1]]), Mathf.RoundToInt(to[idx[1]])}; // start and end angle if (!useCustomRenderRange) { radius[0] = 0; angle[ 0] = 0; angle[ 1] = Mathf.Min(angle[1], 6); } // It makes no sense for the radius to be negative radius[0] = Mathf.Max(0, radius[0]); radius[1] = Mathf.Max(0, radius[1]); if (angle[0] < 0 ) { angle[0] = 6 + (angle[0] % 6); if (angle[0] > angle[1]) {angle[1] += 6;} } if (radius[0] == 0) { for (int i = 0; i < 6; ++i) {contributeL(origin, 0, i);} for (int i = minDepth; i <= maxDepth; ++i) { iterator_y = contribute(1, cHex, 0, iterator_y); iterator_x = contribute(0, cHex, 1, iterator_x); iterator_y = contribute(1, cHex, 2, iterator_y); iterator_y = contribute(1, cHex, 3, iterator_y); iterator_x = contribute(0, cHex, 4, iterator_x); iterator_y = contribute(1, cHex, 5, iterator_y); cHex += forward; } // if the radius is from 0 to 0 we are done here if (radius[1] == 0) { /*Debug.Log( "Delta X:" + (amount[idxS[0]]-iterator_x) + "Delta Y:" + (amount[idxS[1]]-iterator_y) + "Delta Z:" + (amount[idxS[2]]-iterator_z) );*/ return; } // otherwise we move on to the first actual ring ++radius[0]; } else { // for every radial hex add one line, for inner hexes add two lines for (int i = angle[0]; i < angle[1]; ++i) { cHex = origin + radius[0] * radials[i%6]; // one inner line for the radial hex, opposite of side 1 cHex += minDepth * forward; for (int j = 0; j < radius[0]; ++j) { // two inner lines for the inner hex for (int k = minDepth; k <= maxDepth; ++k) { // every hex gets an inner line // every inner hex a connecting line if (j != 0) {connecting(cHex, i);} inner(cHex, i); cHex += forward; } cHex -= (maxDepth+1) * forward; // back to the origin layer if (j != 0) {contributeL(cHex, i, 5);} contributeL(cHex, i, 4); cHex += minDepth * forward; // back forward cHex += radials[(i+2)%6]; } } // add the last radial hex if ((angle[1] - angle[0]) % 6 != 0 || angle[1] == angle[0]) { cHex = origin + radius[0] * radials[angle[1]%6]; cHex += minDepth * forward; for (int j = minDepth; j <= maxDepth; ++j) { inner(cHex, angle[1]); cHex += forward; } cHex -= (maxDepth+1) * forward; contributeL(cHex, angle[1], 3); contributeL(cHex, angle[1], 4); } } // Now start the actual loop... for (int i = radius[0]; i <= radius[1]; ++i) { for (int j = angle[0]; j < angle[1]; ++j) { // connection, bottom and two sides cHex = origin + i * radials[j%6]; // the connection is opposite of the 2nd side // now the inner hexes cHex += minDepth * forward; for (int k = 0; k < i; ++k) { for (int l = minDepth; l <= maxDepth; ++l) { if (k == 0) {connecting(cHex, j);} bottom(cHex, j); sides( cHex, j); cHex += forward; } // now the inner hexes cHex -= (maxDepth+1) * forward; // back to origin layer if (k == 0) {contributeL(cHex, j, 5);} contributeL(cHex, j, 0); contributeL(cHex, j, 1); cHex += minDepth * forward; // back forward cHex += radials[(j+2)%6]; } } // The last radial hex, unless the cone is a circle if ((angle[1] - angle[0]) % 6 != 0 || angle[1] == angle[0]) { cHex = origin + i * radials[angle[1]%6]; cHex += minDepth * forward; for (int j = minDepth; j <= maxDepth; ++j) { connecting(cHex, angle[1]); bottom( cHex, angle[1]); sides( cHex, angle[1]); // If we don't do this a line will be drawn twice if ((angle[1] - angle[0]) % 6 != 5 || i > 1) { closing(cHex, angle[1]); } cHex += forward; } cHex -= (maxDepth+1) * forward; // back to origin layer contributeL(cHex, angle[1], 0); contributeL(cHex, angle[1], 1); contributeL(cHex, angle[1], 2); contributeL(cHex, angle[1], 5); } } /*Debug.Log( "Delta X:" + (amount[idxS[0]]-iterator_x) + "Delta Y:" + (amount[idxS[1]]-iterator_y) + "Delta Z:" + (amount[idxS[2]]-iterator_z) );*/ }
/// <param name="width">Board width</param> /// <param name="height">Board height</param> /// <param name="side">Hexagon side length</param> /// <param name="orientation">Orientation of the hexagons</param> public Board(int width, int height, int side, HexOrientation orientation) { Initialize(width, height, side, orientation, 0, 0); }
/// <param name="side">length of one side of the hexagon</param> public Hex(int x, int y, int side, HexOrientation orientation) { Initialize(Math.ConvertToFloat(x), Math.ConvertToFloat(y), Math.ConvertToFloat(side), orientation); }
private Shape GetHex(Point center, double size, HexType hexType, HexOrientation hexOrientation) { if (null == center) { throw new ArgumentNullException("center"); } if (size <= 0) { throw new ArgumentOutOfRangeException("size"); } double strokeThickness = size / 10; Path hex = new Path { StrokeThickness = strokeThickness }; switch (hexType) { case HexType.WhitePiece: hex.Fill = WhiteBrush; hex.Stroke = BlackBrush; break; case HexType.BlackPiece: hex.Fill = BlackBrush; hex.Stroke = BlackBrush; break; case HexType.ValidMove: hex.Fill = SelectedMoveBodyBrush; hex.Stroke = SelectedMoveBodyBrush; break; case HexType.SelectedPiece: hex.Stroke = SelectedMoveEdgeBrush; break; case HexType.SelectedMove: hex.Fill = SelectedMoveBodyBrush; hex.Stroke = SelectedMoveEdgeBrush; break; case HexType.LastMove: hex.Stroke = LastMoveEdgeBrush; break; } PathGeometry data = new PathGeometry(); PathFigure figure = new PathFigure(); figure.IsClosed = true; double hexRadius = size - 0.75 * strokeThickness; for (int i = 0; i <= 6; i++) { double angle_deg = 60.0 * i + (hexOrientation == HexOrientation.PointyTop ? 30.0 : 0); double angle_rad1 = Math.PI / 180 * (angle_deg - 3); double angle_rad2 = Math.PI / 180 * (angle_deg + 3); Point p1 = new Point(center.X + hexRadius * Math.Cos(angle_rad1), center.Y + hexRadius * Math.Sin(angle_rad1)); Point p2 = new Point(center.X + hexRadius * Math.Cos(angle_rad2), center.Y + hexRadius * Math.Sin(angle_rad2)); if (i == 0) { figure.StartPoint = p2; } else { figure.Segments.Add(new LineSegment(p1, true)); figure.Segments.Add(new ArcSegment() { Point = p2, IsStroked = true, IsSmoothJoin = true, SweepDirection = SweepDirection.Counterclockwise }); } } data.Figures.Add(figure); hex.Data = data; return(hex); }
public Hex(float x, float y, float side, float apotema, HexOrientation orientation) { Initialize(x, y, side, apotema, orientation); }
/// <summary> /// Sets internal fields and creates board /// </summary> /// <param name="width">Board width</param> /// <param name="height">Board height</param> /// <param name="side">Hexagon side length</param> /// <param name="orientation">Orientation of the hexagons</param> /// <param name="xOffset">X coordinate offset</param> /// <param name="yOffset">Y coordinate offset</param> private void Initialize(int width, int height, int side, HexOrientation orientation, int xOffset, int yOffset) { this.width = width; this.height = height; this.xOffset = xOffset; this.yOffset = yOffset; this.side = side; this.orientation = orientation; hexes = new Hex[height, width]; //opposite of what we'd expect boardState = new BoardState(); var h = Math.CalculateH(side); // short side var r = Math.CalculateR(side); // long side // // Calculate pixel info..remove? // because of staggering, need to add an extra r/h float hexWidth = 0; float hexHeight = 0; switch (orientation) { case HexOrientation.Flat: hexWidth = side + h; hexHeight = r + r; pixelWidth = (width*hexWidth) + h; pixelHeight = (height*hexHeight) + r; break; case HexOrientation.Pointy: hexWidth = r + r; hexHeight = side + h; pixelWidth = (width*hexWidth) + r; pixelHeight = (height*hexHeight) + h; break; default: break; } var inTopRow = false; var inBottomRow = false; var inLeftColumn = false; var inRightColumn = false; var isTopLeft = false; var isTopRight = false; var isBotomLeft = false; var isBottomRight = false; // i = y coordinate (rows), j = x coordinate (columns) of the hex tiles 2D plane for (var i = 0; i < height; i++) { for (var j = 0; j < width; j++) { // Set position booleans #region Position Booleans if (i == 0) { inTopRow = true; } else { inTopRow = false; } if (i == height - 1) { inBottomRow = true; } else { inBottomRow = false; } if (j == 0) { inLeftColumn = true; } else { inLeftColumn = false; } if (j == width - 1) { inRightColumn = true; } else { inRightColumn = false; } if (inTopRow && inLeftColumn) { isTopLeft = true; } else { isTopLeft = false; } if (inTopRow && inRightColumn) { isTopRight = true; } else { isTopRight = false; } if (inBottomRow && inLeftColumn) { isBotomLeft = true; } else { isBotomLeft = false; } if (inBottomRow && inRightColumn) { isBottomRight = true; } else { isBottomRight = false; } #endregion // // Calculate Hex positions // if (isTopLeft) { //First hex switch (orientation) { case HexOrientation.Flat: hexes[0, 0] = new Hex(0 + h + xOffset, 0 + yOffset, side, orientation); break; case HexOrientation.Pointy: hexes[0, 0] = new Hex(0 + r + xOffset, 0 + yOffset, side, orientation); break; default: break; } } else { switch (orientation) { case HexOrientation.Flat: if (inLeftColumn) { // Calculate from hex above hexes[i, j] = new Hex(hexes[i - 1, j].Points[(int) FlatVertice.BottomLeft], side, orientation); } else { // Calculate from Hex to the left and need to stagger the columns if (j%2 == 0) { // Calculate from Hex to left's Upper Right Vertice plus h and R offset var x = hexes[i, j - 1].Points[(int) FlatVertice.UpperRight].X; var y = hexes[i, j - 1].Points[(int) FlatVertice.UpperRight].Y; x += h; y -= r; hexes[i, j] = new Hex(x, y, side, orientation); } else { // Calculate from Hex to left's Middle Right Vertice hexes[i, j] = new Hex(hexes[i, j - 1].Points[(int) FlatVertice.MiddleRight], side, orientation); } } break; case HexOrientation.Pointy: if (inLeftColumn) { // Calculate from hex above and need to stagger the rows if (i%2 == 0) { hexes[i, j] = new Hex(hexes[i - 1, j].Points[(int) PointyVertice.BottomLeft], side, orientation); } else { hexes[i, j] = new Hex(hexes[i - 1, j].Points[(int) PointyVertice.BottomRight], side, orientation); } } else { // Calculate from Hex to the left var x = hexes[i, j - 1].Points[(int) PointyVertice.UpperRight].X; var y = hexes[i, j - 1].Points[(int) PointyVertice.UpperRight].Y; x += r; y -= h; hexes[i, j] = new Hex(x, y, side, orientation); } break; default: break; } } } } }
/// <summary> /// Sets internal fields and calls CalculateVertices() /// </summary> private void Initialize(float x, float y, float side, HexOrientation orientation) { this.x = x; this.y = y; this.side = side; Orientation = orientation; hexState = new HexState(); CalculateVertices(); }
/// <param name="width">Board width</param> /// <param name="height">Board height</param> /// <param name="side">Hexagon side length</param> /// <param name="orientation">Orientation of the hexagons</param> /// <param name="xOffset">X coordinate offset</param> /// <param name="yOffset">Y coordinate offset</param> public Board(int width, int height, int side, HexOrientation orientation, int xOffset, int yOffset) { Initialize(width, height, side, orientation, xOffset, yOffset); }
private void Initialize(int width, int height, int side, Hexagonal.HexOrientation orientation, int xOffset, int yOffset, Color boardColor) { this.width = width; this.height = height; this.xOffset = xOffset; this.yOffset = yOffset; this.side = side; this.orientation = orientation; hexes = new Hex[height, width]; //opposite of what we'd expect this.boardState = new BoardState(); this.boardColor = boardColor; float h = Hexagonal.HexMath.CalculateH(side); // short side float r = Hexagonal.HexMath.CalculateR(side); // long side // // Calculate pixel info..remove? // because of staggering, need to add an extra r/h float hexWidth = 0; float hexHeight = 0; switch (orientation) { case HexOrientation.Flat: hexWidth = side + h; hexHeight = r + r; this.pixelWidth = (width * hexWidth) + h; this.pixelHeight = (height * hexHeight) + r; break; case HexOrientation.Pointy: hexWidth = r + r; hexHeight = side + h; this.pixelWidth = (width * hexWidth) + r; this.pixelHeight = (height * hexHeight) + h; break; default: break; } bool inTopRow = false; bool inBottomRow = false; bool inLeftColumn = false; bool inRightColumn = false; bool isTopLeft = false; bool isTopRight = false; bool isBotomLeft = false; bool isBottomRight = false; // i = y coordinate (rows), j = x coordinate (columns) of the hex tiles 2D plane for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // Set position booleans if (i == 0) { inTopRow = true; } else { inTopRow = false; } if (i == height - 1) { inBottomRow = true; } else { inBottomRow = false; } if (j == 0) { inLeftColumn = true; } else { inLeftColumn = false; } if (j == width - 1) { inRightColumn = true; } else { inRightColumn = false; } if (inTopRow && inLeftColumn) { isTopLeft = true; } else { isTopLeft = false; } if (inTopRow && inRightColumn) { isTopRight = true; } else { isTopRight = false; } if (inBottomRow && inLeftColumn) { isBotomLeft = true; } else { isBotomLeft = false; } if (inBottomRow && inRightColumn) { isBottomRight = true; } else { isBottomRight = false; } // // Calculate Hex positions // if (isTopLeft) { //First hex switch (orientation) { case HexOrientation.Flat: hexes[0, 0] = new Hex(0 + h + xOffset, 0 + yOffset, 0, 0, side, orientation, boardColor); break; case HexOrientation.Pointy: hexes[0, 0] = new Hex(0 + r + xOffset, 0 + yOffset, 0, 0, side, orientation, boardColor); break; default: break; } } else { switch (orientation) { case HexOrientation.Flat: if (inLeftColumn) { // Calculate from hex above hexes[i, j] = new Hex(hexes[i - 1, j].Points[(int)Hexagonal.FlatVertice.BottomLeft], i, j, side, orientation, boardColor); } else { // Calculate from Hex to the left and need to stagger the columns if (j % 2 == 0) { // Calculate from Hex to left's Upper Right Vertice plus h and R offset float x = hexes[i, j - 1].Points[(int)Hexagonal.FlatVertice.UpperRight].X; float y = hexes[i, j - 1].Points[(int)Hexagonal.FlatVertice.UpperRight].Y; x += h; y -= r; hexes[i, j] = new Hex(x, y, i, j, side, orientation, boardColor); } else { // Calculate from Hex to left's Middle Right Vertice hexes[i, j] = new Hex(hexes[i, j - 1].Points[(int)Hexagonal.FlatVertice.MiddleRight], i, j, side, orientation, boardColor); } } break; case HexOrientation.Pointy: if (inLeftColumn) { // Calculate from hex above and need to stagger the rows if (i % 2 == 0) { hexes[i, j] = new Hex(hexes[i - 1, j].Points[(int)Hexagonal.PointyVertice.BottomLeft], i, j, side, orientation, boardColor); } else { hexes[i, j] = new Hex(hexes[i - 1, j].Points[(int)Hexagonal.PointyVertice.BottomRight], i, j, side, orientation, boardColor); } } else { // Calculate from Hex to the left float x = hexes[i, j - 1].Points[(int)Hexagonal.PointyVertice.UpperRight].X; float y = hexes[i, j - 1].Points[(int)Hexagonal.PointyVertice.UpperRight].Y; x += r; y -= h; hexes[i, j] = new Hex(x, y, i, j, side, orientation, boardColor); } break; default: break; } } } } }