-
Notifications
You must be signed in to change notification settings - Fork 0
Wall Crawling
AzureCortex includes an optional movement model for mobs that crawl along walls, ceilings, and floors, the
generalization of the historical Ovomorphosis xenomorph movement. This is entirely opt-in: implement
CrawlCapability on your entity and the rest of the framework's navigation/pathfinding code will route through the
crawl-aware evaluators; entities that don't implement it are unaffected.
A mixin-style interface your entity class implements (typically via a mixin onto your entity base class):
public interface CrawlCapability {
boolean isWallCrawling();
void setWallCrawling(boolean crawling);
int getWallCrawlGraceTicks();
void setWallCrawlGraceTicks(int ticks);
Vec3 getCrawlForward();
Vec3 getOldCrawlForward();
Vec3 getCrawlUp();
Vec3 getOldCrawlUp();
double getCrawlDistFromBlock();
double getOldCrawlDistFromBlock();
void setCrawlOrientation(Vec3 forward, Vec3 up, double distFromBlock);
}The old* accessors exist for smooth render-frame interpolation between the previous and current tick's orientation.
If you don't want to hand-roll storage, CrawlState implements the bookkeeping backed by synced entity data
(EntityDataAccessors), you still register the SynchedEntityData.defineId fields yourself and typically delegate
your CrawlCapability methods to a held CrawlState instance:
private final CrawlState crawlState = new CrawlState(
this, IS_CRAWLING, CRAWL_FWD_X, CRAWL_FWD_Y, CRAWL_FWD_Z,
CRAWL_UP_X, CRAWL_UP_Y, CRAWL_UP_Z, CRAWL_DIST
);
// then, e.g.:
@Override public boolean isWallCrawling() { return crawlState.isWallCrawling(); }Call crawlState.tick() once per tick from your entity's own tick method to keep interpolation state and grace ticks
current.
Drives gravity suppression, surface alignment, and (via NavigationHandler) movement for crawl-capable mobs. Call
these each tick from your entity's tick method:
CrawlController.updateWallCrawlingPhysics(mob); // gravity suppression, grace-tick countdown
CrawlController.updateCrawlOrientation(mob, movement); // surface alignmentUseful static queries:
CrawlController.canWallCrawl(mob); // implements CrawlCapability, not in water/vehicle
CrawlController.isWallCrawling(mob);
CrawlController.wasRecentlyWallCrawling(mob); // currently crawling OR still has grace ticks left
CrawlController.setWallCrawling(mob, true);wasRecentlyWallCrawling matters when one action takes over from a crawl-driven approach action, it lets the new
action inherit "was crawling" state even after the previous action already cleared the flag.
CrawlController implements NavigationHandler and delegates computeMovement to MovementController, see
Navigation and Pathfinding, so wall-crawl-capable mobs still get the same obstacle-steering/danger-repulsion
behavior on top of crawl physics.
The crawl-aware A* pathfinder: understands tight-tunnel crawling, vertical-shaft climbing, and surface-cling climb
nodes reached via CrawlCapability, on top of everything AStarPathfinder already does. Routes hazard/passable-solid
classification through MovementCapability (see Navigation and Pathfinding) exactly like the plain pathfinder —
nothing about "which blocks are climbable/passable for this mob" is hard-coded.
var path = CrawlTraversalEvaluator.INSTANCE.findPath(mob, start, goal, 96, 1);
// or with a caller-supplied cache, e.g. inside a larger per-tick scope:
var path = CrawlTraversalEvaluator.INSTANCE.findPath(mob, start, goal, 96, 1, cache);Searches up to 6,000 nodes (vs. 2,000 for the plain pathfinder) since crawl-capable creatures typically need to explore
a larger, more three-dimensional search space. Use IncrementalPathSession.crawling(...) (see
Navigation and Pathfinding) to spread that cost across ticks rather than paying for it synchronously.
A crawl-capable entity typically:
- Implements
CrawlCapability(directly or via a mixin delegating toCrawlState). - Calls
CrawlController.updateWallCrawlingPhysics/updateCrawlOrientationeach tick. - Uses
CrawlTraversalEvaluator.INSTANCE(or anIncrementalPathSession.crawling(...)session) as itsPathfinderin movement actions likeMoveToDestinationAction(see Built-in Actions). - Uses
CrawlController.INSTANCEas itsNavigationHandlerif it needs custom movement code beyond what the built-in actions provide.
AzureCortex now ships a crawl-capable example alongside the zombie and skeleton: CortexSpiderEntity, in
com.azure.azurecortex.example.spider. See
Wall-Climbing Example (Spider) for the full walkthrough (goal enum, planner, tree,
entity wiring, and the CrawlCapability/MovementCapability implementation) built entirely from the pieces
documented on this page, including CrawlToDestinationAction, a new action that example adds for actually driving
movement across walls and ceilings (see Built-in Actions).
-
Navigation and Pathfinding, the ground-walking model this generalizes, and shared pieces (
MovementCapability,PathNodeCache, incremental search). -
Built-in Actions, actions that accept any
Pathfinder, including the crawl-aware ones. - Wall-Climbing Example (Spider), a complete worked example using everything on this page.