Skip to content

Conversation

@gantsevdenis
Copy link
Contributor

@gantsevdenis gantsevdenis commented Jan 5, 2023

replaces the (dead? I guess) PR: #1213, I don't have the rights to modify it anyway.

Compiles and merges cleanly with latest master.
(I only added logging, and fixed the debugDraw to use the right perspective matrix)

UPDATE, I am dumping what I came up to here so that I am not alone carrying those heavy thoughts:

  1. I believe initial direction was wrong
  • Flow field itself is only the small half of the problem: it finds a globally optimal solution to a static problem. Flow field doesn't take into account dynamic obstacles. As such, most players won't even notice that pathfinder changed from A* to Flow field, because dynamic obstacles is what causing all problems. "Pathfinding" != "collision avoidance" !
  • We obviosuly try to navigate in a system with dynamic obstacles, and what we are looking for is called "potential fields", the best paper I found on the subject is "Continuum Crowds by Adrien Treuille, Seth Cooper, University of Washington
    Zoran Popović, 2 Electronic Arts
    " 1 .
    If you read another suggested paper (Crowd Pathfinding and Steering using Flow Field tiles) 2 ,
    out of 10 pages, only 1 (one) sentence on two lines briefly mentions dynamic obstacles. Not the best source for inspiration!
  • Trying to update a Flow field with dynamic obstacles doesn't scale, because we need a high resolution (the smallest dynamic obstacle is small cyborg, which is only 32 world units ("wu"), one full tile is 128wu), and that's just waayy too slow and in any case it doesn't make much sense to calculate an optimal solution just to throw it away the next logical tick.
  1. What I think we should do instead:
  • We need to combine globally optimal Flow field solution, to local solution to dynamic problem. Note, that because it's local, there is no way to ensure that droid will always take the correct path (which kinda mimics the real life: you can't know how far a wall goes unless you follow it). This is against what is described in the book 1 , as they do search for a global solution in even with dynamic obstacles. I don't think this limits us in any way, going from local solution to global is easy: just run cost-minimizing function over the full field.

  • Compute costs for flow field (at coarse grained resolution of 1 tile), but do not compute directions yet. Assume minimum cost is 4, not 1. This is for easier interpolation later. Flow field result can be cached, and they should be valid for targets of different radius. When a structure is built/destroyed it triggers recalculation of all flow fields for ground propulsions (DONE).
    This can be optimized, somewhat easily, for ex by delaying re-computation of FF only to when a droid actually stumbles upon a new, unknown static obstacle.
    But this optimization is only possible for newly built structures.
    Another solution would be to delay re-computation by N logical ticks, so that we update only once per multipe structures built/destroyed.

  • Each logical tick, create a fresh, high resolution (1/16 of a tile, let's call it "cell": so that each tile is 4x4 cells) array. For each moving droid, populate high-resolution array with an area of discomfort in the approximate direction the unit is currently moving, (do not create a circle area around it, that make movement decision look pretty dumb: I tried it). Continuous direction (uint16_t) are sampled to fit into 8 predefined directions. (DONE)

  • For each moving droid, calculate the sum of comfort fields, and discomfort fields (so our flow field cost is a "discomfort"), but subtract the part of the droid itself (DONE). Notice that our flow field has lower resolution, so interpolate its cost (per tile) for each cell. (this is annoying and error prone, because interpolation is different for 8 discreet directions... IN PROGRESS)

  • Now, calculate the path N cells ahead, aka, choose the direction of least discomfort N times. I don't know yet how large N should be, I am thinking about between 1 (=one cell) and 8 (=2 full tiles) (TODO).

  • Now that we know what is the discreet path along high-resolution comfort field, interpolate the angles of all N calculated directions, so that we move Direction back to continuous values from discreet (EDIT: or use those points as control points in Bézier curve describing the path). This is crucial to make droid behave naturally, otherwise they abruptly change their movement vector on the seems between cells/tiles. Note that movement behaviors inherent to propulsions (like wheels making circles and hovers drifting around) should be prioritized over directions suggested by our "pathfinder+avoidance" logic: I think the directions obtained above should only be used to gently steer droids in the right direction, instead of assigning it directly (TODO) (EDIT: again, consider using Bézier curves)

  • Use (dis)comfort fields to create "activity zones" of different types: for ex, artificially increase comfort values around a building under constructions so that Trucks automatically choose the next closest possible emplacement, instead of being stuck behind each other; or add discomfort for droids with full health which are next to a repair station: this will automatically push them away; add more discomfort for areas known to be reachable by enemy fire so that low-health droids will avoid them, etc... (TODO)

  1. Some possible different solution:
  • "Reciprocal N-body collision avoidance" / "Relative Velocity Obstacles" / "ClearPath". Some provide a C++ library. Not tested. Useless for "activity zones" because those are potential fields. Also, not clear to me how it integrates with global Pathfinder.
  1. Some definitely I-dont-believe-are-possible solutions:
  • Steering behaviors. This is way too basic, and plus it requires a new physics engine, and doesn't seem like a good fit for WZ2100

If someone knows this stuff better, and/or sees some incoherence: please do leave a comment, I am not a bloody expert in robotics 💯

@gantsevdenis gantsevdenis force-pushed the flowfield branch 3 times, most recently from e16f113 to b49ff83 Compare January 7, 2023 22:52
@gantsevdenis gantsevdenis changed the title Flowfield again Flowfield & collision avoidance Apr 12, 2023
@dkargin
Copy link
Contributor

dkargin commented Jun 2, 2023

Calculation of reciprocal N-body collision becomes pretty complicated for large number of units. Steering (boids) behaviors are very simple to implement but pretty painful to tweak. I've spent a ton of time for both during my small gamedev career.

I would like to try continuum crowds. Maybe it will need some mixture with more "modern" tricks from D*/lifelong A* to keep only a part of flow/continuum field updated.

Generally, I came here to try flowfield things, but surprisingly found your MR with most work already done.

@dkargin
Copy link
Contributor

dkargin commented Jun 2, 2023

  1. Flow field should be used only in areas, where density of units is very high. In low density/low dynamics area continuum field will be an overkill and good old A* will be a better solution.
  2. Flow fields can be "linked" to commanders. It will effectively reduce amount of fields to maintain. And maybe provide some tangible benefits from using commanders in multiplayer games.

@gantsevdenis
Copy link
Contributor Author

@dkargin I still have much work not pushed here, because I wasn't sure I am moving in right direction/ using right approach; and since you seem to have some real gamedev experience (which I don't), maybe worth get in touch? Sometimes it helps just to talk in order to clarify ideas. Obviously we ll post here every valuable conclusion.
Plenty of options (Discord, google meet, zoom, etc...), whatever you feel like

