проблемВертикальная Hex сетка: Получить й кольцо плитки окружающей специфично координаты
То, что я пытаюсь сделать, это получить число х колец из заданной точки, и хранить эти кольца в List<List<HexCoordinate>>
, где внутренний list - список всех гексов в этом кольце, а HexCoordinate - это структура, определенная ниже
В идеале, я хотел бы иметь возможность указать координату, и сколько звонков мне хотелось бы найти и получить алгоритм захвата плитки для меня.
Изображения и попытки
У меня есть вертикальная (Flat Top) Hex сетка, которая выглядит следующим образом
В коде, каждая плитка представлена простой структурой HexCoordinate GitHub
public struct HexCoordinate : IEquatable<HexCoordinate>
{
public int X { get; private set; }
public int Y { get; private set; }
public HexCoordinate(int x, int y)
{
X = x;
Y = y;
}
public HexCoordinate North() => this + new HexCoordinate(0, -1);
public HexCoordinate South() => this + new HexCoordinate(0, 1);
public HexCoordinate West() => this + new HexCoordinate(-1, 0);
public HexCoordinate East() => this + new HexCoordinate(1, 0);
public HexCoordinate NorthWest() => this + new HexCoordinate(-1, -1);
public HexCoordinate NorthEast() => this + new HexCoordinate(1, -1);
public HexCoordinate SouthWest() => this + new HexCoordinate(-1, 1);
public HexCoordinate SouthEast() => this + new HexCoordinate(1, 1);
public bool Equals(HexCoordinate other)
{
return X == other.X &&
Y == other.Y;
}
public static HexCoordinate operator +(HexCoordinate one, HexCoordinate two)
{
return new HexCoordinate(one.X + two.X, one.Y + two.Y);
}
}
Для моего примера, в частности, у меня есть изображение, которое я сделал, чтобы попытаться понять эту проблему самостоятельно
То, что я Пытался
И потому, что мне нужно, чтобы показать, что я уже пробовал, это то, что я пытался до сих пор
public const int MAX_RINGS = 3;
public List<List<HexCoordinate> GetsRingsWithinHex(HexCoordinate coordinate, int maxRings = MAX_RINGS)
{
// Attempt One Pseudocode
// reference: http://gamedev.stackexchange.com/questions/51264/get-ring-of-tiles-in-hexagon-grid
// int ring = 1
// Travel around the ring by traversing N,SE,S,SW,NW,N,NE multiplied by the ring number
// ring++
// Travel Around ring again
// cont until desired ring...
var hexRings = new List<List<HexCoordinate>>();
// Add in the current hex to the list
var currentHex = new List<HexCoordinate>();
currentHex.add(coordinate);
hexRings.Add(currentHex);
// Now go through and add the other rings
while (hexRings.Count <= maxRings)
{
var ring = new List<HexCoordinate>();
HexCoordinate tempCoordinate = coordinate;
int currentRingNumber = hexRings.Count;
// We start off by going north to the correct ring, and then adding it to our list
for (int i = 0; i < currentRingNumber; i++)
{
tempCoordinate = tempCoordinate.North();
}
ring.add(tempCoordinate);
// After that, we proceed to go clockwise around the ring until we come back to the start
for (int i = 0; i < currentRingNumber; i++)
{
tempCoordinate = tempCoordinate.SouthEast();
// If the ring is an odd number, you need to re-align the coordinates back to where whey should be
if (IntExtensions.IsOdd(i)) tempCoordinate = tempCoordinate.North();
ring.add(tempCoordinate);
}
// The rightmost segment is east because we can go straight down the required number of times
for (int i = 0; i < currentRingNumber; i++)
{
tempCoordinate = tempCoordinate.South();
ring.add(tempCoordinate);
}
// We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1
for (int i = 0; i < currentRingNumber - 1; i++)
{
tempCoordinate = tempCoordinate.SouthWest();
ring.add(tempCoordinate);
}
// Coming into this statement, we are now at the bottom 3 coordinates.
// Since our grid is laid out vertically, we can assume that these three hexes will be directly west of eachother
// So we only have to go west twice to make our way to the next north segment
for (int i = 0; i < 2; i++)
{
tempCoordinate = tempCoordinate.West();
ring.add(tempCoordinate);
}
// We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1
for (int i = 0; i < currentRingNumber - 1; i++)
{
tempCoordinate = tempCoordinate.NorthWest();
ring.add(tempCoordinate);
}
// The left most segment is easy because we can just go straight up
for (int i = 0; i < currentRingNumber; i++)
{
tempCoordinate = tempCoordinate.North();
ring.add(tempCoordinate);
}
// We utilize Current Ring - 1 because we only want this to run on rings that are greater than 1
for (int i = 0; i < currentRingNumber - 1; i++)
{
tempCoordinate = tempCoordinate.NorthEast();
// If the ring is an even number, you need to re-align the coordinates back to where whey should be
if (IntExtensions.IsEven(i)) tempCoordinate = tempCoordinate.South();
ring.add(tempCoordinate);
}
// Finally, we add the ring to our system rings and loop until we no longer fit the criteria
hexRings.Add(ring);
}
return hexRings;
}
И в случае, если это необходимо, вот мои IntExtensions
public static class IntExtensions
{
public static bool IsBetween(this int num, int low, int high)
{
return num >= low && num <= high;
}
public static bool IsOdd(this int value)
{
return value % 2 != 0;
}
public static bool IsEven(this int value)
{
return value % 2 == 0;
}
}
Моя текущая проблема заключается в том, что этот алгоритм работает для t он 1-го и 2-го колец, но как только он доберется до третьего кольца (и, предположительно, дальше, если я запустил его за 3), координаты внизу и углы начнут смещаться на 1 ... как видно из вывода в моем консоль ниже (с тем, что он должен быть отредактирован вручную вручную)
Ring 0 - System 5, 5
Ring 1 - System 5, 4
Ring 1 - System 6, 5
Ring 1 - System 6, 6
Ring 1 - System 5, 6
Ring 1 - System 4, 6
Ring 1 - System 4, 5
Ring 2 - System 5, 3
Ring 2 - System 6, 4
Ring 2 - System 7, 4
Ring 2 - System 7, 5
Ring 2 - System 7, 6
Ring 2 - System 6, 7
Ring 2 - System 5, 7
Ring 2 - System 4, 7
Ring 2 - System 3, 6
Ring 2 - System 3, 5
Ring 2 - System 3, 4
Ring 2 - System 4, 4
Ring 3 - System 5, 2
Ring 3 - System 6, 3
Ring 3 - System 7, 3
Ring 3 - System 8, 4
Ring 3 - System 8, 5
Ring 3 - System 8, 6
Ring 3 - System 8, 7
Ring 3 - System 7, 8 //(Should be 7, 7)
Ring 3 - System 6, 9 //(Should be 6, 8)
Ring 3 - System 5, 9 //(Should be 5, 8)
Ring 3 - System 4, 9 //(Should be 4, 8)
Ring 3 - System 3, 8 //(Should be 3, 7)
Ring 3 - System 2, 7
Ring 3 - System 2, 6
Ring 3 - System 2, 5
Ring 3 - System 2, 4
Ring 3 - System 3, 4 //(Should be 3, 3)
Ring 3 - System 4, 3
ли кто-нибудь сможет помочь поставить меня в правильном направлении, или предоставить мне алгоритм, который позволил бы мне получить кольцо проклятий? Я лично застрял в этой проблеме около полутора лет, и я, похоже, не могу понять этого.
Первое, что приходит мне на ум: Почему бы не использовать другую схему нумерации для сетки? Двойное разрешение. Шести в первом столбце начинаются с 0 с шагом 2, шестнадцатеричные столбцы второго столбца начинаются с 1 с шагом 2. Следовательно, ваши гексы расположены на обычной квадратной сетке с двойным разрешением. Затем вы можете использовать алгоритм круга Брешенхэм, чтобы быстро решить, пересечен ли шестнадцатеричный круг с кругом радиуса 2 *. – BitTickler
My F # port of Wikipedia bresenham C обычно не выглядит хорошо :) Но из моих текущих исследований я склонен думать, что описанный выше подход в принципе возможен. Здесь ваше ожидаемое ring3 приводит к моему «двойному разрешению». Вместо этого не отображали шестиугольники, кроме кругов;) http://imgur.com/kZtWw8S – BitTickler
вам необходимо учесть ** LSB ** координаты 'x' и' y' и соответствующим образом скорректировать позицию.Вместо этого вам не нужны круги, кроме шестиугольников, поэтому Bresenham непригодным для использования. Вместо этого вы ищете все гексы с расстоянием 1,2,3,4 ... ячейки от источника, поэтому «A *» было бы лучше. Посмотрите на [Улучшение производительности обнаружения щелчка на изометрической сетке с шахматным столбцом] (http://stackoverflow.com/a/35917976/2521214), особенно 'cell2scr' и' scr2cell', что я подразумеваю под LSB 'x, y' (это квадратная сетка, но проблема одна и та же). btw nice sketch – Spektre