At the end of the previous section, we provide an example of path finding. In most cases, the operation is still good, but there is a small problem, such:
Obviously, the obstacle has blocked the road, but the ball still ran out through the diagonal line!
Where is the problem? Let's first review the if statement used for judgment in astar..
// Skip if (test = node |! Test. resumable) {continue ;}
In this judgment, there is no rule that the object line is not allowed. Let's see how to fix it:
When we examine the four-week nodes in a node-centered manner, if both the horizontal and vertical directions are obstacles, even if the diagonal nodes are common nodes that can be crossed, they cannot pass. Therefore, you only need to add two conditions for judgment.
// If it is the current node, or it cannot pass, and the horizontal and vertical directions are excluded as the exception of the obstacle node, if (test = node |! Test. retriable |! _ Grid. getnode (node. X, test. Y). retriable |! _ Grid. getnode (test. X, node. Y). resumable) {continue ;}
Run the following command:
Everything is normal!
In the preceding examples, the destination and target points are fixed, but in actual games, the opposite is true. For example, if you select a farmer, click on the map, farmers can automatically find the path to the target point.
Package {import flash. display. sprite; import flash. display. stagealign; import flash. display. stagescalemode; import flash. events. event; import flash. events. mouseevent; [SWF (width = 600, Height = 600)] public class game extends sprite {private VaR _ cellsize: Int = 20; private VaR _ grid: grid; private VaR _ PLAYER: SPRITE; private VaR _ index: int; private VaR _ path: array; Public Function game () {stage. align = stagealign. top_left; Stage. scalemode = stagescalemode. no_scale; makeplayer (); makegrid (); stage. addeventlistener (mouseevent. click, ongridclick);}/** generate a player role (for simplicity, it is a circle) */private function makeplayer (): void {_ player = new sprite (); _ player. graphics. beginfill (0xff0000); _ player. graphics. drawcircle (0, 0, 5); _ player. graphics. endfill (); _ player. X = math. random () * 600; _ player. y = math. random () * 600; addchild (_ player);}/** generate a grid and place it randomly Set some obstacles */private function makegrid (): void {_ grid = new grid (30, 30); For (var I: Int = 0; I <200; I ++) {_ grid. setretriable (math. floor (math. random () * 30), math. floor (math. random () * 30), false);} drawgrid ();}/** draw gridlines and fill the obstacle color */private function drawgrid (): void {graphics. clear (); For (var I: Int = 0; I <_ grid. numcols; I ++) {for (VAR J: Int = 0; j <_ grid. numrows; j ++) {var node: node = _ grid. getnode (I, j); graphics. lines Tyle (0); graphics. beginfill (getcolor (node); graphics. drawrect (I * _ cellsize, J * _ cellsize, _ cellsize, _ cellsize) ;}}/** return node color */private function getcolor (node: node ): uint {If (! Node. retriable) return 0; If (node = _ grid. startnode) return 0 xcccccc; If (node = _ grid. endnode) return 0xff0000; return 0 xffffff;}/** when you click the mouse, the end point is randomly set and the current position of the player is used as the start point */private function ongridclick (Event: mouseevent ): void {var xpos: Int = math. floor (mousex/_ cellsize); var ypos: Int = math. floor (Mousey/_ cellsize); _ grid. setendnode (xpos, ypos); xpos = math. floor (_ player. x/_ cellsize); ypos = math. floor (_ player. y/_ cellsize); _ grid. setstartnode (xpos, ypos); drawgrid (); findpath ();}/** pathfinding */private function findpath (): void {var astar: astar = new astar (); if (astar. findpath (_ grid) {_ Path = astar. path; _ Index = 0; addeventlistener (event. enter_frame, onenterframe) ;}}/** animation processing per frame */private function onenterframe (Event: Event): void {var targetx: Number = _ path [_ Index]. x * _ cellsize + _ cellsize/2; var targety: Number = _ path [_ Index]. y * _ cellsize + _ cellsize/2; // apply the passing vertex to the yellow var passednode: node = _ path [_ Index]; graphics. linestyle (0); graphics. beginfill (0xffff00); graphics. drawrect (passednode. x * _ cellsize, passednode. y * _ cellsize, _ cellsize, _ cellsize); var DX: Number = targetx-_ player. x; var DY: Number = targety-_ player. y; var Dist: Number = math. SQRT (dx * dx + dy * Dy); If (Dist <1) {_ index ++; // Add 1 to the index, that is, if (_ index> = _ path. length) // when the last node is reached, remove the enter_frame listener {removeeventlistener (event. enter_frame, onenterframe) ;}} else {_ player. X + = DX *. 5; _ player. Y + = Dy *. 5 ;}}}}
Move the mouse over a blank node and click it to see what will happen?
Consider the last question: the actual game map has a ground, a high slope, a sand, a snow... different road conditions, the difficulty of walking (that is, the cost) should be different? In all our examples, all nodes that can be crossed are treated equally. How can we differentiate different terrain situations?
Note: In node.
Public var costmultiplier: Number = 1.0; // cost factor
And in astar.
// Calculate the total cost of the test node var G: Number = node. G + cost * test. costmultiplier;
You must be smart! Yes, costmultiplier is the cost Weight Factor. If the weight factor of each node is different, it can reflect the difficulty of walking on different terrain.
Package {import flash. display. sprite; import flash. events. mouseevent; public class gridview2 extends sprite {private VaR _ cellsize: Int = 20; private VaR _ grid: grid; Public Function gridview2 (Grid: grid) {_ grid = grid; for (var I: Int = 0; I <_ grid. numcols; I ++) {for (VAR J: Int = 0; j <_ grid. numrows; j ++) {// set different "cost Weight Factor" Var mult: Number = math for each node. sin (I *. 50) + math. cos (J *. 2 + I *. 05); _ grid. getnode (I, j ). c Ostmultiplier = math. ABS (mult) + 1 ;}} drawgrid (); findpath (); addeventlistener (mouseevent. click, ongridclick);} // draw grid public function drawgrid (): void {graphics. clear (); For (var I: Int = 0; I <_ grid. numcols; I ++) {for (VAR J: Int = 0; j <_ grid. numrows; j ++) {var node: node = _ grid. getnode (I, j); graphics. linestyle (0); graphics. beginfill (getcolor (node); graphics. drawrect (I * _ cellsize, J * _ cellsize, _ cellsize, _ Cellsize) ;}}// obtain the cell color (associated with the weight factor, the smaller the costmultiplier, the deeper the color) Private function getcolor (node: node): uint {If (! Node. retriable) return 0; If (node = _ grid. startnode) return 0x666666; If (node = _ grid. endnode) return 0x666666; var shade: Number = 300-70 * node. costmultiplier; return shade <16 | shade <8 | shade;} // when a cell is clicked, switch the node to a common node or an obstacle node private function ongridclick (Event: mouseevent ): void {var xpos: Int = math. floor (event. localx/_ cellsize); var ypos: Int = math. floor (event. localy/_ cellsize); _ grid. setretriable (XP OS, ypos ,! _ Grid. getnode (xpos, ypos ). retriable); drawgrid (); findpath () ;}// find a private function findpath (): void {var astar: astar = new astar (); If (astar. findpath (_ grid) {// showvisited (astar); showpath (astar) ;}} private function showvisited (astar: astar): void {var visited: array = astar. visited; For (var I: Int = 0; I <visited. length; I ++) {graphics. beginfill (0 xcccccc); graphics. drawrect (visited [I]. x * _ cellsize, visited [I]. y * _ cellsize, _ cellsize, _ cellsize); graphics. endfill () ;}} private function showpath (astar: astar): void {var path: array = astar. path; For (var I: Int = 0; I <path. length; I ++) {graphics. linestyle (0); graphics. beginfill (0); graphics. drawcircle (path [I]. x * _ cellsize + _ cellsize/2, path [I]. y * _ cellsize + _ cellsize/2, _ cellsize/3 );}}}}
Keep up with the gridview in the previous section. compared with AS, gridview2.as sets different weighting factors for Nodes Based on the sin and cos functions in the constructor. In addition, the cost of dark colors is higher than that of light colors, test:
Package {import flash. display. sprite; import flash. display. stagealign; import flash. display. stagescalemode; import flash. events. mouseevent; [SWF (backgroundcolor = 0 xffffff, width = 440, Height = 440)] public class pathfinding_2 extends sprite {private VaR _ grid: grid; private VaR _ gridview: gridview2; public Function pathfinding_2 () {stage. align = stagealign. top_left; stage. scalemode = stagescalemode. no_scale; _ grid = new grid (20, 20); _ grid. setstartnode (1, 1); _ grid. setendnode (18, 18); _ gridview = new gridview2 (_ grid); _ gridview. X = 20; _ gridview. y = 20; addchild (_ gridview );}}}
It can be seen that after the weight factor is adjusted, the path should be in the area close to the light color as much as possible! The comparison may not be strong.CodeIn the gridview2 switch back to the gridview, compare to see the path without weighting factor interference
Of course, in the specific game development process, *AlgorithmWe also need to combine many other technologies (such as loading maps, setting weights with maps, and assigning maps to grid units) to make a good game, here we will only discuss the principles of pathfinding algorithms. We will leave other aspects for you to complete on your own.