Reference material
Unity3D Artificial Intelligence Programming
A-star routing algorithm
A star routing algorithm is a relatively simple routing algorithm. Let's make a small Demo and learn how it works. The level is limited. Please give us more advice. Thank you.
As shown in the following figure, consider the map as a plane composed of two-dimensional small squares. Set a starting point A and a target point Z. A and Z occupy a small square respectively.
In order to obtain the route from point A to point B, the operation process of star A routing algorithm is as follows:
Step 1. Put the starting point A into an array OpenList of storage path points, and arrange the elements of the array in ascending order according to the amount of movement needed to reach the end point from the location of the element.
At this point, only A is the element in OpenList.
Step 2. Extract the element with the least amount of movement from OpenList. The first one is starting point A. Then, traverse eight points around it to find out if there is point B with the least amount of movement to the end point.
In row i, the subscripts of eight squares around the grid of column j are:
There are four exceptions
1.i-1 < 0 indicates that no calculation of 7, 8, 9 is required.
2.j-1 < 0 indicates that 7,4,1 need not be calculated.
3.i+1 > Total number of rows indicates no need to calculate 1, 2, 3
4.j + 1 > Total column number indicates that 9, 6, 3 need not be calculated
Suppose we find point B and add it to OpenList, and then sort OpenList, where the elements in OpenList are: B, A.
…
Assuming that step 2 continues three times, each time the next path point is found, the elements in OpenList are:
E, D, C, B, A 5 points.
Now proceed to step 2. When we execute step 5, we traverse the eight points around E and find that none of them are movable, indicating that E is a dead path. Then we need to exclude E from the list of path points and add E to the list of dead paths CloseList. This point will not be within the scope of our search for paths.
At this point, the elements in OpenList are: D, C, B, A.
The elements in CloseList are: E 1 point.
Step 2 goes on for the sixth time and traverses the seven points around D (point E excluded), finds the second smallest point F besides E, and then adds it to OpenList.
Now the elements in OpenList are: F, D, C, B, A5 points.
The element in CloseList has E 1 point.
Loop through step 2 until the point taken from OpenList is the end point, the path search is completed and the appropriate path is found.
Demo structure
Now we will demonstrate the A-star routing algorithm in the form of demo. First, we create a cube lattice prefabrication to represent a grid on the map, and add text showing F,G, H values and lattice index on it.
Then we create several color materials, and use color to distinguish the grid more intuitively:
Blue Corresponding Starting Point
Pink corresponding endpoint
Yellow corresponds to possible path points
Green Corresponds to the Final Path Point
I used four classes to implement this Demo: AStar Manager, AStar Control, Cube Entity, Cube Component.
Cube Component inherits MonoBehaviour and belongs to the lattice prefabrication. Its function is to respond to clicks and change materials.
public void PickCube(GameObject inGameObj)
{
AStarManager2.Instance.PickCube(this);
}
public void ChangeMaterial(int innClick)
{
if (1 == innClick)
{
mTrsfmCube.renderer.material = mMaterialBlue;
}
else if (2 == innClick)
{
mTrsfmCube.renderer.material = mMaterialPurple;
}
}
The CubeEntity class is used to control the lattice prefabrication and the CubeComponent component. It contains the function of calculating and displaying its F,G,H values.
public void CalculateFGH(CubeEntity inCubeParent, CubeEntity inEndCubEntity)
{
if(null == inCubeParent)
{
mfGValue = 0;
mLabelGValue.text = "G: " + mfGValue;
}else
{
/*
mnGValue = inCubeParent.mnGValue;
mnGValue += (int)Vector3.Distance(
inCubeParent.CubeCpnt.transform.position
, this.CubeCpnt.transform.position
);
*/
mfGValue = inCubeParent.mfGValue;
mfGValue += Vector3.Distance(
inCubeParent.CubeCpnt.transform.position
, this.CubeCpnt.transform.position
);
mLabelGValue.text = "G: " + mfGValue.ToString("f1");
}
mfHValue = Vector3.Distance(
inEndCubEntity.CubeCpnt.transform.position
, this.CubeCpnt.transform.position
);
mLabelHValue.text = "H: " + mfHValue.ToString("f1");
mfFValue = mfGValue + mfHValue;
mLabelFValue.text = "F: " + mfFValue.ToString("f1");
}
AStarControl is a class of management operations, responsible for controlling the movement of the lens and responding to mouse operations, drawing the mouse drag box.
void OnPostRender()
{
if (null == mMaterial)
{
Debug.Log("OnPostRender: mMaterial is null!!!");
return;
}
if (!mbStartRender)
{
return;
}
//GL.Clear(true, true, Color.white);
GL.PushMatrix();
//Applied material
mMaterial.SetPass(0);
//Setting the transformation matrix needed for rendering
//Matching our Matrix
//GL.MultMatrix(this.transform.localToWorldMatrix);
//Auxiliary functions are used to make an orthogonal projection transformation
//When this function is called, the conical area of the field of view follows(0,0,-1) to (1,1,100). This function is used to plot2D Graphical.
GL.LoadOrtho();
//Draw lines
GL.Begin(GL.LINES);
//Setting vertex color
GL.Color(Color.red);
this.DoDrawLine(
mFirstMousePositionVEC3.x,
mFirstMousePositionVEC3.y,
mSecondMousePositionVEC3.x,
mSecondMousePositionVEC3.y
);
GL.End();
//Drawing triangles
GL.Begin(GL.TRIANGLES);
GL.Color(new Color(0, 255, 0, 0.6f));
this.DoDrawTriangle(
mFirstMousePositionVEC3.x,
mFirstMousePositionVEC3.y,
mSecondMousePositionVEC3.x,
mSecondMousePositionVEC3.y
);
GL.End();
GL.PopMatrix();
}
AStar Manager is used to control the whole demo process. At first, it will create a map of 20*20 grids, and use the co-process to create the effect of making grids one by one.
public IEnumerator LoadAllCube(Object inCubeResObj, Transform inTrsfmParent)
{
yield return null;
//Each frame loads a Cube.
for (int i = 0; i < mnRow; ++i)
{
for (int j = 0; j < mnColumn; ++j)
{
//Horizontal creation
Vector3 cubeAddPos = new Vector3(
mStartPointVEC3.x + (j+1) * mnCellSize
, mStartPointVEC3.y - (i+1) * mnCellSize
, 0.0f
);
/*
//Vertical creation
Vector3 cubeAddPos = new Vector3(
mStartPointVEC3.x + (i+1) * mnCellSize
, mStartPointVEC3.y - (j+1) * mnCellSize
, 0.0f
);
*/
//For ease of calculation, the number of rows is calculated from 1.
CubeEntity tempCubeEntity = new CubeEntity(
inCubeResObj
, inTrsfmParent
, mStartPointVEC3
, cubeAddPos
, i
, j
, (i) * mnColumn + (j +1)
);
tempCubeEntity.Init();
mlistAllCubeEntity.Add(tempCubeEntity);
mCubeEntityAry[i, j] = tempCubeEntity;
yield return null;
//Interrupt for 1 second
//yield return new WaitForSeconds(1);
}
}
mbLoadComplete = true;
}
Then it monitors in the update function and starts to find the path when there is a starting point and an ending point. When the map changes, it starts to find the path again.
void Update()
{
//Once the starting point and the end point are not empty and the path-finding is not started, then the path-finding cooperation begins.
if (!mbStartAStar && null != mStartCube && null != mEndCube && !mbPathfindingComplete)
{
mbStartAStar = true;
//Add the starting point to the open list and sort it
mlistOpen.Add(mStartCube);
mlistOpen.Sort();
mStartCube.CalculateFGH(null, mEndCube);
mStartCube.CubeCpnt.ShowCubeData();
//StartCoroutine(this.StartAStarPathFinding() );
StartCoroutine("StartAStarPathfinding");
Debug.Log("Update : start Pathfinding");
}
//If any of the starting, ending and obstacle nodes is changed in the path finding process,
//So end the journey and start again.
if (mbStartAStar && mbRestartPathFinding)
{
StopCoroutine("StartAStarPathfinding");
//Except for the starting and ending points, all other paths are reset.
for (int i = 0; i < mlistOpen.Count; ++i)
{
if (mlistOpen[i].IndexPRO == mStartCube.IndexPRO)
{
continue;
}
if (mlistOpen[i].IndexPRO == mEndCube.IndexPRO)
{
continue;
}
mlistOpen[i].ResetState();
}
for (int i = 0; i < mlistClose.Count; ++i)
{
if (mlistClose[i].IndexPRO == mStartCube.IndexPRO)
{
continue;
}
if (mlistClose[i].IndexPRO == mEndCube.IndexPRO)
{
continue;
}
mlistClose[i].ResetState();
}
mlistOpen.Clear();
mlistTempCubeEntity.Clear();
mlistClose.Clear();
mbStartAStar = true;
//Add the starting point to the open list and sort it
mlistOpen.Add(mStartCube);
//Empty the parent node, it is possible that the previous sorting is not the starting point, and has the parent node
mStartCube.CubeParent = null;
mlistOpen.Sort();
mStartCube.CalculateFGH(null, mEndCube);
mStartCube.CubeCpnt.ShowCubeData();
StartCoroutine("StartAStarPathfinding");
mbRestartPathFinding = false;
}
}
Below is the video I put on Station b.
Video demo