Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Pathfinder, a simple example. (A*)

Author
Message
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 29th Dec 2010 22:50 Edited at: 31st Dec 2010 01:58
Hey guys!

This is a simple example of an A* pathfinder.

UPDATE: Made some speed optimizations, and made the path generated more inclined to make "diagonal" movement.
UPDATE: Added a binary search function for the insertion of nodes on the Open list. (speed optimization)
UPDATE: You can now move the start and destination points of the path in addition to drawing walls. Also I made it look a little nicer on the screen, and added some info and instructions.

I have attached the project/source files to this post, have a go at it.

Here's a link to the tutorial I was reading, just incase you wanna read about the theory behind it.
http://www.gamedev.net/reference/articles/article2003.asp

Comments and the likes are welcome.




Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 29th Dec 2010 23:26 Edited at: 29th Dec 2010 23:27
Quote: "There is a bug when you block the path and then open a path again, the program will crash."


Before anyone delves into the code what did you expect it to do? Obviously there shouldn't be a path in that situation. Here's what I get when I tried your code: (nice code apart from the bug though )

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 29th Dec 2010 23:39
I get the bug when I remove a block after there has been NO path...
But you say you get it also when you place a block?

Hmm... *dives into code*

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 29th Dec 2010 23:46
Quote: "But you say you get it also when you place a block?"


Yes. Just place blocks around the blue block then click anywhere.

What happens to your memblock logic when there isn't a path to begin with? Your main loop seems to assume a path already exists - but if you block the path then there isn't a path in existence when the next loop starts. If you can't see a problem there I suggest putting print statements at critical points in the code to see how far it's got.

Is the line reference correct in the error message?
Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 29th Dec 2010 23:49
Just seen your other post on this topic. Is it the same error? In this case perhaps the memblock doesn't exist when you try to delete it?
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 29th Dec 2010 23:55
Hmm.. Thanks for the input...

Gonna look a little closer at the main loop.

Have checked all the memblock statements and they seem to be in order. But you never know.

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 00:12
I found the bug!

Apparently you're not supposed to delete a memblock which isn't there.

Thx for the help GG.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 00:12
Quote: "Have checked all the memblock statements and they seem to be in order. But you never know."


How about this?

This might be your problem (simplified). What memblock value do you assume when there is not a path?

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 00:14 Edited at: 30th Dec 2010 00:15
Yeah... that was exactly the problem, also I changed it so it returns 0 instead of -1 in several places, since 0 is not a valid memblock anyways.

EDIT: The returning of -1 was a leftover from when I was storing the path in an array.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 00:14
Quote: "Apparently you're not supposed to delete a memblock which isn't there."


That is not the error. The problem is the value you assume for the memblock number when it doesn't exist.

But at least you found the bug. (Well, we both did. )
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 00:16
Yeah... thanks alot man.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 00:16
Quote: "Thx for the help GG."


You're welcome.

I'm glad I didn't need to delve into the rest of the code ...
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 00:19
Quote: "I'm glad I didn't need to delve into the rest of the code ..."


It's actually quite a read... lol ...

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 16:45 Edited at: 30th Dec 2010 16:48
UPDATE: 30. December, 2010

You can now move the start and destination points of the path in addition to placing walls.
Also I made it look a little nicer, with some info and instructions on the screen.

The download is attached to the first post.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 17:25 Edited at: 30th Dec 2010 17:31
Thanks. Sounds useful. I might well use that code one day.

How well does it work on bigger arrays/finer resolution blocks?

Edit Just tested it. Neat. Works perfectly.
Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 20:11
Despite my better judgement I couldn't resist peeking into the code.

You mention possible optimisations in your code.

In your demo such optimisations probably aren't worthwhile but on a larger/finer map they might be.

Your suggestion to use a binary search for insertion is one.

Another might be your calculation of the Manhattan distance. If I've understood your code you recalculate that each time you visit a node. Isn't it the case though that once you have a path you also have an accurate underestimate of the path length from each node on the path - namely the actual path length from those nodes. Any additional walls can only increase those lengths or have no effect, they certainly cannot decrease the length. In other words, why not maintain an array of such distances and calculate or revise them upwards when necessary? You'd have to decide what to do if you changed the overall starting or destination points.
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 20:45 Edited at: 30th Dec 2010 20:48
The H value(manhattan) is only calculated whenever a new node is added to the open list. If a node already exist the H value is just copied.

