프로그래밍
Hexagon
by violetoz
2013. 5. 14.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
namespace HexDemo
{
class Hex
{
private float radius;
private float width;
private float halfWidth;
private float height;
private float rowHeight;
public Hex(float radius)
{
this.radius = radius;
this.height = 2 * radius;
this.rowHeight = 1.5f * radius;
this.halfWidth = (float)Math.Sqrt((radius * radius) - ((radius / 2) * (radius / 2)));
this.width = 2 * this.halfWidth;
}
public Vector2 TileOrigin(Vector2 tileCoordinate)
{
return new Vector2(
(tileCoordinate.X * width) + ((tileCoordinate.Y % 2 == 1) ? halfWidth : 0), //Y % 2 == 1 is asking 'Is Y odd?'
tileCoordinate.Y * rowHeight);
}
public Vector2 TileCenter(Vector2 tileCoordinate)
{
return TileOrigin(tileCoordinate) + new Vector2(halfWidth, halfWidth);
}
public enum Direction
{
NorthEast,
East,
SouthEast,
SouthWest,
West,
NorthWest,
NumberOfDirections,
}
public static Direction RotateDirection(Direction direction, int amount)
{
//Let's make sure our directions stay within the enumerated values.
if (direction < Direction.NorthEast || direction > Direction.NorthWest || Math.Abs(amount) > (int)Direction.NorthWest)
throw new InvalidOperationException("Directions out of range.");
direction += amount;
//Now we need to make sure direction stays within the proper range.
//C# does not allow modulus operations on enums, so we have to convert to and from int.
int n_dir = (int)direction % (int)Direction.NumberOfDirections;
if (n_dir < 0) n_dir = (int)Direction.NumberOfDirections + n_dir;
direction = (Direction)n_dir;
return direction;
}
public static Direction Opposite(Direction direction) { return RotateDirection(direction, 3); }
public static Vector2 Neighbor(Vector2 tile, Direction direction)
{
if (tile.Y % 2 == 0) //Is this row even?
{
switch (direction)
{
case Direction.NorthEast: tile.Y += 1; break;
case Direction.East: tile.X += 1; break;
case Direction.SouthEast: tile.Y -= 1; break;
case Direction.SouthWest: tile.Y -= 1; tile.X -= 1; break;
case Direction.West: tile.X -= 1; break;
case Direction.NorthWest: tile.X -= 1; tile.Y += 1; break;
default: throw new InvalidOperationException("Invalid direction");
}
}
else //This is an odd row.
{
switch (direction)
{
case Direction.NorthEast: tile.X += 1; tile.Y += 1; break;
case Direction.East: tile.X += 1; break;
case Direction.SouthEast: tile.X += 1; tile.Y -= 1; break;
case Direction.SouthWest: tile.Y -= 1; ; break;
case Direction.West: tile.X -= 1; break;
case Direction.NorthWest: tile.Y += 1; break;
default: throw new InvalidOperationException("Invalid direction");
}
}
return tile;
}
public Vector2 TileAt(Vector2 worldCoordinate)
{
float rise = height - rowHeight;
float slope = rise / halfWidth;
int X = (int)Math.Floor(worldCoordinate.X / width);
int Y = (int)Math.Floor(worldCoordinate.Y / rowHeight);
Vector2 offset = new Vector2(worldCoordinate.X - X * width, worldCoordinate.Y - Y * rowHeight);
if (Y % 2 == 0) //Is this an even row?
{
//Section type A
if (offset.Y < (-slope * offset.X + rise)) //Point is below left line; inside SouthWest neighbor.
{
X -= 1;
Y -= 1;
}
else if (offset.Y < (slope * offset.X - rise)) //Point is below right line; inside SouthEast neighbor.
Y -= 1;
}
else
{
//Section type B
if (offset.X >= halfWidth) //Is the point on the right side?
{
if (offset.Y < (-slope * offset.X + rise * 2.0f)) //Point is below bottom line; inside SouthWest neighbor.
Y -= 1;
}
else //Point is on the left side
{
if (offset.Y < (slope * offset.X)) //Point is below the bottom line; inside SouthWest neighbor.
Y -= 1;
else //Point is above the bottom line; inside West neighbor.
X -= 1;
}
}
return new Vector2(X, Y);
}
}
}