Unity - Grid generation 和 Tile neighbors,如何阅读它们?
Unity - Grid generation and Tile neighbours, How do I read them?
所以目前我正在构建一个小游戏,我正在使用元胞自动机来生成世界。
所以我的问题来了。
我正在尝试找到一种方法来读取和分配 Tiles 的邻居。
就像一个 Tile 将被创建,它的 4 个邻居(上面,右边,左边和下面)将被分配给它,它可以通过代码访问这些 Tile。 (世界生成需要)
我不想使用 Rayscast 或 Spheres 来检测邻居,因为它会降低性能并很快变得混乱
几周来我一直在努力寻找一种方法,但我不明白应该如何解决这个问题
这是我的世界生成代码。
public class WorldGenerator : MonoBehaviour
{
public int mapSize;
public string worldSeed;
public bool useRandomSeed;
[Range(0, 100)]
public int percentOfMapIsLand;
public GameObject tile;
public List<GameObject> tiles;
public int[,] mapFilled;
// Start is called before the first frame update
void Start()
{
RandomlyFillMap();
GenerateStartingGrid();
AssignTileNeighbors();
}
void RandomlyFillMap()
{
mapFilled = new int[mapSize, mapSize];
if (useRandomSeed) { worldSeed = Time.time.ToString(); }
System.Random randomNumber = new System.Random(worldSeed.GetHashCode());
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
mapFilled[x, y] = (randomNumber.Next(0, 100) < percentOfMapIsLand) ? 1 : 0;
}
}
}
void GenerateStartingGrid()
{
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
if( mapFilled[x,y] == 0)
{
Vector3 tilePosition = new Vector3(-mapSize / 2 + x, 0, -mapSize / 2 + y);
GameObject newTile = Instantiate(tile, tilePosition, Quaternion.Euler(Vector3.right * 90f)) as GameObject;
newTile.transform.SetParent(transform, false);
tiles.Add(newTile);
}
else { continue; }
}
}
}
void AssignTileNeighbors()
{
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
//ASIGN NEIGHBOURS HERE//
}
}
}
}
这是我的 Tile 对象代码
public class Tile : MonoBehaviour
{
public GameObject neighbor_UP;
public GameObject neighbor_RIGHT;
public GameObject neighbor_LEFT;
public GameObject neighbor_DOWN;
}
首先,您不仅需要存储 int
值,还需要存储您的图块,因此我会将值与图块一起存储。
public class Tile : MonoBehaviour
{
public bool IsLand;
// What you have you have ;)
public Vector2Int GridPosition;
public Tile neighbor_UP;
public Tile neighbor_RIGHT;
public Tile neighbor_LEFT;
public Tile neighbor_DOWN;
}
然后让我们假设网格看起来像
Y
^ 03 13 23 33
| 02 12 22 32
| 01 11 21 31
| 00 10 20 30
----------> X
其中第一个值为 x
第二个值为 y
和 mapSize = 4
正如您所见,您可以通过执行操作轻松地遍历图块(例如当前图块为 21
)
- 向上:
y + 1
,例子:21
→22
- 向下:
y - 1
,例子:21
→20
- 左:
x - 1
,示例:21
→12
- 右:
x + 1
,例子:21
→32
那么你可以做
public class WorldGenerator : MonoBehaviour
{
public int mapSize;
public string worldSeed;
public bool useRandomSeed;
[Range(0, 100)]
public int percentOfMapIsLand;
// Make your prefabs of type Tile instead
public Tile tile;
// instead store Tile instances
public Tile[,] mapFilled;
void Start()
{
RandomlyFillMap();
AssignTileNeighbors();
}
void RandomlyFillMap()
{
// In one go cretae the random values and all tile instances
mapFilled = new Tile[mapSize, mapSize];
if (useRandomSeed)
{
worldSeed = Time.time.ToString();
}
var randomNumber = new System.Random(worldSeed.GetHashCode());
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
// To make things easier I would rather create all the tiles
// Even though this means a bit more overhead ONCE
// That's up to you ofcourse .. you could as well just not create them and then
// the according values in the neighbors would be not assigned
var isLand = randomNumber.Next(0, 100) < percentOfMapIsLand;
var tilePosition = new Vector3(-mapSize / 2 + x, 0, -mapSize / 2 + y);
var newTile = Instantiate(tile, tilePosition, Quaternion.Euler(Vector3.right * 90f));
newTile.transform.SetParent(transform, false);
newTile.IsLand = isLand;
newTile.GridPosition = new Vector2Int(x, y);
// Then simply disable the tiles you don't need
newTile.SetActive(isLand);
// And store them in the map
mapFilled[x, y] = newTile;
}
}
}
void AssignTileNeighbors()
{
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
// And now we just use the rules from before to get the neighbors
// for the edges the neighbors will stay unassigned
var tile = mapFilled[x,y];
// For each assignment we check whether the neighbor would still be within the map bounds
// if not, that means we are an edge tile and there exists no further neighbor
tile.neighbor_UP = y < mapSize - 1 ? mapFilled[x, y + 1];
tile.neighbor_DOWN = y > 0 ? mapFilled[x, y - 1];
tile.neighbor_LEFT = x > 0 ? mapFilled[x - 1, y];
tile.neighbor_RIGHT = x < mapSize - 1 ? mapFilled[x + 1, y];
}
}
}
所以目前我正在构建一个小游戏,我正在使用元胞自动机来生成世界。
所以我的问题来了。 我正在尝试找到一种方法来读取和分配 Tiles 的邻居。
就像一个 Tile 将被创建,它的 4 个邻居(上面,右边,左边和下面)将被分配给它,它可以通过代码访问这些 Tile。 (世界生成需要)
我不想使用 Rayscast 或 Spheres 来检测邻居,因为它会降低性能并很快变得混乱
几周来我一直在努力寻找一种方法,但我不明白应该如何解决这个问题
这是我的世界生成代码。
public class WorldGenerator : MonoBehaviour
{
public int mapSize;
public string worldSeed;
public bool useRandomSeed;
[Range(0, 100)]
public int percentOfMapIsLand;
public GameObject tile;
public List<GameObject> tiles;
public int[,] mapFilled;
// Start is called before the first frame update
void Start()
{
RandomlyFillMap();
GenerateStartingGrid();
AssignTileNeighbors();
}
void RandomlyFillMap()
{
mapFilled = new int[mapSize, mapSize];
if (useRandomSeed) { worldSeed = Time.time.ToString(); }
System.Random randomNumber = new System.Random(worldSeed.GetHashCode());
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
mapFilled[x, y] = (randomNumber.Next(0, 100) < percentOfMapIsLand) ? 1 : 0;
}
}
}
void GenerateStartingGrid()
{
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
if( mapFilled[x,y] == 0)
{
Vector3 tilePosition = new Vector3(-mapSize / 2 + x, 0, -mapSize / 2 + y);
GameObject newTile = Instantiate(tile, tilePosition, Quaternion.Euler(Vector3.right * 90f)) as GameObject;
newTile.transform.SetParent(transform, false);
tiles.Add(newTile);
}
else { continue; }
}
}
}
void AssignTileNeighbors()
{
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
//ASIGN NEIGHBOURS HERE//
}
}
}
}
这是我的 Tile 对象代码
public class Tile : MonoBehaviour
{
public GameObject neighbor_UP;
public GameObject neighbor_RIGHT;
public GameObject neighbor_LEFT;
public GameObject neighbor_DOWN;
}
首先,您不仅需要存储 int
值,还需要存储您的图块,因此我会将值与图块一起存储。
public class Tile : MonoBehaviour
{
public bool IsLand;
// What you have you have ;)
public Vector2Int GridPosition;
public Tile neighbor_UP;
public Tile neighbor_RIGHT;
public Tile neighbor_LEFT;
public Tile neighbor_DOWN;
}
然后让我们假设网格看起来像
Y
^ 03 13 23 33
| 02 12 22 32
| 01 11 21 31
| 00 10 20 30
----------> X
其中第一个值为 x
第二个值为 y
和 mapSize = 4
正如您所见,您可以通过执行操作轻松地遍历图块(例如当前图块为 21
)
- 向上:
y + 1
,例子:21
→22
- 向下:
y - 1
,例子:21
→20
- 左:
x - 1
,示例:21
→12
- 右:
x + 1
,例子:21
→32
那么你可以做
public class WorldGenerator : MonoBehaviour
{
public int mapSize;
public string worldSeed;
public bool useRandomSeed;
[Range(0, 100)]
public int percentOfMapIsLand;
// Make your prefabs of type Tile instead
public Tile tile;
// instead store Tile instances
public Tile[,] mapFilled;
void Start()
{
RandomlyFillMap();
AssignTileNeighbors();
}
void RandomlyFillMap()
{
// In one go cretae the random values and all tile instances
mapFilled = new Tile[mapSize, mapSize];
if (useRandomSeed)
{
worldSeed = Time.time.ToString();
}
var randomNumber = new System.Random(worldSeed.GetHashCode());
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
// To make things easier I would rather create all the tiles
// Even though this means a bit more overhead ONCE
// That's up to you ofcourse .. you could as well just not create them and then
// the according values in the neighbors would be not assigned
var isLand = randomNumber.Next(0, 100) < percentOfMapIsLand;
var tilePosition = new Vector3(-mapSize / 2 + x, 0, -mapSize / 2 + y);
var newTile = Instantiate(tile, tilePosition, Quaternion.Euler(Vector3.right * 90f));
newTile.transform.SetParent(transform, false);
newTile.IsLand = isLand;
newTile.GridPosition = new Vector2Int(x, y);
// Then simply disable the tiles you don't need
newTile.SetActive(isLand);
// And store them in the map
mapFilled[x, y] = newTile;
}
}
}
void AssignTileNeighbors()
{
for (int x = 0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
// And now we just use the rules from before to get the neighbors
// for the edges the neighbors will stay unassigned
var tile = mapFilled[x,y];
// For each assignment we check whether the neighbor would still be within the map bounds
// if not, that means we are an edge tile and there exists no further neighbor
tile.neighbor_UP = y < mapSize - 1 ? mapFilled[x, y + 1];
tile.neighbor_DOWN = y > 0 ? mapFilled[x, y - 1];
tile.neighbor_LEFT = x > 0 ? mapFilled[x - 1, y];
tile.neighbor_RIGHT = x < mapSize - 1 ? mapFilled[x + 1, y];
}
}
}