Процедурная генерация карты - определите соседние тайлы
Первоначально я использовал 2d Array "Tile" для хранения процедурно сгенерированной карты с ее различным содержимым.
Каждая плитка содержит смежный список, который позволяет каждой отдельной плитке узнать, какие вершины находятся ближе всего к ней, касаясь ее с 8 разных сторон (прямой и соседний по диагонали).
Общая идея была взята из генерации полигональных карт Амит, но я попытался упростить ее, используя сетку вместо воронуа, однако я столкнулся с большим количеством неприятностей, чем первоначально предполагалось. Мое текущее затруднительное положение заключается в том, чтобы выяснить смежность, когда я пересмотрел 2d Arrays.
Вот как я делал это, прежде чем перейти к списку:
private void ConstructAdjacencyList() {
// Create Adjacency List
for (int x = 0; x < mapWidth; x++) {
for (int y = 0; y < mapHeight; y++) {
// Bool to find position of point
bool omitLeft = false; bool omitRight = false;
bool omitTop = false; bool omitBottom = false;
// Enable bools based on position, reset on each loop
if (x == 0)
omitLeft = true;
else if (x == mapWidth - 1)
omitRight = true;
if (y == 0)
omitTop = true;
else if (y == mapHeight - 1)
omitBottom = true;
// Add entries to list based on bool settings
if (!omitLeft) {
// Left center
islandMap[x,y].adjacent.Add(islandMap[x-1,y]);
if (!omitTop)
islandMap[x,y].adjacent.Add(islandMap[x-1,y-1]);
if (!omitBottom)
islandMap[x,y].adjacent.Add(islandMap[x-1,y+1]);
}
if (!omitTop) // Top Center
islandMap[x,y].adjacent.Add(islandMap[x,y-1]);
if (!omitBottom) // Bottom Center
islandMap[x,y].adjacent.Add(islandMap[x,y+1]);
if (!omitRight) {
// Right Center
islandMap[x,y].adjacent.Add(islandMap[x+1,y]);
if (!omitTop)
islandMap[x,y].adjacent.Add(islandMap[x+1,y-1]);
if (!omitBottom)
islandMap[x,y].adjacent.Add(islandMap[x+1,y+1]);
}
}
} // End Adjacency
Debug.Log ("Adjacencies Built");
}
Значения x, y теперь хранятся в islandMap.point (Vector 2d, в котором хранятся значения x и y, сгенерированные следующим образом:)
public MapController() {
width = height = (int)Mathf.Sqrt (tileCount);
// Lists for points
var points = new List<Vector2>();
// Build a random set of points.
for (float x = 0; x < width; x++) {
for (float y = 0; y < height; y++) {
points.Add(new Vector2(x,y));
}
}
map = new Map (points, width, height, lakeTreshold);
}
И сама карта в настоящее время имеет следующее:
public class Map {
Func<Vector2, bool> inside; // Contains function to randomly seed area
bool needsMoreRandomness;
public List<Tile> islandMap; // Previously was Tile[,] islandMap
public int mapWidth { get; private set; } // Calculated as Sqrt(totalPoints)
public int mapHeight { get; private set; }
Наряду с другими методами, такими как метод ConstructAdjacencyList(), на котором я сейчас остановился.
Итак, как я могу продолжить создание списка смежности окружающих точек, не полагаясь на позиционирование массива? Могу ли я временно ссылаться на весь список из массива, размещать ссылки на каждую плитку во всем списке в этом 2-мерном массиве, устанавливать смежности, а затем удалять массив без потери информации? Я полагаю, что он будет использовать только ссылки, так что все должно быть в порядке... Каждая плитка содержит индекс для хранения порядка, в котором она была построена следующим образом:
foreach (var point in points) {
var p = new Tile { index = islandMap.Count, point = point };
p.border = point.x == 0 || point.x == mapWidth || point.y == 0 || point.y == mapHeight;
islandMap.Add (p);
tileLookup[point] = p;
}
Извините, если это слишком долго... Я только что понял, что это довольно массивно...
2 ответа
Предполагая, что вы ничего не сделали, чтобы изменить порядок точек, вы можете рассматривать одномерный список / массив как 2D список / массив. Пример, на который я ссылаюсь, написан на C, но язык идей не зависит.
При этом, предполагая, что вы будете делать это только один раз во время инициализации и учитывая относительно небольшое количество точек, вы можете так же легко перебрать его с помощью функции, которая перебирает список точек и выбирает соседей как необходимо. Мой C# немного ржавый, но я говорю о чем-то вроде этого:
private List<Vector2> getAdjacenctPointList(List<Vector2> pointsList, Vector2 point){
var adjacencyList = new List<Vector2>();
foreach (var pt in pointList){
var offset = Math.abs(pt.x - point.x) + Math.abs(pt.y - point.y);
if(offset > 0 && offset <= 1.0){
adjacencyList.add(pt);
}
}
return adjacencyList;
}
Окончательный ответ, который я получил, - это наименьший объем работы, который позволил мне переработать мой исходный код 2d-массива, опубликованный выше, - просто создать временный 2d-массив и сохранить в нем все ссылки - при необходимости создать все смежные области и затем избавьтесь (просто потеряв прицел) от 2-го массива.
Вот фактический метод с системой 2d массивов. Первые пара утверждений, за которыми следовал вложенный цикл for, - вот все, что нужно:
private void ConstructAdjacencyList() {
Tile[,] tempArray = new Tile[mapWidth, mapHeight];
int count = 0;
// Populate the temp 2D array with list references
for (int x = 0; x < mapWidth; x++) {
for (int y = 0; y < mapHeight; y++) {
tempArray[x,y] = islandMap[count];
count++;
}
}
// Create Adjacency List using our TempArray
for (int x = 0; x < mapWidth; x++) {
for (int y = 0; y < mapHeight; y++) {
// Bool to find position of point
bool omitLeft = false; bool omitRight = false;
bool omitTop = false; bool omitBottom = false;
// Enable bools based on position, reset on each loop
if (x == 0)
omitLeft = true;
else if (x == mapWidth - 1) // Optimize with if else to split checks in half.
omitRight = true;
if (y == 0)
omitTop = true;
else if (y == mapHeight - 1)
omitBottom = true;
// Add entries to list based on bool settings
if (!omitLeft) {
// Left center
tempArray[x,y].adjacent.Add(tempArray[x-1,y]);
if (!omitTop)
tempArray[x,y].adjacent.Add(tempArray[x-1,y-1]);
if (!omitBottom)
tempArray[x,y].adjacent.Add(tempArray[x-1,y+1]);
}
if (!omitTop) // Top Center
tempArray[x,y].adjacent.Add(tempArray[x,y-1]);
if (!omitBottom) // Bottom Center
tempArray[x,y].adjacent.Add(tempArray[x,y+1]);
if (!omitRight) {
// Right Center
tempArray[x,y].adjacent.Add(tempArray[x+1,y]);
if (!omitTop)
tempArray[x,y].adjacent.Add(tempArray[x+1,y-1]);
if (!omitBottom)
tempArray[x,y].adjacent.Add(tempArray[x+1,y+1]);
}
}
} // End Adjacency
Debug.Log ("Adjacencies Built");
}
Чтобы убедиться, что все получилось так, как я хотел, я проверил его визуально, установив один случайный куб, и проверил различные точки по всей области, чтобы убедиться, что ошибок не было и не было.
Конечный результат, как и ожидалось, изображен ниже:
Спасибо за помощь:)