@past-due past-due marked this pull request as draft January 30, 2025 20:33
@ManManson
Copy link
Member

Another possible direction to solve dynamic collision avoidance problems, while maintaining reasonable performance, is Anytime Dynamic A*, which may be easier to integrate since it builds upon the existing A* framework.

Although, I haven't done any in-depth analysis of how well this algorithm can perform compared to both flow fields or the existing solution, so it needs more thought and careful analysis to evaluate this solution against other previously proposed algorithms.

@MayorUshanka
Copy link

MayorUshanka commented Feb 14, 2025

Yet another way to solve traffic jams is to keep the current path finding, and give droids a way to push others away.

I propose a model where each droid has a bounding circle. When 2 bounding circles overlap, a force is applied to both proportional to the distance of overlap. This pushing physics would require low friction over the ground however, but I think fun play >> realism. Structures could also be given radii, and we could mathematically think of them as having "infinite mass", aka, only apply the push-away force on the droid.

To keep the feature where you can roadblock an enemy, perhaps apply more friction when the 2 droids are not the same alliance.

Circle-circle overlap is very cheap, since you can cancel the square root on both sides when calculating euclidian distance, but it would still be O(n²). To make this collision detection scale well, a BVH could be used, or a quad tree (which would align nicely with the already built in grid, as a side effect it would provide a spatial index for units). That makes it scale O(nlog(n)). Such a structure takes no more than 100 lines of code.

Another irritation is units that need to slowly turn to some direction before they start moving. I realize it's only barely related, but I also suggest getting rid of that as well, and doing the turn while moving. This is less realistic but would be way more fun to play as it solves a major point of "MOVE you stupid ####" frustration for me.

@KJeff01 KJeff01 added the PR: Limbo Work that was never finished and may have significant conflicts. PRs will be slated for closure. label Aug 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement PR: Limbo Work that was never finished and may have significant conflicts. PRs will be slated for closure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants