request for code: simple A*
BlitzMax Forums/BlitzMax Programming/request for code: simple A*
| ||
I'd like to request some A* methods/functions that: 1: don't come with 54 terabyte of comments between the code that make it unreadable, and for me, unusable. See, I don't want to know how the code works, I only want to know how the algo should be used. 2: are completely local, no globals, global arrays, wasted consts etc. 3: are clear about what the input and output formats are. 4: come *only* as one type with methods/functions, I don't want to see any examples that mess the whole thing up, also I don't want any external game-depended stuff in the core pathfinding algo. Only its own startX/Y and endX/Y fields. In fact, who's talking games anyway? Actually what I'd like to see is a type that looks as follows: Type TPathfinder Field status:Int ' 0: no possible path, 1:path found Field startX:Int, startY:Int, endX:Int, endY:Int Field diagonals:Int=1 ' true: use diagonal routes in pathfinding Field mapwidth:Int Field mapheight:Int Field map:TBank ' representing a 2d map where 0=walkable and 1=wall Field route:Int[] Method Setmapwidth(width:Int) ' all kinda bounds checks here ' .. ' .. If mapwidth<1 RuntimeError "mapwidth<1" mapwidth=width Mapdimensions End Method Method Setstart(x:Int,y:Int) Assert x>=0 And x<mapwidth "start X out ot range" Assert y>=0 And y<mapheight "start Y out ot range" startx=x; starty=y End Method Method Setend(x:Int,y:Int) Assert x>=0 And x<mapwidth "end X out ot range" Assert y>=0 And y<mapheight "end Y out ot range" endx=x; endy=y End Method Method Mapdimensions() mapheight=BankSize(map)/mapwidth If mapheight<1 RuntimeError "mapheight<1" End Method Method Setmap(bank:TBank=Null) Assert bank<>Null "bank=null" Assert BankSize(bank)>=1 "no dimension in bank" map=bank Mapdimensions End Method Method Findpath() ' resulting path in a 'resliced' route[]. ' as [x0, y0, x1, y1, x2, y2, x3, y3, ..etc. .. xn,yn] ' ^ start ^ end ' End Method End Type ' to use: ' make some bank ' make a pathfind instance ' add bank to instance ' set width and start/emd coords ' find path ' read out path from array ' yay \o/ If it's easy to adjust the A* code in the archives to this format then I'd be grateful to the one who does so. :-) |
| ||
I think the problem is that most A* here is blitzbasic code. I'll be happy to code one in blitzmax. Why is the map a bank and not a 2d array though? |
| ||
Well, dunno. Perhaps because a bank is a bank, and not an int? :P If I add a bank to this type instance then map references to this bank, so I won't loose any more mem. Ints/bytes/floats etc. are copied to a new var instance afaik, so I figure the same counts for arrays of those basic vars. If you do, please try to fill in those methods/functions in my framework.. ^_^ For I think that's a clean/open way to do all this. |
| ||
http://www.blitzmax.com/Community/posts.php?topic=62388#697498 |
| ||
Too much noise in it. It's what I meant with 'game depending', in that code there's this Tunit stuff everywhere. Unit? What unit? sprite:timage? What image? Speed? Who needs speed? Who says pathfinding is exclusively for games? Tnode, oh really.. so that costs yet another (global) type, and do I actually care, for only 2 int fields? Tilesize? What tiles? As far as I'm concerned, a tile is a visual property, not a functional property. Etc. etc., that whole thing is almost a game already, it's far from neutral and sterile. The minimum required for pathfinding is a start location and an end location, and a 2d map with walkable/nonwalkable states. I suggest keeping these kind of solutions as minimal as possible, in order to be as flexible and modular as possible. |
| ||
Check the german blitzbasic forum. There is a working and very good A* ressource in the codearchive of the blitzmax categorie (there is one for regular blitz as well if you do not like the BM one) |
| ||
Curtastic: so .. you're up to do it (in the way I proposed)? :P |
| ||
ya!!!111:):):): I think I can do it this weekend |
| ||
Example of how to use: |
| ||
I want your babies! |
| ||
You're welcome, let me know if any improvements are needed, for the code archives or anything. And my seed will conquer the world! |
| ||
^_^ Why the 'abstract' btw? |
| ||
Well I don't see the need to make new instances, since all you need is the route. I could easily change it though. Right now if you want to keep 2 separate paths you have to do: local myroute[] local blahroute[] tpathfinder.findpath(x1,y1,x2,y2) myroute=tpathfinder.route tpathfinder.findpath(blahx,blahy,targetx,targety) blahroute=tpathfinder.route |
| ||
Oops there was a big memory leak because of cyclic refrences, I just edited and fixed it. |
| ||
Here's some code I borrowed from somewhere and ported, I've restricted to 4 directions but it's easy to change back. |
| ||
Awesome Curtastic, thanks! Couple of things: -You misspelled "diagonal." -If I put a value >1 into the map, will it count it as being twice as slow to walk over? If not, what part of the code should I change to make it do this? This is essential for games with varying terrian. (I think it also means that Map[] should be changed to something with decimals, not an int, so I can say, for example, 1.5.) |
| ||
-You misspelled "diagonal." wow. How can I even be smart enough to code this? lol. I seriously didnt know how to spell that. fixed. -If I put a value >1 into the map, will it count it as being twice as slow to walk over? If not, what part of the code should I change to make it do this? This is essential for games with varying terrian. (I think it also means that Map[] should be changed to something with decimals, not an int, so I can say, for example, 1.5.) I could add support for that. Theoretically all you have to do is something like this: 'cost is slightly more for diagnols If Dir < 4 Then NewP.Cost = P.Cost + CostOfTile Else NewP.Cost = P.Cost + CostOfTile*Root2 EndIf |
| ||
I think it needs something like being able to walk in diagonals while not cutting corners when there's a non-walkable thing to cross. Another option for the diagonals field perhaps? 0 no diagonals 1 diagonals + cutting 2 diagonals, no cutting I keep seeing Warcraft in front of me where figures are walking in all 8 directions but aren't cutting corners at buildings/trees etc. |
| ||
Actually I think we should expand this pathfinder with all kinda extra functionality, without loosing its neutrality of course. Apart from the walk/wall and the said ramping there could also be floors (used in cobination with ramping), meaning that from floor a you can't directly move to floor b, only via a ramp. Also, there could be walkable tiles with priorities, high priority is to choose over low priority. What about legal random errors in a path to simulate human errors? (otherwise you get straight marching of units). These errors could be simulated by analyzing the found path: for each step in the route check the surrounding tiles, if they are walkable then the route could add this to the route. What about another route[] to store enviromental properties for each step? Like how many rings of directly walkable tiles are around the position of the step? etc. all these things keep the thing neutral but could greatly enhance the functionality! |
| ||
Wow, nice bit of code! :) |
| ||
I think it needs something like being able to walk in diagonals while not cutting corners when there's a non-walkable thing to cross. Another option for the diagonals field perhaps? 0 no diagonals 1 diagonals + cutting 2 diagonals, no cutting Ya I'll add that. I just didn't know if anyone wanted it. I keep seeing Warcraft in front of me where figures are walking in all 8 directions but aren't cutting corners at buildings/trees etc. Actually in warcraft (and most games I've seen) you can cut corners. Notice the footman is cutting a corner between farms. Most games have corners rounded, so there is room to cut inbetween. What about legal random errors in a path to simulate human errors? (otherwise you get straight marching of units). These errors could be simulated by analyzing the found path: for each step in the route check the surrounding tiles, if they are walkable then the route could add this to the route. Done! What about another route[] to store enviromental properties for each step? Like how many rings of directly walkable tiles are around the position of the step? Well once the route is found you can always do that, it shouldn't be be the pathfinder's job. Now lets say the object is larger than one tile, the pathfinder will need to find a path that the large object can fit through. That's something that I can add. Also, there could be walkable tiles with priorities, high priority is to choose over low priority. Ya I'll do that except the tiles will store how long it takes to move into it. So a high number is slower and 0 is the fastest. [edit: done] Wow, nice bit of code! :) thanks! |
| ||
^_^ babies, more babies! ^_^ But one baby needs a new diper: try to move along the edges of the map with this randomness (place a wall next to it orso) and you'll get an assert exception (coords out of bounds). [edit] hm.. or maybe not.. oO |
| ||
the example could use this, under the: mx = MouseX() / TS my = MouseY() / TS mx=Max(mx,0); mx=Min(mx,19) my=Max(my,0); my=Min(my,19) |
| ||
ok, I added the no cuting corners option. Any more ideas? |
| ||
nice! perhaps the option to specify a variable width for moving agents as an argument, So the pathfinder could exclude paths that are to narrow for anything with a width greater than 1 cell. For example, a width=3 would represent a unit that occupies a 3x3 area. |
| ||
well, those floors I mentioned perhaps, with ramps 'n stuff (like in Starcraft). Tho I wouldn't know how to include that in one single 2d array. |