I'm not sure how you would precalc an array for H values since they would need to be re-precalced when the start/destination points change... And you would need a value for each (x,y) coordinate...

Not sure if this is what you meant...

EDIT: Also the Manhattan method isn't really computationally expensive, it's just 2 subtractions and a multiplication.

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 21:52 Edited at: 30th Dec 2010 21:53
UPDATE: 30. December, 2010

- Added a binary search function for the insertion of nodes on the Open list. (speed optimization)

- Doubled the map resolution.

Download in top post has been updated.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 21:55
Quote: "If a node already exist the H value is just copied."


Thanks. I missed that.

Quote: "I'm not sure how you would precalc an array for H values since they would need to be re-precalced when the start/destination points change..."


I'm not suggesting pre-calculation, only not re-calculating. However, I'm also suggesting that you replace the Manhattan value by a better estimate available when you have found the path. This is valid as long as the overall start and destination don't change. A better estimate for H should speed up the search since you should be able to rule out unpromising branches more quickly.

Quote: "And you would need a value for each (x,y) coordinate..."


Why is that a problem? In your demo you'd need only a 40x40 array (but I think you store those values anyway if I've understood your earlier remark correctly so you wouldn't need an additional array). Perhaps I've misunderstood what constitutes a "node"?.

Quote: "Also the Manhattan method isn't really computationally expensive, it's just 2 subtractions and a multiplication."


Agreed. However, two points:

(1) trivial but unnecessary calculations repeated thousands of times will slow things down;

(2) an improved heuristic will reduce the number of times those trivial calculations are repeated.

These points mount up with large map sizes. I don't yet have an idea of what constitutes "large" in your application. I'm thinking of maps up to 1000x1000 say in size.
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 22:29
Quote: "Why is that a problem? In your demo you'd need only a 40x40 array (but I think you store those values anyway if I've understood your earlier remark correctly so you wouldn't need an additional array). Perhaps I've misunderstood what constitutes a "node"?."


Yes, the nodes(positions) that are considered for the path are stored in the gCList() (closed list), which is then traversed backwards following the parent of each node when saving the path.

I'm not quite sure I'm following exactly what you're saying, but I think you mean that it can be sped up if the distance from any given node to the destination is estimated better, then you are right. But I am also new at this pathfinding stuff, so I don't really know how yet. But I will read up on some other methods on the net.

In the meantime, here is a new version that draws a little image in the top left corner of the screen, plotting the considered nodes for the path...

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 30th Dec 2010 23:02
Quote: "but I think you mean that it can be sped up if the distance from any given node to the destination is estimated better"


Yes.

Quote: "But I am also new at this pathfinding stuff, so I don't really know how yet."


I might find time to delve into this over the next few days.

Quote: "which is then traversed backwards following the parent of each node when saving the path."


Isn't that essentially what's needed to do the updating I suggested?

Anyway, food for thought.

I still think it's a nicely implemented demo.
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 30th Dec 2010 23:18
As far as I can tell from the tutorials I am reading, the Manhattan method is the optimal one for gridbased pathfinding with only 4 directions.

They do however point out another possible speedup for large/fine maps:

- Create a more coarse map ontop of the fine map and use that for getting really close, and then just search the fine map for the last few moves.

Also my implementation of the checking of surroundings and updating nodes might be a little off... Trying to figure out a better way, maybe where I can ignore some nodes and not add them for evaluation...

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 31st Dec 2010 00:14
Here's some other tips I found...

6. Some Speed Tips: As you develop your own A* program, or adapt the one I wrote, you will eventually find that pathfinding is using a hefty chunk of your CPU time, particularly if you have a decent number of pathfinding units on the board and a reasonably large map. If you read the stuff on the net, you will find that this is true even for the professionals who design games like Starcraft or Age of Empires. If you see things start to slow down due to pathfinding, here are some ideas that may speed things up:

