16

I'm making a Tower Defense and I need a good pathing algorithm for it.

I have thought about Dijkstra but I need one that can be dynamic; it must be able to update itself when one edge is removed or added without a full recalculation.

I'm coding in C# if it helps.

Grace Note
  • 599
  • 6
  • 13
Daniel
  • 549
  • 3
  • 11

9 Answers9

19

I needed to solve a similar problem: pathfinding on a large maze-like grid with constantly changing "costs" and barriers.

The thing is, in tower defense game the number of entities that need to have the path solved for them is usually much larger than the number of nodes in the graph. A* is not the most appropriate algorithm for handling this, because you'll need to solve it anew each time something is changed. Well it is appropriate if you need to find only one path, but in my case I needed to be able to handle entities which can appear in different locations and each has its own path.

The Floyd-Warshall algorithm is far more appropriate, though for my case I wrote a custom algorithm that whenever a node changes, it re-calculates the cost to that node from all its neighbors, and then if the neighbors have been changed it is invoked recursively on them.

So in the beginning of the game, I just fire up this algorithm on all my "goal" nodes. Then, whenever a single node changes (for example, becomes un-passable), I just fire it up on that node and the change is propagated to all the nodes that will be affected, and then stopped. So no need for global recalculation, and the algorithm is completely independent from the number of entities that will require pathfinding.

My algorithm was basically something like (pseudo-code):

update_node method in Node class:
    $old <- $my_score
    find $neighbor node among all neighbors such that
        $neighbor.score + distance_to($neighbor) is minimal
    $my_score <- $neighbor.score + distance_to($neighbor)
    $next_node <- $neighbor
    if ($my_score != $old)
        for each $neighbor
            $neighbor.update_node()

With the initial score depending on whether the node is a target or some kind of barrier.

Oak
  • 1,242
  • 12
  • 20
7

You'll generally want to use A*, unless there's something importantly different you're looking for.

John Haugeland
  • 954
  • 6
  • 8
  • If I'm not that familiar with A*, how would I address dynamically changing environments? Re-calculate at every frame? At collisions? – Justin L. Jul 22 '10 at 01:57
  • 1
    Generally you would re-path each frame in a simple game like this. The map grid will likely be very small and the number of agents in the hundreds at most. If it ended up being a huge performance problem somehow you could optimize it later by not rebuilding the tree except when needed. – coderanger Jul 22 '10 at 02:32
  • Pathfinding isn't that fast. Games like BTTD can be sluggish on avarage pc, and if I implement it any worse it will get stuck. Is there something I'm missing? – Daniel Jul 22 '10 at 03:57
  • Most TD games are grid based with a grid of maybe 32x32, path finding on that should be pretty blazingly fast. – coderanger Jul 22 '10 at 04:52
  • 6
    If it is sluggish, my recommendations: don't calculate the path for every mob. Likely, theyre all taking the same path. I only recalc on new tower placement, and the tower is in current path. Even then, Only do a re-calc for monsters at points in the path before the block square, not for mobs that are past it and therefore don't care. And then, to make the pathfinding shorter, you could limit it to find the way to square after the blocked square, since you already know the path from there. – seanmonstar Jul 22 '10 at 08:33
  • I need to pick up a bit of industry lingo - what is a "mob"? is it just an enemy AI? – Iain Jul 22 '10 at 14:01
  • He means a crowd of enemies, like one sees in a tower defense game. It's not industry lingo; he's just being conversational.

    Look, A* is retarded fast. It's fast enough that we were using it to pathfind for groups on 500x500 maps on the Gameboy Advance, which is an ARM7 running at 16 mHz. Even from inside flash, if your A* isn't making time individually, the implementation is the problem.

    I'll put my AS3 A* pathfinder in http://scutil.com/ this weekend. That should remove any need for you to bother with mobs (for which the appropriate answer is something like D* or R*).

    You're welcome.

    – John Haugeland Jul 23 '10 at 15:20
  • 4
    Actually, "mob" is industry (and MMO/MUD player) lingo for "mobile object". –  Jul 23 '10 at 18:41
  • Speaking as someone who helped create PennMUSH, and who's been in the industry 15 years, I can say firmly that I've never heard anyone use that extremely unnecessary shorthand.

    Never once.

    – John Haugeland Jul 24 '10 at 05:26
  • 3
    Regardless, it is long-standing, dating back to MUD1, and standard enough to have appeared in many publications. http://en.wikipedia.org/wiki/Mob_%28computer_gaming%29 –  Jul 25 '10 at 18:57
  • @seanmonstar thanks you rock, of course, all the mobs from a tower share a route, you just made my game do like 1% of pathfinding i was doing, same result. – DFectuoso Aug 18 '10 at 22:49
