Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flowfield pathing #1620

Merged
merged 112 commits into from
Jul 19, 2024
Merged
Changes from 1 commit
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
0b3a0e6
path: Initial cost field implementation.
heinezen Jan 27, 2024
c4b1094
path: Define common cost values.
heinezen Feb 4, 2024
dea91a7
path: Initial integration field implementation.
heinezen Feb 4, 2024
7d14a6a
path: Flow field value types.
heinezen Feb 9, 2024
c1b6890
path: Flow field computation.
heinezen Feb 9, 2024
a58b631
path: Integrator implementation.
heinezen Feb 9, 2024
5d97ce8
path: Rename old A* cost type to avoid conflicts.
heinezen Feb 9, 2024
7ddd25d
path: Test flow field calculations.
heinezen Feb 9, 2024
a112009
path: Test individual field types.
heinezen Feb 10, 2024
a1449a4
path: Add demo skeleton for flowfield pathfinder.
heinezen Feb 10, 2024
fc2e9b6
path: Render background in flow field demo.
heinezen Feb 10, 2024
e17d052
path: Convert indent in multi-line comments to tabs.
heinezen Feb 13, 2024
8f0242a
path: Draw cost field in demo.
heinezen Feb 13, 2024
51f09ae
path: Move camera in dem so that whole grid is visible.
heinezen Feb 13, 2024
a6840b4
path: Draw grid lines on top of field.
heinezen Feb 15, 2024
29e49ff
renderer: Fix unindexed mesh being drawn with wrong primitive.
heinezen Feb 15, 2024
02e666b
path: Show cost as tile colours on grid.
heinezen Feb 15, 2024
3cb4983
path: Draw integration field in demo.
heinezen Feb 16, 2024
2dfde71
path: Fix method argument name.
heinezen Feb 17, 2024
c885c6e
path: Fix integration update overflow.
heinezen Feb 18, 2024
520c9cf
patg: Get individual flow field cell values.
heinezen Feb 18, 2024
01bff57
path: Draw flow field in demo.
heinezen Feb 18, 2024
791fa60
path: Change field that is rendered with F1-F4 keys.
heinezen Feb 23, 2024
d24bc06
path: Reset flow field values on build.
heinezen Feb 24, 2024
0b0774e
path: Change goal with right mouse button.
heinezen Feb 24, 2024
89b210d
path: Create RenderManager in demo for all graphics code.
heinezen Feb 24, 2024
53bee9d
path: Remove old renderer code from demo.
heinezen Feb 25, 2024
e3005a8
path: Toggle vsibility of steering vectors.
heinezen Feb 25, 2024
94a423e
path: Change flow field tile colors depending on flags.
heinezen Feb 25, 2024
ea1a01d
path: Update rendering when switching targets.
heinezen Feb 25, 2024
164ed60
path: Fix wavefront algorithm.
heinezen Feb 25, 2024
2800ac8
path: Turn off OpenGL debugging for demo.
heinezen Feb 25, 2024
1746590
path: Add helpful log messages to demo.
heinezen Feb 25, 2024
88fd1f1
path: Add log messages for field types.
heinezen Feb 25, 2024
23d8298
path: Add constant for initial flow field cell value.
heinezen Feb 25, 2024
67d6067
path: Add flags to integration field cell type.
heinezen Feb 25, 2024
824fcca
path: Check for line of sight flag when building flow field.
heinezen Feb 25, 2024
35533ce
path: LOS pass in integration field.
heinezen Mar 2, 2024
a42fc33
path: Manual resetting of integration/flow field.
heinezen Mar 2, 2024
ce0210b
path: Handle LOS corners.
heinezen Mar 4, 2024
1ee2baa
path: Add another impassible cell to demo.
heinezen Mar 4, 2024
a36931f
path: Integrate cost withexisting wavefront.
heinezen Mar 7, 2024
1cfac16
path: Use wavefront blocked cells as start for cost integration in demo.
heinezen Mar 8, 2024
f9e4007
path: Fix initial wavefront hit not being considered for cost.
heinezen Mar 9, 2024
3b63113
path: Fix cost calculation for wavefront blocked cells.
heinezen Mar 9, 2024
88f42e5
path: Increase precision of wavefront blocked lines.
heinezen Mar 10, 2024
e3e420d
path: Document our bresenham's line algorithm implementation.
heinezen Mar 10, 2024
897bfe1
path: Add LOS pass to integrator.
heinezen Mar 10, 2024
b693ea1
path: Grid for multiple fields.
heinezen Mar 17, 2024
4278de9
path: Portals between fields.
heinezen Mar 17, 2024
a92b93d
path: Separate grid into sectors.
heinezen Mar 17, 2024
1f48794
path: Move old path implementation to 'legacy' folder.
heinezen Mar 17, 2024
d7424b3
path: Pathfinder object.
heinezen Mar 17, 2024
b46c9fa
path: Path request class.
heinezen Mar 17, 2024
2f58987
path: Do not render vectors for LOS cells in demo.
heinezen Mar 23, 2024
4170ff1
path: Assign IDs to grids and portals.
heinezen Mar 23, 2024
73d8062
path: Port flowfield pathfinder to coordinate system.
heinezen Mar 23, 2024
ca05032
path: Store grid size in vector.
heinezen Mar 23, 2024
f943d86
path: Demo for pathfinding grid.
heinezen Mar 23, 2024
b3b620b
path: Fix portals not being created if they end in a corner.
heinezen Mar 23, 2024
b382abb
path: Connect portals between sectors.
heinezen Mar 24, 2024
9a1cc15
path: Refactor demo 1 code for readability.
heinezen Mar 24, 2024
2dd0c3a
fix copyright years
heinezen Mar 24, 2024
bf6136b
path: Get sector size of grid.
heinezen Mar 25, 2024
87bf805
path: Append demo ID to RenderManager class name.
heinezen Mar 25, 2024
8ab759d
path: Draw grid in demo 1.
heinezen Mar 25, 2024
9d90004
path: Render grid in demo 1.
heinezen Mar 27, 2024
ca2de69
path: Daw portal tiles on grid.
heinezen Mar 27, 2024
ea9f143
path: Remove last tile check in portal search.
heinezen Mar 29, 2024
3993d41
path: Use matching types in flood fill algorithm.
heinezen Mar 29, 2024
d0f88dc
path: Store sector position relative to grid origin
heinezen Mar 30, 2024
bc9279a
path: Port A* algorithm code to grid portals.
heinezen Mar 30, 2024
42393b8
path: Fix node cost comparison on heap.
heinezen Mar 31, 2024
16710e9
path: Calculate example path in demo.
heinezen Mar 31, 2024
de9dc91
path: Remove unnecessary parameter.
heinezen Mar 31, 2024
46a544f
path: Remove cost field storage from integrator.
heinezen Apr 1, 2024
4814659
path: Use legacy namespace for old code.
heinezen Apr 1, 2024
ba505e9
path: Integrate cost via portal.
heinezen Apr 2, 2024
e701d8c
path: More fine-grained control in integrator.
heinezen Apr 2, 2024
1466aa1
path: Build flow field via portal. (partial)
heinezen Apr 3, 2024
b74d19c
etc: Pretty printers for path::flow_t and path::integrated_flags_t.
heinezen Apr 7, 2024
555d199
patg: Rename integrate_t to integrated_t.
heinezen Apr 7, 2024
6e19321
etc: Pretty printer for path::integrated_t.
heinezen Apr 7, 2024
5c708eb
path: Don't use other integration field.
heinezen Apr 8, 2024
9b4e7fb
etc: Fix pathfinding pretty printers flag lookups.
heinezen Apr 8, 2024
479e647
path: Exit high-level pathfinding early if start and target are in sa…
heinezen Apr 8, 2024
ae2785d
path: Correctly set starting cost for portal target.
heinezen Apr 9, 2024
d93380a
path: Build flow field via portal.
heinezen Apr 9, 2024
f791358
path: Exclude target cells from search in flow field.
heinezen Apr 12, 2024
bbb5ab3
path: Traverse flow field to find waypoints.
heinezen Apr 12, 2024
8fff701
path: Show waypoints in demo 1.
heinezen Apr 12, 2024
6f568b1
path: Include path start in waypoints.
heinezen Apr 12, 2024
07de19b
path: Draw start and end of path with separate colors.
heinezen Apr 12, 2024
17b53aa
path: Make some of the variable types in the demo more obvious.
heinezen Apr 12, 2024
1d384a6
path: Fix warnings about type conversions.
heinezen Apr 12, 2024
ed5d6c8
path: Initialize portals in Grid object.
heinezen Apr 12, 2024
9cc8710
path: Move flow_dir_t to types.h.
heinezen Apr 12, 2024
1f882f0
path: Document pathfinding functions.
heinezen Apr 13, 2024
78657a3
path: Add timer for path request to demo 1.
heinezen Apr 13, 2024
9ff5802
path: Add TODOs.
heinezen Apr 13, 2024
e947022
path: Fix an issue with gcc not default initializing correctly in rel…
heinezen Apr 13, 2024
066dd06
doc: Pathfinding documentaton text.
heinezen Apr 13, 2024
f9f9ae1
docs: Pathfinding documentation diagrams.
heinezen May 6, 2024
5079768
path: Set start/target in demo with mouse callbacks.
heinezen May 6, 2024
405e2dd
path: Draw waypoints in separate render pass.
heinezen May 6, 2024
e0b63a2
path: Fix check for flow field count.
heinezen May 6, 2024
8b1d427
path: Use distance between portal centers for A star distance cost.
heinezen May 6, 2024
9ebe429
path: Fix setting start/target position.
heinezen May 6, 2024
c6b7b28
path: Use window_settings type to set window size,
heinezen May 6, 2024
9a5ac8d
path: Avoid narrowing conversion to coord types.
heinezen May 6, 2024
cfebd22
path: Reset timer when path is recalculated.
heinezen May 7, 2024
12cd944
path: Fix includes after rebase.
heinezen May 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
doc: Pathfinding documentaton text.
  • Loading branch information