•Consider a smaller map or fewer units.
•Never do path finding for more than a few units at a time. Instead put them in a queue and spread them out over several game cycles. If your game is running at, say, 40 cycles per second, no one will ever notice. But they will notice if the game seems to slow down every once in a while when a bunch of units are all calculating paths at the same time.
•Consider using larger squares (or whatever shape you are using) for your map. This reduces the total number of nodes searched to find the path. If you are ambitious, you can devise two or more pathfinding systems that are used in different situations, depending upon the length of the path. This is what the professionals do, using large areas for long paths, and then switching to finer searches using smaller squares/areas when you get close to the target. If you are interested in this concept, check out my article Two-Tiered A* Pathfinding.
•For longer paths, consider devising precalculated paths that are hardwired into the game.
•Consider pre-processing your map to figure out what areas are inaccessible from the rest of the map. I call these areas "islands." In reality, they can be islands or any other area that is otherwise walled off and inaccessible. One of the downsides of A* is that if you tell it to look for paths to such areas, it will search the whole map, stopping only when every accessible square/node has been processed through the open and closed lists. That can waste a lot of CPU time. It can be prevented by predetermining which areas are inaccessible (via a flood-fill or similar routine), recording that information in an array of some kind, and then checking it before beginning a path search.
•In a crowded, maze-like environment, consider tagging nodes that don't lead anywhere as dead ends. Such areas can be manually pre-designated in your map editor or, if you are ambitious, you could develop an algorithm to identify such areas automatically. Any collection of nodes in a given dead end area could be given a unique identifying number. Then you could safely ignore all dead ends when pathfinding, pausing only to consider nodes in a dead end area if the starting location or destination happen to be in the particular dead end area in question.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 31st Dec 2010 00:47
I suspect several of those methods give you good, but nevertheless sub-optimal, solutions. Fine in a game of course - who's going to notice that the boss that's just killed you didn't quite take the shortest route before ambushing you.

Quote: "the Manhattan method is the optimal one for gridbased pathfinding with only 4 directions"


I think we're at cross-purposes because I didn't make myself clear. I'm talking about the situation where you keep adding extra wall blocks. But your program allows you to remove blocks of course.

If you don't remove wall blocks and don't change the overall start and destination then you can re-use the shortest path information that you've already found. In that case I don't see how the Manhattan estimate can be optimal. In the other cases I can see that the Manhattan method is hard to beat without a lot of messy coding (which would probably defeat the purpose).
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 31st Dec 2010 01:41 Edited at: 31st Dec 2010 01:42
I think maybe I get it now, and I have made it so the path is only recalculated if it gets blocked by a new wall, or if you delete a wall.

Is this what you meant?

EDIT: And ofcourse it gets recalculated if you move the start/dest points.

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 31st Dec 2010 01:55 Edited at: 31st Dec 2010 01:56
UPDATE: 31. December, 2010

- Made a few speed optimizations.
- Improved the look of the generated path by encouraging the pathfinder to move "diagonal" when sensible.

Download in top post has been updated.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 31st Dec 2010 02:55
Quote: "I think maybe I get it now, and I have made it so the path is only recalculated if it gets blocked by a new wall, or if you delete a wall."


That's not what I meant - but it's a good idea anyway.

I'll try to explain what I mean tomorrow (it's far too late here for me to risk saying anything coherent ...).
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 2nd Jan 2011 23:47
I have stopped fiddling with this for now and started work on a TowerDefense clone, which is the reason why I need a pathfinder. But if you come up with any good optimizations or features, please do tell...

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 13th Jan 2011 19:36
I just read through some of your old comments and...

Quote: "I'm not suggesting pre-calculation, only not re-calculating. However, I'm also suggesting that you replace the Manhattan value by a better estimate available when you have found the path. This is valid as long as the overall start and destination don't change. A better estimate for H should speed up the search since you should be able to rule out unpromising branches more quickly."


So what you were actually suggesting is that when I backtrack the nodes(saving the path) i update the H values to "show" this path to the destination, and then save it for when I calculate a new path?

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 13th Jan 2011 19:44
I believe so.
enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 13th Jan 2011 19:48
Might actually be usefull, especially if you are using the same start/end positions alot (like in a towerdefense clone).

Will probably add a bit of code complexity though, but might just be worth it.

enderleit
19
Years of Service
User Offline
Joined: 30th May 2007
Location: Denmark
Posted: 13th Jan 2011 19:52
Hmm... just got an idea...

Maybe if you need to make a new path and the start/end is roughly the same, you could pre-initialize the H values along the current path so that it will follow it. If a wall pops up it will continue calculating H in the normal way, but would probably end up finding the old path again after going around the new obstacle...

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 13th Jan 2011 20:11
Quote: "Will probably add a bit of code complexity though, but might just be worth it."


Yes. Might need to be a big map before you see any benefit though.

Quote: "you could pre-initialize the H values along the current path"


