
Age of Empires Definitive Edition's pathing and movement - ingve
https://richg42.blogspot.com/2018/02/on-age-des-pathingmovement.html
======
faitswulff
The fact that this post seems to be engendered by a comment on a forum ("The
pathfinding in the game is terrible.") reminds me of 'Designing Video Games is
Hard Work, But the Millions of Angry Players Make It All Worthwhile'

[http://thehardtimes.net/harddrive/designing-video-games-
hard...](http://thehardtimes.net/harddrive/designing-video-games-hard-work-
millions-angry-players-make-worthwhile/)

~~~
baldfat
I use to be a high level Age of Kings player (Even got an invite to the first
World Cyber Olympics in NYC).

The pathing was ALWAYS horrible but the PATCHING by the developer was even
worse. There were times when the community just banned certain things because
they were just broken (Teuten's Town halls were only costing wood but did more
damage than high costing resource units and buildings).

As a high level player a broken pathing allowed me to micro my troops and get
an advantage over other players. Most players play with the speed of a 4X and
there were few of us who played by trying to make 150+ commands a minute.

So this horrible pathing was seen as an advantage by faster players.

Scale APM Description ~50 Casual player ~75 Experienced player ~150 Proficient
player >200 Proficient player with superfluous actions

~~~
preben
Brood War does this _all_ the time. The pathing is notoriously bad[1] and
nothing has been done to fix it because it's not a problem. It allows players
extinguish themselves by working with the weird behaviors.

[1] Day[9] on Pathing in BW
[https://youtu.be/rWvoMrYCQBU?t=17m50s](https://youtu.be/rWvoMrYCQBU?t=17m50s)

~~~
paulryanrogers
As a casual gamer I find this aggravating. Why should the NPCs be left dumber
and less human than they could be? It breaks immersion and makes the game
harder for novices to enjoy.

~~~
khedoros1
Because it's hard to fit a lot of intelligence into the game, when it has to
run on a 90MHz Pentium I with 16MB of RAM available.

I thought it was pretty good, and more than enjoyable, when it came out 19
years ago.

~~~
paulryanrogers
As did I back in the day. But now I'm older with less time to micromanage
pathfinding. And our devices are much faster than when many of these games
launched

~~~
khedoros1
Well, in general, the rest of the answer to your question is that _newer_
games tend to have better pathfinding, but adding better pathfinding to older
games will make them essentially different games. Casual players might like
it; serious players would throw a shit-fit. It's one of those "we can, but
_should_ we?" questions; everyone's going to have a different opinion.

Now...I don't see why they couldn't have included it as a toggle-able option.
I know that I've considered trying to build updated versions of old games, and
when thinking about how to do it, that seemed like the best choice.

------
discreditable
Having played the game for a bit, one of the charming things is that the path
finding still feels a lot like the original. It's certainly better. As
mentioned, the new version fixes a lot of villager collision issues. They
preserved the behaviors that made AoE what it was and fixed some of the bad
aspects of it.

------
Radim
For people interested in path finding, there was some fascinating research
done in the 90s:

[http://faculty.nps.edu/ncrowe/snell2.htm](http://faculty.nps.edu/ncrowe/snell2.htm)

They used Snell's law to design pathfinding directly on region polygons, based
on ray refraction. This is in contrast to the more common type of "grid
searches" (A* being the most prominent example) which superimpose a grid and
then do a wavefront graph search on that.

I remember implementing this "refraction search" in the 90s as a C++ PoC. It
was a fascinating and elegant concept, but a complete bitch to get right due
to its "continuous" nature (rays just barely hitting polygon vertices,
parallel edges, numerical instability).

~~~
rcfox
I think it's more popular nowadays to do a search on an adjacency graph of
polygons and then smooth the path with something like the funnel algorithm.
[http://digestingduck.blogspot.ca/2010/03/simple-stupid-
funne...](http://digestingduck.blogspot.ca/2010/03/simple-stupid-funnel-
algorithm.html)

~~~
crispweed
Yes, a lot of people are doing this, and it's not a bad approach.

There's another approach you can take for continuous space pathfinding,
however, which is to use visibility graphs.

See [http://www.cs.kent.edu/~dragan/ST-
Spring2016/visibility%20gr...](http://www.cs.kent.edu/~dragan/ST-
Spring2016/visibility%20graphs.pdf), for example, for some explanation and
diagrams.

This is the approach I used in PathEngine (www.pathengine.com).

A lot of people are put off by the possibility for graph explosion in
situations where there are a lot of obstacles in an open environment, but
PathEngine works around this quite effectively by detecting these kinds of
obstacles and pulling them out of the visibility graph (and pathfinding
search).

~~~
AstralStorm
And I suppose when encountering them (since they were culled not truly
removed) switching to a backup collision avoidance mechanism or replanning?

~~~
crispweed
The trick is to detect obstacles that are likely to have minimal affect on the
global result of pathfinding search, e.g. convex obstacles that are in the
middle of open spaces, or, more specifically in the case of PathEngine,
obstacles that don't combine with other nearby obstacles to form larger
blockages.

After the initial graph search, the path is modified to avoid these obstacles
locally (by pushing the path around the obstacles, essentially), before it's
returned from the pathfinding query.

So the way it's set up in PathEngine this optimisation is largely hidden from
application code (code that calls into the pathfinding API).

Leaving this to be handled later on, by agent local obstacle avoidance, could
also work..

------
sdrothrock
Talk about a thankless job! That's an extensive list of bugs and working on
someone else's (very old) playground is incredibly difficult.

~~~
pm90
I imagine its more of a passion project. If I had free time, I would love to
delve into the internals of the game that I played so many times as a kid.

Side note: Age of Empires 2 was the first computer game that got me truly
hooked on to computers. I was never interested in the shoot em ups, but a
strategy game, with such gorgeous graphics (for the time) and compelling semi-
historical storyline... it was enchanting!

~~~
always_good

        > gorgeous graphics (for the time)
    

Google image search "age of empires 2." Those graphics are still amazing and
can't really get much better, which is why all they need is HD remastering.

Gorgeous and captivating 2D work, just like booting up the game Pharaoh after
all these years. Just needed a user-made patch to allow higher resolution
support.

------
kbwt
>DE's pathing system's findPath() function was speeded up by approx 3-4x
faster vs. Age1's

How would that make any impact at all given that the game ran just fine on
1997 hardware?

~~~
numerlo
The fact that you don't need to optimize something doesn't mean you shouldn't.

~~~
Invisig0th
Avoiding premature optimization is one of the most important best practices of
modern software development.

~~~
qu4z-2
This isn't premature... the algorithm and performance are understood. That
said, I agree that it's not always the best use of time.

------
simias
I would've guessed that bad pathfinding in these old games was caused by very
aggressive optimizations to improve performance but then the author starts off
by saying:

>DE's pathing system's findPath() function was speeded up by approx 3-4x
faster vs. Age1's

So the old code was just that bad? It's a bit odd, you'd expect such a
critical piece of code in an RTS to be reasonably well written and optimized.

~~~
creato
Before saying the old code was just bad, put yourself in the shoes of an AoE1
developer.

Google and stack overflow don't exist. If there is a good A* implementation to
start from, it's still going to be hard to find. At the time AoE1 was
developed, it would require _considerably_ more skill and effort to develop a
high quality path finding engine than it would today.

Contemporary games also had bad pathfinding. Today, we know what is possible
with good pathfinding. Would you have known at the time? Just knowing what is
possible is very valuable information. My guess is that if an AoE1 engineer
could have time traveled for just a few minutes to observe modern pathfinding,
they would be able to very quickly make progress on improving to something
closer to what we expect today.

The old pathfinding might have been bad, but I wouldn't assume that it would
have been easy to make it that much better at the time. We have a lot of
knowledge now that is easy to take for granted.

~~~
AstralStorm
Are you for real? The good path finding algorithms were devised in 80s and are
described in detail in chestnuts like Cormen, Leiserson, Rivest, Stein
Introduction to Algorithms. Released in 1990.

I can understand skimping $40 on a book... but not the argument that it was
hard to find those things.

~~~
w0utert
'Pathfinding' in the scope of an RTS means a little more than just
'pathfinding' in the scope of a graph.

If you had read the article you would have seen that there is a lot of
dynamics behavior going on that is essential for the gameplay, but mostly
unrelated to the A* search itself. I don't think you would find many books
from the 80s about pathfinding for RTS games.

~~~
animal531
Exactly. There's a huge difference between a theoretical algorithm in a book
(that performs 1 search) vs having 120 real time units all trying to walk
together, or even worse, through each other.

In the 80's and 90's you were lucky to dig up docs from BBS releases that had
math and graphics tutorials in them, it was very hard to find anything
practical.

~~~
AstralStorm
120 real units. By that you mean plotting 120 paths simultaneously using a
common flow algorithm used by internet routers which is more than fast enough
and reasonably easy to speed up or truncate.

The tricky part is on assigning nodes on a contiguous map or reducing number
of nodes. (Or expanding node resolution on demand.)

Of course many games of the time side stepped it by using greedy truncated
pathing instead. Easy, dirty, mediocre results.

------
kakaorka
I hate that it’s only available on windows 10. Bad move Microsoft!

~~~
artimaeis
Genuinely curious: what other platforms would you like to see this on?

~~~
kakaorka
I use windows 7, I refuse to use windows 10 because of the clear privacy
issues in it. So I would’ve liked if it worked on windows 7.

------
gameswithgo
I just did some teaching of A* on my stream on Tuesday night in golang,
tonight we make it fast by implementing a proper priority queue from scratch.

[https://www.twitch.tv/videos/233560937](https://www.twitch.tv/videos/233560937)

Much simpler case since it is on a grid and turn based!

------
z3t4
A total rewrite is almost _never_ worth it _unless_ the thing you are
rewriting is not under development in-production. eg. you don't have to fix
bugs in the old version during the rewrite. As you will have a very clear
specification and domain experience (if you also worked on the original).

~~~
AstralStorm
And this is why Age of Empires never got its pathing or engine rewritten in
later versions... oh wait.

------
JepZ
> Age1's pather's A* implementation was outright broken (the open list
> management was flawed, so the cheapest node wasn't always expanded upon
> during each iteration)

What is left of A* if even that doesn't work?!?

~~~
shoo
maybe it picked the cheapest node quite often. you might still get 85%-95%
optimal paths - roughly heading the right way with occasional strange
sidesteps and zigzags in the route

if it was completely broken it probably wouldn't have shipped that way, so the
defect meant it was probably only somewhat broken and the end result was
workable.

------
indescions_2018
Just pre-compute everything. Put your vector fields in textures at map design
time and be done with it. No point in overthinking this once its a simple
lookup per frame.

The real fun is designing the agent's AI: exploration, avoidance, engagement
;)

Crowd Pathfinding And Steering Using Flow Field Tiles

[http://www.gameaipro.com/GameAIPro/GameAIPro_Chapter23_Crowd...](http://www.gameaipro.com/GameAIPro/GameAIPro_Chapter23_Crowd_Pathfinding_and_Steering_Using_Flow_Field_Tiles.pdf)

Flow Field Pathfinding Tutorial

[http://leifnode.com/2013/12/flow-field-
pathfinding/](http://leifnode.com/2013/12/flow-field-pathfinding/)

~~~
arcticfox
> Put your vector fields in textures at map design time and be done with it.

I think you're forgetting there _is no_ map design time in Age of Empires
since the maps are RNG. Also, walls, structures, and destroyed forests are
critical to gameplay, so it has to be an extremely dynamic process.

There are obviously ways to improve the pathfinding,
[https://github.com/SFTtech/openage](https://github.com/SFTtech/openage) has
many plans, but your dismissals are starting from wrong assumptions.

------
JepZ
Sounds like many player complain about, that the game is too much like AoE1 :D

So far I played only one match but that felt pretty much like the AoE1.

~~~
jandrese
As someone who was a big RTS fan back in the 90s, the level of enthusiasm for
AoE seems kind of odd to me. I always thought of it as an also-ran. I remember
it coming out kind of late, only a little before Blizzard released StarCraft
and basically killed the genre.

It did have a fairly unique setting among RTSes at least. So I could see the
niche among historical enthusiasts who also wanted to play RTS. That wasn't me
though.

------
quadcore
Cool. I've coded a RTS myself, and I might be able to add some information.

 _DE 's pather gives up if after many thousands of iterations it can't make
forward progress towards the goal, to avoid spending CPU cycles on hopeless
pathing unnecessarily. (It's more complex than this, but that's the gist of
it.)_

The right way to do that is to make a unit _pop_ the action on top of its
stack if it cant perform it. So if a unit cant move somewhere, it just removes
the action that says it should move there. Now, the trick is: a user click
pushes an action which isnt the actual move but which generate actions with
actual move. It allows the unit to not give up when it cant perform an action
on a user order but make it retry later, say in half a second.

 _I implemented the A_ early exploration optimization*

I did something similar. The way I did that was that a unit of the group would
perform an A* but on a grid that has say 64x less cells. The path would be
marked and the following, per unit, precise A* would not push into the
openlist a cell that's not in the marked grid. Subsequently, if another unit
of the group starts a precise A* but is not itself on a marked cell, it
performs again a big cell A* marking (union-ed with the previous one). Note
that when you select units and perform actions with them, 1) they will have
the same actions by definition and 2) they will group if you move them, which
3) makes that algorithm quickly efficient in practice.

The only requirement is a map of the walls at the size of the "big grid".
Could be problematic I guess in some cases. Not that it doesn't take into
account dynamic walls which is ok (units and such).

 _For short range paths, straight line paths are preferred vs. the tile path
returned by findPath() if the straight line path is safe to traverse_

I understand the constraint of this new Age of Empire. Still it's a good
introduction for the next topic. I dont know what the guys from blizzard used
in SC2 but here is what I did to improve the grid system.

Essentially it all goes down to 2 constraints: 1) you dont want a non-idle
unit to be ever blocked by friendly idle units and 2) you want the attacking
units to block any unit - because you dont want an attacking unit to move
because eh, it's making damage right now. The difficulty is that (1) seems
incompatible with (2) at first, when using A* (on a grid or anything else).
(1) makes multiple units to be on one node, (2) and more generally combat,
make you dramatically want a node to have only one unit for obvious reasons:
you want a unit to be able to fire immediately if at order range and to block
the other units.

The way I solved that is by using marching squares. All units moves freely on
the map, at the "pixel scale", the floating point scale - though it's all
integers because the network algorithm, the lockstep, needs integer. Anyway,
so you have some fix point math which divide a cell into say, 1024 integer-
units.

When performing a pathfinding, a marching square mesh is first built
(environment can be precomputed, attacking units are dynamic walls I recall).
But the trick and the cool thing is that, when building that marching square
mesh, you can actually and easily make a graph of it, which includes a lot of
the original cells nodes. Now that you have a graph, you can do an A* and (1)
and (2) are all solved. It's quite super simple to implement and as fast as
the grid basically. There is also an added benefit: it's easy to make units go
straight all the time because the marching squares will gives you the vertex
that are reflexes and units can jump from reflexes right away.

The magic moment is that when you select a group of unit and make it attack a
single target, the units will form a circle in a very elegant way. Here:
[https://gfycat.com/TediousThoseKitty](https://gfycat.com/TediousThoseKitty)

~~~
AstralStorm
Pretty decent, alternative approach is to form virtual "formations" when units
near each other and move as blocs. This removes multiple problems like units
bumping into each other on the way and is kind of the behaviour a strategy
player would expect. On obstruction, make neighbours slow down and indeed use
obstruction avoidance (local pathfinding) to "squish" the formations. Return
to these later when possible.

Marching squares indeed produces a similar result of "squishing". However as
it is ran per unit you will have more collisions.

~~~
quadcore
_Pretty decent, alternative approach is to form virtual "formations" when
units near each other and move as blocs. This removes multiple problems like
units bumping into each other on the way and is kind of the behaviour a
strategy player would expect. On obstruction, make neighbours slow down and
indeed use obstruction avoidance (local pathfinding) to "squish" the
formations. Return to these later when possible._

Yes definitely. That is orthogonal to the main pathfinder. Moving units doesnt
count as "walls" and so they can just push each other using a physic/collision
engine and move all together like one body as well using that engine which is
a sort of "local pathfinder" in some ways (it can be tweak so that units tend
to avoid each other and all).

------
waterhouse
Something has puzzled me about pathfinding in games. There is a well-known
algorithm[1] for finding an optimal path: you start at the destination, assign
that a cost of 0, make a queue from the points that can reach it directly,
compute for each of those points the minimum "cost of directly reaching a
marked point + cost written on the marked point", and then, while the queue is
nonempty, taking the point with the cheapest minimum cost, marking that point
with that cost, adding the point's neighbors to the queue, and recomputing the
"minimum cost" for everything that can directly reach the point. You can then
either terminate when your source point gets marked, or maybe keep going and
keep the whole table around for the next time you need a path to that
destination.

At least in turn-based games like Civilization, where most of the runtime is
spent letting the player think while refreshing the display, it seems
eminently feasible to do this every time a unit is given a goto command. (Also
the number of points isn't that large: probably a few thousand distinct
squares, much less if you restrict yourself to continents.) Yet Civilization
II, at least, yields obviously suboptimal results, and I think I read that one
thing it does is run a "perfect" search for every square on the screen, but do
something more stupid if part of the optimal path is off the visible screen.

In an RTS, the terrain is probably somewhat more continuous, so there may be
more "points" to deal with, and probably more paths need to be computed.
Structures are built and destroyed, changing the terrain and the paths; units
are moved around much more frequently, though arguably the presence of units
should be ignored unless you're very close to the destination. Commands are
issued much faster. All these add to the problem, but still...

I would expect games to be implemented first with perfect pathfinding, and
then, if that was prohibitively expensive, to have optimizations, possibly
"lossy optimizations" (i.e. heuristics), perhaps a bunch of caching or maybe
"computing things at low resolution first"... And every optimization could be
easily tested against the perfect pathfinding. If the optimizations would
often lead to abysmal path-choosing, then this would be very easy to discover
in testing.

So I'm surprised that games could have been released with pathfinding bad
enough to become infamous. And yet this seems to have happened in multiple
games (e.g. in Starcraft). How? Am I severely underestimating the problem
difficulty? Did people not even try for perfection because of how slow CPUs
were? Did people just assume basic heuristics would work and not bother to
check—I guess _they_ didn't have the advantage of learning from the failures
of the previous generation?

[1] "Dijkstra's algorithm" seems to be what the kids call it. Did Dijkstra
only ever come up with one algorithm? I think "frontier algorithm" would be an
improvement. Oh well.
[https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)

~~~
JoeAltmaier
'Perfect pathfinding' sucks with swarms. The first unit gets to the choke
point; the rest about-face and start marching off the long way around the
forest (because that's now the shortest path with the primary path blocked).
Happened all the time in Warcraft I, and was astonishingly annoying.

~~~
Splines
It seems like a harder problem than that as well - you might want some of the
units in the back of the swarm to go the long way because they'd wait a long
time at the choke.

 _But_ maybe you don't want to do that - those units in the back are squishy
and need to stick with the units at the front of the choke.

 _But_ maybe that's ok - the alternative path isn't too far away and it's not
a risky move to make.

Maybe that's too complicated. Probably best to make the swarm operate as if
other moving units don't exist (to make pathing predictable) and let the
player micromanage via waypoints/grouping.

~~~
AstralStorm
Typically in RTS it is better to keep formation. If the user spots that units
are choking they will order them elsewhere.

The moving units are often easily handled via local avoidance as needed.

------
urza
Meanwhile I will be in forests... Kingdom Come.