heinezen committed May 24, 2024
commit 066dd06abef0b30fee21eeed8697c300a73b1aed
122 changes: 122 additions & 0 deletions doc/code/pathfinding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Pathfinding

openage's pathfinding subsystem implements structures used for navigating game entities in the
game world. These structures define movement costs for a map and allow search for a path
from one coordinate in the game world to another.

Pathfinding is a subsystem of the [game simulation](/doc/code/game_simulation/README.md) where
it is primarily used for movement and placement of game entities.

1. [Architecture](#architecture)
2. [Workflow](#workflow)


## Architecture

The architecture of the pathfinder is heavily based on the article *Crowd Pathfinding and Steering*
*Using Flow Field Tiles* by Elijah Emerson (available [here](http://www.gameaipro.com/GameAIPro/GameAIPro_Chapter23_Crowd_Pathfinding_and_Steering_Using_Flow_Field_Tiles.pdf)). A core design
decision taken from this article was the usage of flow fields as the basis for the pathing algorithm.

Flow fields offer a few advantages for large group movements, i.e. the movement you typically see in
RTS games like Age of Empires. For example, they allow reusing already computed path results for
subsequent pathing requests and can also be used for smart collision avoidance. One downside
of using flow fields can be the heavy upfront cost of pathing calculations. However, the downsides
can be mitigated to some degree with caching and high-level optimizations.

The openage pathfinder is tile-based, like most flow field pathfinding implementations. Every tile
has a movement cost associated with it that represents the cost of a game entity moving on that tile.
When computing a path from A to B, the pathfinder tries to find the sequence of tiles with the cheapest
accumulated movement cost.

In openage, the pathfinding subsystem is independent from the terrain implementation in the game
simulation. Terrain data may be used to influence movement cost during gameplay, but pathfinding
can be initialized without any requirements for terrain code. By only loosely connecting these two system,
we have a much more fine-grained control that allows for better optimization of the pathfinder.
The most relevant similarity between terrain and pathfinding code is that they use the same
[coordinate systems](/doc/code/coordinate-systems.md#tiletile3). To make the distinction between
pathfinding and terrain more clear, we use the term *cells* for tiles in the pathfinder.

![UML pathfinding classes]()

The relationship between classes in the pathfinder can be seen above. `Grid` is the top-level structure
for storage of movement cost. There may be multiple grids defined, one for each movement type
used by game entities in the game simulation.

Every grid is subdivided into sectors, represented by the `Sector` class. Each sectors holds a
pointer to a `CostField` which stores the movement cost of individual cells. All sectors on the
same grid have a fixed square size that is determined by the grid. Thus, the sector size on
a grid is always consistent but different grid may utilize different sector sizes.

Sectors on a grid are connect to each other with so-called portals, see the `Portal`
class. Portals represent a passable gateway between two sectors where game entities
can pass through. As such, portals store the coordinates of the cells in each sector
where game entities can pass. `Portal` objects are created for every continuous sequence of cells
on the edges between two sectors where the cells are passable on both sides of the two sectors.
Therefore, there may be multiple portals defined for the edge between two sectors.

Additionally, each portal stores which other portals it can reach in a specific sector. The
result is a portal "graph" that can be searched separately to determine which portals
and sectors are visited for a specific pathing request. This is used in the high-level
pathfinder to preselect the sectors that flow fields need to be generated for (see the
[Workflow section](#workflow)).

The individual movement cost of each cell in a sector are recorded in a `CostField` object.
The cost of a cell can range from 1 (minimum cost) to 254 (maximum cost), while a cost of 255
makes a cell impassible. For Age of Empires, usually only the minimum and impassable cost
values are relevant. The cost field is built when the grid is first initialized and
individual cost of cells can be altered during gameplay events.

To get a path between two coordinates, the game simulation mainly interfaces with a `Pathfinder`
object. The `Pathfinder` class calls the actual pathfinding algorithms used for searching
for a path and stores references to all available grids in the pathfinding subsystems. It can receive
`PathRequest` objects that contain information about the grid that should be searched as well as
the start and target coordinates of the desired path. Found paths are returned as `Path` objects
which store the waypoint coordinates for the computed path.

Flow field calculations are controlled by an `Integrator` object, which process a cost field
from a sector as well as target coordinates to compute an `IntegrationField` and a `FlowField` object.
`IntegrationField`s are intermediary objects that store the accumulated cost of reaching
the target cell for each other cell in the field, using the cell values in the cost field as basis.
From the integration field, a `FlowField` object is created. Cells in the flow field store
movement vectors that point to their next cheapest neighbor cell in the integration field. `Path`s
may be computed from these flow field by simply following the movement vectors until the
target coordinate is reached.


## Workflow

To initiate a new search, the pathfinder receives a `PathRequest` object, e.g. from the game simulation.
Every path request contains the following information:

- ID of the grid to search
- start cell coordinates
- target cell coordinates

The actual pathfinding algorithm is split into two stages.

1. High-level portal-based search to identify the visited sectors on the grid
2. Low-level flow field-based search in the identified sectors to find the waypoints for the path

The high-level search is accomplished by utilizing the portal graph, i.e. the
connections between portals in each sector. From the portal graph, a node mesh is created
that can be searched with a graph-traversal algorithm. For this purpose, the A\* algorithm
is used. The result of the high-level search is a list of sectors and portals that are
traversed by the path.

The high-level search is mainly motivated by the need to avoid costly flow field
calculations on the whole grid. As the portal graph should already be precomputed when
a path request is made, the main influence on performance is the A\* algorithm. Given
a limited number of portals, the A\* search should overall be very cheap.

The resulting list of sectors and portals is subsequently used in the low-level flow
field calculations. As a first step, the pathfinder uses its integrator to generate
a flow field for each identified sector. Generation starts with the target sector
and ends with the start sector. Flow field results are passed through at the cells
of the identified portals to make the flow between sectors seamless.

<!-- TODO: More descriptions of cost/integration/flow field calculations -->

In a second step, the pathfinder follows the movement vectors in the flow fields from
the start cell to the target cell. Waypoints are created for every direction change, so
that game entities can travel in straight lines between them. The list of waypoints
from start to target is then returned by the pathfinder via a `Path` object.