- Unity 2018 Artificial Intelligence Cookbook(Second Edition)
- Jorge Palacios
- 220字
- 2021-07-16 18:11:34
There's more...
We'll learn ways to implement the LoadMap function by using the .map file format as an example:
- Define the function and create a StreamReader object for reading the file:
private void LoadMap(string filename) { string path = Application.dataPath + "/" + mapsDir + "/" + filename; try { StreamReader strmRdr = new StreamReader(path); using (strmRdr) { // next steps in here } } catch (Exception e) { Debug.LogException(e); } }
- Declare and initialize the necessary variables:
int j = 0; int i = 0; int id = 0; string line; Vector3 position = Vector3.zero; Vector3 scale = Vector3.zero;
- Read the header of the file containing its height and width:
line = strmRdr.ReadLine();// non-important line line = strmRdr.ReadLine();// height numRows = int.Parse(line.Split(' ')[1]); line = strmRdr.ReadLine();// width numCols = int.Parse(line.Split(' ')[1]); line = strmRdr.ReadLine();// "map" line in file
- Initialize the member variables, allocating memory at the same time:
vertices = new List<Vertex>(numRows * numCols); neighbours = new List<List<Vertex>>(numRows * numCols); costs = new List<List<float>>(numRows * numCols); vertexObjs = new GameObject[numRows * numCols]; mapVertices = new bool[numRows, numCols];
- Declare the for loop for iterating over the characters in the following lines:
for (i = 0; i < numRows; i++) { line = strmRdr.ReadLine(); for (j = 0; j < numCols; j++) { // next steps in here } }
- Assign true or false to the logical representation depending on the character read:
bool isGround = true; if (line[j] != '.') isGround = false; mapVertices[i, j] = isGround;
- Instantiate the proper prefab:
position.x = j * cellSize; position.z = i * cellSize; id = GridToId(j, i); if (isGround) vertexObjs[id] = Instantiate(vertexPrefab, position, Quaternion.identity) as GameObject; else vertexObjs[id] = Instantiate(obstaclePrefab, position, Quaternion.identity) as GameObject;
- Assign the new game object as a child of the graph and clean up its name:
vertexObjs[id].name = vertexObjs[id].name.Replace("(Clone)", id.ToString()); Vertex v = vertexObjs[id].AddComponent<Vertex>(); v.id = id; vertices.Add(v); neighbours.Add(new List<Vertex>()); costs.Add(new List<float>()); float y = vertexObjs[id].transform.localScale.y; scale = new Vector3(cellSize, y, cellSize); vertexObjs[id].transform.localScale = scale; vertexObjs[id].transform.parent = gameObject.transform;
- Create a pair of nested loops right after the previous loop, for setting up the neighbors for each vertex:
for (i = 0; i < numRows; i++) { for (j = 0; j < numCols; j++) { SetNeighbours(j, i); } }
- Define the SetNeighbours function, called in the previous step:
protected void SetNeighbours(int x, int y, bool get8 = false) { int col = x; int row = y; int i, j; int vertexId = GridToId(x, y); neighbours[vertexId] = new List<Vertex>();
costs[vertexId] = new List<float>(); Vector2[] pos = new Vector2[0]; // next steps }
- Compute the proper values when we need a vicinity of eight (top, bottom, right, left, and corners):
if (get8) { pos = new Vector2[8]; int c = 0; for (i = row - 1; i <= row + 1; i++) { for (j = col -1; j <= col; j++) { pos[c] = new Vector2(j, i); c++; } } }
- Set up everything for a vicinity of four (no corners):
else { pos = new Vector2[4]; pos[0] = new Vector2(col, row - 1); pos[1] = new Vector2(col - 1, row); pos[2] = new Vector2(col + 1, row); pos[3] = new Vector2(col, row + 1); }
- Add the neighbors to the lists. It's the same procedure as for the type of vicinity:
foreach (Vector2 p in pos) { i = (int)p.y; j = (int)p.x; if (i < 0 || j < 0) continue; if (i >= numRows || j >= numCols) continue; if (i == row && j == col) continue; if (!mapVertices[i, j]) continue;
int id = GridToId(j, i); neighbours[vertexId].Add(vertices[id]); costs[vertexId].Add(defaultCost); }