5

The route algorithm I used on my TD was backwards from normal A* pathing due to the number of entities I had in the game. Instead of routing from the goal to the bad guys, I routed from the goal to every empty square on the board.

This doesn't take very long, you just keep iterating the board until you've found your "costs", and it provides good feedback for blocked routes (if you're doing those). Using Floyd's algorithm is fast and cache friendly compared to A* as it's not doing data dependent lookups, it's just loading in and operating on data in streams.

Start with your board set to infinite cost, then set the goal square to cost zero, then iterate over the board checking to see if a neighbouring cell costs less than the current cost plus the travel cost. The travel cost is where you put your heuristic (in my case, the cost of travelling diagonally was infinite, but the cost of travelling through a tower was high, so they were allowed to eat through towers, but didn't unless they had no choice)

Once you've got your costs grid, you can quickly build a "flow" grid from that by testing the steepest gradient of cost on the cells. This works really well for massive amounts of bad guys because none of them ever have to path find, they just follow the virtual signposts.

Another benefit is that this way you only have to run this task every time you adjust the obstructions (or in my game, when a creep eats through one of your towers). Not every time a creep/mob enters the field (which with thousands of mobs and tens per second would have been quite a headache).

Richard Fabian
  • 3,567
  • 1
  • 23
  • 32
4

Pathfinding is fast, and on something the size of a normal tower defense game, you'll have no trouble running a full A* or Dijkstra pass whenever something changes. We're talking well under a millisecond for a full refresh. Any kind of adaptive pathfinding ends up horrifyingly complicated. Just do it the simple way, unless you're making the world's largest tower defense grid.

ZorbaTHut
  • 11,580
  • 1
  • 37
  • 44
  • 1
    It's worth noting that Tower Defense is popular on mobile phones, where pathfinding is not fast. Especially on slightly older devices, like the Sidekick, or Android 1.6 devices. – seanmonstar Jul 22 '10 at 08:37
  • 1
    Developers have been using pathfinding algorithms like A* and Dijkstra on far less powerful hardware for decades (think Game Boy). Any phone new enough to have a screen adequate for gaming shouldn't have a problem, provided of course that the implementation is reasonably efficient.

    There are some nifty optimizations discussed here: http://harablog.files.wordpress.com/2009/06/beyondastar.pdf

    – Mike Strobel Aug 20 '10 at 15:33
  • +1. I came to the same conclusion when I was developing my own DTD clone. I tried updating the paths incrementally but the algorithm became too complex. After spending a day on it, I switched to a full recalc on each change. That worked, and with a few tweaks I was able to make it fast enough. – finnw Feb 08 '11 at 14:59
2

How does A* pathfinding work? might be a good place to start :-)

coderanger
  • 6,147
  • 36
  • 38
2

This may be overkill for your solution, but think of routing backwards instead of forwards.

In a TD game, the enemies are generally trying to get to a specific goal. Route backwards from that goal to the first enemy, then cache that path. On path generation for subsequent enemies, use the first path as a starting point, and so on. If you have multiple enemy entrace points, or multiple goals, have a range of pre-cached paths to start from.

tenpn
  • 5,524
  • 3
  • 32
  • 45
1

Waypoint pathfinding would probably be the best for a td game, because generally based on the level the ai follows a direct path. Basically you set your nodes or waypoints then have the "ai" point towards the waypoiny and walk to it, once it gets close enough to that have it go to the next waypoint, face it and move towards it.

Loktar
  • 186
  • 4
  • This only works for those TD games where you can only place turrets at the side of the path - not games that allow placement of towers anywhere on the board. – Iain Jul 22 '10 at 14:02
  • yeah initially the author didn't specify which type he wanted so I assumed non dynamic. – Loktar Oct 06 '10 at 18:13
1

Since someone asked, you address dynamically-changing environments by re-computing the path every time the player places or removes a tower, and you just store that path in memory in the mean time. The environment doesn't change on every frame.

Note that some TD games have a set path and don't allow you to place towers on it, so they solve pathfinding the easy way: by hardcoding a path and not letting you block it :)

Ian Schreiber
  • 4,412
  • 17
  • 19
1

A simple solution is to cheat.

Design the map beforehand to make sure that there is no dead ends. Then in each intersection, add a trigger that makes the character to choose a route (example: always turn left, always turn right, or random).

MrValdez
  • 731
  • 1
  • 8
  • 17
  • 1
    Presumably he is talking about something like Desktop TD where the user is creating the map on the fly. Still for the "dumb" enemies that might be a nice solution so you can make enemies with better AI a bit of a difficulty boost. – coderanger Jul 22 '10 at 04:57