You'd have to do that carefully by allowing for the possibility that the new route is better than the old route depending on where the new end point is for example. If I've remembered the algorithm correctly then H needs to be an underestimate of the actual shortest route from the current position to the endpoint.

Quote: "If a wall pops up it will continue calculating H in the normal way, but would probably end up finding the old path again after going around the new obstacle"


Not necessarily. When certain critical walls are added the optimal route can change dramatically. But one thing is certain - extra walls can never shorten the best route from a point.
Kiaurutis
15
Years of Service
User Offline
Joined: 19th Jan 2011
Location: Lithuania
Posted: 24th Jan 2011 17:30
what about big 3D maps for RTS game? if want to use pathfinding routine, i have to make a big resolution obstacles map? but if units can move only 4 (or 8) ways, wont path look too "edgy"- when object has to move like this:

|A| | | | |
| |*| | | |
| | |*|*| |
| | | | |B|

Or even worse:

|A|*|*| | |
| | |*| | |
| | |*|*| |
| | | |*|B|

Is there any way to make this path smoother?
Should i try to add some separate function to move object between these waypoints not exactly over them but in a curves (circles) with fixed minimum radius as near as possible? but in this case there would be lots of nasty maths...
i am scared of maths
Madscientist
16
Years of Service
User Offline
Joined: 23rd Aug 2009
Location: Between a rock and a hard place
Posted: 24th Jan 2011 20:42
@Kiaurutis
What I did was combined the A* algorithm with waypoints so the characters would find the right waypoint to go to based off of it's distance from the character and the destination. I attached what I did.

My computer surpasses all the technologies of the day. What computer do I have?

Kiaurutis
15
Years of Service
User Offline
Joined: 19th Jan 2011
Location: Lithuania
Posted: 24th Jan 2011 23:25
@Madscientist

looks good, but... i was asking if i need to make very thick map of waypoints (or obstacles), and it looks as i do
for many waypoints, will be created lots of spheres, which may slow down pc (not sure- nab at these technical things)
now 1 more thing about your application: it gets bugged in 1 position. i made a screen-shot-movie to show whats happening. excluding that 1 case, i like it- nice work

P.S. when open that .avi file with winamp it gets upside down
wmp plays it ok
Madscientist
16
Years of Service
User Offline
Joined: 23rd Aug 2009
Location: Between a rock and a hard place
Posted: 25th Jan 2011 02:23
(I can't open .rar files, only .zip)
I know it's buggy, I have to get around rewriting it to work better but you get the idea. The spheres are just for a visual representation. They aren't necessary. What I do to set up the waypoint positions is make planes in my 3d program inside my map where the waypoints are to be placed. Then export the planes as 1 object. Then I load that object into dbpro and create and position a waypoint at every plane (which are limbs of the object). Then I delete that object. This is sort of complex, you could also create a quick waypoint editor and position the waypoints, then save their locations in a text file. Then just load the data in the text file for the waypoints.
Hope this helped.

My computer surpasses all the technologies of the day. What computer do I have?

Kiaurutis
15
Years of Service
User Offline
Joined: 19th Jan 2011
Location: Lithuania
Posted: 26th Jan 2011 07:02
This is zip file
I strongly recommend u to rewrite all the buggy stuff, before it stops u from doing smth.
Bugs are evil make your way to programmers heaven by fixing them
Madscientist
16
Years of Service
User Offline
Joined: 23rd Aug 2009
Location: Between a rock and a hard place
Posted: 27th Jan 2011 01:13
I will...
eventually...

My computer surpasses all the technologies of the day. What computer do I have?

Kiaurutis
15
Years of Service
User Offline
Joined: 19th Jan 2011
Location: Lithuania
Posted: 17th Feb 2011 19:37 Edited at: 18th Feb 2011 09:30
@Madscientist

I was willing there is an easier way to evade obstacles, but now i see this must be one of the easiest ways to do it. Your code looks really simple, but lacks of comments
In case that it is quite long, can U please comment it?

The waypoint test program is coded for 1 object. I guess it can work with several objects simultaneously, doesn't it?

[EDIT]

here is a tiny bit of code to fast construct 10*10 nodes grid:



i already found out how to change maximal nodes connections, but it doesn't affect how box moves. Does your code allows diagonal movement calculations?

Join The dark Side! We have cookies

Login to post a reply

Server time is: 2026-07-17 14:00:17
Your offset time is: 2026-07-17 14:00:17