Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
Recently I've been upping my production on WoB and things have been going nicely, now they're likely going to halt until I get a pathfinding algorithm. What this algorithm needs to do is Take Point A X and Y, and Point B X and Y, within the tiles figure out the quickest path, and then send the (In this case the enemy) Point A on the first step. I've looked at A*, but can't figure it out. Ereon said he'd get back to me, but its turning a bit slow, so I'm thinking of seeing which one of you is faster. I understand BM far better than any other language, but Pseudo, or BB is better than nothing. ------------------ |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Mene, I wrote a pathfinding algorithm this summer. It works fairly well. It's written in BASIC, so you would need to convert it to whatever you are coding in, but it shouldn't be impossible. Also, are you using a tile engine for movement of characters? Or a tile engine to create the background graphics and the characters can move wherever they want. I suspect that the characters move tilespace by tilespace, right. And one last thing, can the characters move diagonally? |
||||
jestermax![]() Member Posts: 1064 From: Ontario, Canada Registered: 06-21-2006 |
Try reading some theory on Dijkstra's Shortest path algorithm. they're very similar but i think Dijkstra's is a but more basic and easy to implement iteratively. ------------------ |
||||
spade89![]() Member Posts: 561 From: houston,tx Registered: 11-28-2006 |
hey i am no game programmer but does this have something to do with the stuff like the traveling salesman problem?? i think i saw it at www.cprogramming.com under binary tress i think. you could google for it too ------------------ Jesus answered, "I am the way and the truth and the life. No one comes to the Father except through me. |
||||
jestermax![]() Member Posts: 1064 From: Ontario, Canada Registered: 06-21-2006 |
Nope, TSP is an animal of a different viciousness, although at first glance it does look somewhat familiar to shortest path/minimum spanning tree stuff. ------------------ |
||||
ArchAngel Member Posts: 3450 From: SV, CA, USA Registered: 01-29-2002 |
Dijkstra's algorithim is well worth learning. http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm If can understand and implement it, you're a coder. ------------------ |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
JeTSpice, no real engine, its all hardcoded by me. Yeah, if its in basic it should be fairly easy. I don't have a tile engine. Yes, they move by segments of 40 pixels. no, they cannot move diagnally. Arch/Everybody else. I'll look into that algorithm. ------------------ |
||||
samw3![]() Member Posts: 542 From: Toccoa, GA, USA Registered: 08-15-2006 |
quote: I think its also a lot slower since it doesn't have the heuristic element and has to search *every* direction. It seems like Mene has equally weighted paths (40 pixel segments) and since the vision system or distance to destination could add the heuristic element, I personally think that A* is a better choice. I've stubbed out a section on the wiki for Game Algorithms on the Game Design page. Perhaps we all flesh out that section as we have time. God Bless! ------------------ |
||||
Jari![]() Member Posts: 1471 From: Helsinki, Finland Registered: 03-11-2005 |
Hey, what language you are using? I used the Astar c++ class (from one book) in Darkening. It was a challange it self to use the pathfinding class, so I wouldnt bother learning the actual algorithm. Just a suggestion. ------------------ [VoHW] (Help needed) [Blog] (Contact) - Truedisciple (mp3) |
||||
AndyGeers![]() Member Posts: 45 From: London, UK Registered: 06-20-2005 |
quote: I learnt A* from this website: Amit's Game Programming. You could see if that helps you understand it. ------------------ |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
I'm using Blitz Max. Yes, I will know what angle the player is at. ------------------ |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
I'll have some info up later tonight or tomorrow. You might want to try this: get a piece of graph paper. choose a starting point and ending point and draw some obstacles on it. Make sure that you stay on the lines of the graph paper. Then, pretend you are a computer trying to get from start to finish. Put a "1" on the squares around the starting place. That means, if you took one step, then those are all the possible places you would be. If your character can't move diagonally, then don't put 1's in the diagonals. Next put a "2" around all the 1's. But if there's a number already there then don't put a number there. If there is an obstacle, don't put any numbers there, either. Eventually you'll get to your ending point. Now get a red pen or something and draw boxes around the numbers as they descend. Start at the end and draw a box around the lowest number that's next to it. Pretend it's the number 17. There will always be a 16 next to the 17 so draw a box around the 16. Then 15, etc. until you get to 1. There's your path. I'll post some pictures and code on the wiki later. |
||||
spade89![]() Member Posts: 561 From: houston,tx Registered: 11-28-2006 |
hey i was reading the wiki about djikstra's algorithm and i found this blog about google maps and i thought it was interesting what they had done: http://googleblog.blogspot.com/2007/11/road-to-better-path-finding.html ------------------ Jesus answered, "I am the way and the truth and the life. No one comes to the Father except through me. |
||||
steveth45![]() Member Posts: 536 From: Eugene, OR, USA Registered: 08-10-2005 |
A* is the bomb. My advice, learn it. I believe Game Programming Gems (the first one) has a great article on it, with psuedocode. Most of the articles on A* spend countless pages discussing the best heuristic for estimating the distance from a given point to the destination. I found "as the crow flies" to be perfectly adequate. I didn't even read the whole article in GPG, I just took the psuedocode and turned it into working C++ code, which didn't really take long. If it turns out that you actually have performance issues, then maybe you'd want to tweak the heuristic. Trying to figure that out ahead of time is sort of in the realm of excessive premature optimization. I think the strangest part was constructing an efficient priority queue--sort of the key to A*. I actually did a linear search when inserting elements, but I start at the point of last insertion, which is generally "close" to the correct location. Here is the wikipedia psuedocode.
------------------ |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
For future reference, http://theory.stanford.edu/~amitp/GameProgramming/ appears to be a good source. ------------------ |
||||
TwoBrothersSoftware Member Posts: 141 From: Janesville, Wi USA` Registered: 08-05-2006 |
A* Draw circles around the target - when you find the source move in circle by circle. Hope this helps you get a grasp on it. It always helps me to visualize it. |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Along the lines of what 2Bros is saying, here's some pics: pic 7 - the 12th step for the NPC. The paths are starting to close in on themselves in places. I'd suggest doing a few of these to understand basic pathfinding. I'll see if I can dig up my code... [This message has been edited by JeTSpice (edited November 19, 2007).] [This message has been edited by JeTSpice (edited November 19, 2007).] |
||||
samw3![]() Member Posts: 542 From: Toccoa, GA, USA Registered: 08-15-2006 |
Fantastic work JetSpice! This is a great tutorial on the mechanics of pathfinding. really cool! ------------------ |
||||
AndyGeers![]() Member Posts: 45 From: London, UK Registered: 06-20-2005 |
JetSpice's awesome walkthrough (which I think is technically Djikstra's rather than A*) makes it clear why A* is much more efficient - a lot of time is wasted in this straightforward version expanding out MOVING AWAY from the destination. A* just adds in a heuristic that (simplistically stated) means that it always tests the squares nearer the destination first (for any arbitrarily complex definition of 'nearer' - it's gets really cool when you start factoring in costs like how dangerous a given square is to be in, or funky heuristics like that) ------------------ [This message has been edited by andygeers (edited November 20, 2007).] |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Mene, after you get ahold of the concept of pathfinding, you'll also want to consider the majority of terrain you'll be using it in. In my game, I'm using pathfinding as a way to navigate a very complex maze of trees. The dense forest is created randomly, so I'm using the process above. Another thing to consider is the size of the map. In my game, it's 32 x 24. When a player directs a PC or an NPC has to navigate, the distance is very small, ususally within 10 tile spaces (or about 400 pixels). I think the most steps I've seen an NPC have to take is about 40. So this simple pathfinding approach works well for the needs of my game. But if you are working with a scrolling map, the pathfinding technique I've laid out is definitely going to slow you down. In such a case, you can limit the computer's search to a "bird's eye view" from start to finish, as Steveth45 says. If you are not working in maze-like terrain, but simply need to navigate around a few buildings or trees or something, you can do this: Draw a straight line from NPC to target. This technique will not always give you the shortest distance, but it will give you a natural feel of the way that real people find their destination: They walk toward it, avoiding obstacles. Okay, I won't post my code, because it's long and might not be helpful anyway. But if you need any other help or explanation, I'm here. |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
This is what I'm talking about...![]() ------------------ [This message has been edited by Mene-Mene (edited November 20, 2007).] |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Okay, that type of map would make good use of my code. I'll send it to you. | ||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Where should I send it? Or should it be posted here? Maybe you don't need it? | ||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
you could PM me it. Or you could send it to me on my wiki talk and I would delete it if you wanted it hidden, you could post it here, or I could give you my YM, (and me yours) and last of all and least prefered, I could give you my email. ------------------ |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Okay, PM'd ![]() |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
I've made a first edition translation into BM. It doesn't seem to be finding somethings. I'm not seeing Doodad_map, whether its supposed to be a function or an array. http://www.christiancoders.com/cgi-bin/code/code_showentry.pl?id=mene-mene11282007111103&comments=no ------------------ |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
"doodad_map"-sorry I guess I forgot to define it. It is an array, the exact size of the map, which contains all the spaces that cannot be walked on. In your WoB screenshot, it would be all the squares where the yellow walls are. Here's the line: This line checks various maps to make sure that the space is walkable. ( doodad_map actually tells the computer where to put houses, trees, and other props. I used this because the props are irregularly shaped (don't fit into tiles) and so I needed two map arrays -- one for terrain, and one for objects.) ( trigger_map is kind of the same thing - mostly it's used for water and lava which are terrains that the NPCs should avoid (no pathfinding). But I wanted the player to be able to accidentally move the character into the lava.) You probably don't want to use the exact words "doodad_map" and "trigger_map." You can shorten that line to: And then add other conditionals (within that same line) which tell the pathfinding routine to avoid the yellow walls. The conditional needs an array with the same dimensions as your map. You might already have such an array in the program? if path_map(x,y) = 0 and end_flag = 0 and (there's no yellow wall on space x,y) then... |
||||
MastaLlama![]() Member Posts: 671 From: Houston, TX USA Registered: 08-10-2005 |
So, to take JeTSpice's example and turn it into A*, would I be correct in stating the following? ...or does it just turn it into Best-First-Search? - evaluate the distance between [grid positions at current level (1,2,3,n)] vs [goal position] [This message has been edited by mastallama (edited November 28, 2007).] |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
I would totally love to know it, too. Steveth45 talked about line-of-site being the best option, and AndyGeers pointed out why the approach I outlined is not as efficient. I'd guess you're right, MastaLlama, but I'd like to hear from somebody who knows. (And if they could baby-step us, cool. (Because there A* tutorials out there are ???confusing??? to me.) |
||||
MastaLlama![]() Member Posts: 671 From: Houston, TX USA Registered: 08-10-2005 |
Actually, what I added seems to be more like Best-First-Search. If the grid looks like so:
Then my additions would cause the computer to go right first, then around the [O]bstacles because the [E]nd point is closer ...instead of to the left first to get around the [O]bstacles. |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Yes. You could also have a bit of code which checks each new step taken to see if there is a direct route between it and any previous step. If there is a direct route, then the redundant steps are ommitted. Cool idea, MastaLlama. So, the path would go toward the right, and hit the wall and randomly turn up or down and then turn again, making a u-turn. But the code would be checking each new step for direct paths to any previous step, and the u-turn would be omitted. It would kind of be like taking out the slack in the path. |
||||
MastaLlama![]() Member Posts: 671 From: Houston, TX USA Registered: 08-10-2005 |
From what I read, that's exactly how A* works, taking the slack out of the path along with not having to check EVERYTHING with the circles/diamonds. Another intersting one is bi-directional search where you search from both the start point and end point and actually calculate smaller paths by retargeting your searches for the new start point and new end point.
compare [S] to [E] from [S] go to [1]
from [1] (instead of [S]) go to [2]
from [2] go to [3]
This would work faster than concentric circles because it pulls you towards where you need to go instead of checking every possibility. For bigger maps it would work the fastest to get A* under your belt. I don't understand how it works just yet, but I'm getting closer [This message has been edited by mastallama (edited November 28, 2007).] |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
I'm not sure if this matters or not, but the Enemy would only go to the player if the view of the player is unobstructed. ------------------ |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Mene, are you saying: 1.) in WoB, you need the NPC to move only if he sees the player or 2.) in MastaLlama's example, the NPC will only move if he sees the player. ? |
||||
MastaLlama![]() Member Posts: 671 From: Houston, TX USA Registered: 08-10-2005 |
I'm guessing he means #1 as my example was just in concept and could go either way ![]() Mene-Mene, I did a tech demo once similar to the movement you are talking about. If I have time tonight, I'll try and dig it up and let you take a look at my code (it's in Blitz3D but it's 2d interaction and code). It seems like the hard part for you will be getting the enemy to *not* go after the player when the player is not in the enemy's field of view (FOV). I think Ereon (?) was doing something with FOV before where I made the following images as examples: |
||||
JeTSpice Member Posts: 433 From: La Crosse, Wisconsin, USA Registered: 06-10-2006 |
Mene, It shouldn't matter that the enemy has to see the player before he will move. You would simply not call the pathfinding subroutine unless the enemy sees the player. The "enemy seeing the player" would be one of the conditions which needs to be satisfied before pathfinding is called. However, do you need pathfinding at all? If the enemy will only move when he sees the player, then that is a straight line between player and enemy: in this case, no pathfinding is needed. Just do something like this: If enemyX < playerX then enemyX = enemyX + 1 Maybe you want to ensure that if the player ducks behind a wall, the enemy won't just stand there, not knowing what to do, but will walk around the wall. Is this true? Then you will need pathfinding. |
||||
Mene-Mene![]() Member Posts: 1398 From: Fort Wayne, IN, USA Registered: 10-23-2006 |
I was unsure if I even needed pathfinding. Mastallama: It was penny, and the code I have so far is http://www.christiancoders.com/cgi-bin/code/code_listentries.pl?id=AL (Or just look under algorithms in the code place here. It doesn't account for obstacles yet. JeTSpice, yeah, that i suppose would work, as there can't be any obstacles there anyway... lol. a small oversight and overcomplication... ------------------ |
||||
AndyGeers![]() Member Posts: 45 From: London, UK Registered: 06-20-2005 |
quote: The pseudo-code here is fairly easy to follow on how A* works. Each square has three values: You then keep two lists: OPEN (a list of squares that we're going to evaluate) and CLOSED (a list of the squares that we've already evaluated). You seed OPEN with the starting square, and CLOSED starts off empty. As you examine each square in OPEN, you add all of its neighbours to OPEN (at least, the ones that aren't already in CLOSED) and then add the square itself to CLOSED. The magic is the data structure you use for the OPEN list: rather than being a straight forward queue or stack kind of thing, you use what's known as a 'Priority Queue' - each item in the list has a rank associated with it (in this case, f) and each iteration we start by examining the LOWEST ranking square in OPEN. Since f is sum of g and h (i.e. the cost to get TO that square plus the rough cost to get FROM that square) then the square with the lowest f is theoretically the square that's easiest to get to and closest to your destination, i.e. well worth evaluating. And very very roughly, that's A* ------------------ |