Skip to content

Wall Climbing Example (Spider)

AzureDoom edited this page Aug 30, 2026 · 2 revisions

Wall-Climbing Example (Spider)

com.azure.azurecortex.example.spider.CortexSpiderEntity is the third bundled example, alongside the melee zombie (Full Example Walkthrough) and the ranged skeleton (Ranged Example Walkthrough (Skeleton)). It uses the same GOAP/behavior-tree shape as those examples, but swaps in AzureCortex's crawl-aware navigation for live-target pursuit.

The important architectural point is still the same: wall crawling belongs mostly to the navigation/execution layer, not the decision layer. The planner can still think in terms of WANDER, INVESTIGATE, and HUNT_TARGET; only the movement branch that actually needs to climb has to care about crawl traversal.

What changed in the current example

The current 1.21.1 example differs from the original walkthrough in a few important ways:

  • The spider now targets players and iron golems only under vanilla-like dark/night conditions.
  • CrawlToDestinationAction now handles both crawl movement and ordinary ground movement itself.
  • Ground movement gets explicit low-step jumping instead of relying only on passive step height.
  • Crawl routing can fall back to ordinary AStarPathfinder when the ground route is better.
  • The crawl action turns the mob toward its horizontal movement direction.
  • The crawl search accepts vertical/ceiling cling surfaces more consistently and has a larger search budget.
  • The example spider has STEP_HEIGHT = 1.5F / maxUpStep() = 1.5F.
  • The old custom travel(Vec3) override was removed from CortexSpiderEntity.
  • The example's crawl chase is intentionally slower and much quicker to declare itself stuck/repath.

1. The goal type

The goal enum is deliberately ordinary:

public enum CortexSpiderGoal implements Goal {
    NONE,
    WANDER,
    INVESTIGATE,
    HUNT_TARGET;

    @Override
    public boolean isNone() {
        return this == NONE;
    }
}

Nothing about this enum says "crawler" because crawling is not a planning concern. A crawler still wants to wander, investigate, or hunt just like a ground mob.

2. The goal planner

CortexSpiderGoalPlanner remains structurally similar to CortexSkeletonGoalPlanner:

  1. Hunt a valid live target.
  2. Otherwise investigate a recent sighting.
  3. Otherwise wander.

It also uses the same GoalFailureCooldowns / PlanFeedback flow as the other examples so repeated FAILED_STUCK or FAILED_NO_PATH results can temporarily reduce the desirability of immediately retrying the same plan.

See GOAP Planning for the planner mechanics.

3. Vanilla-like nighttime targeting

The current spider example no longer uses the broad players().or(ironGolems()) predicate. Its sensor is built from the nighttime-aware helpers:

var validity = VanillaTargetPredicates.onlyPlayersAtNight()
    .or(VanillaTargetPredicates.onlyGolemsAtNight());

onlyPlayersAtNight() also rejects dead, creative, and spectator players. This keeps the example closer to vanilla spider behavior without changing the planner itself: when no valid target is sensed, the normal investigate/wander branches continue to work.

4. The behavior tree

The high-level tree still looks like the other bundled examples:

return PrioritySelector.of(
    new ActionNode<>(idle, 0),
    new Condition<>(
        (agent, bb, cd) -> bb.get(CommonBlackboardKeys.ACTIVE_GOAL_TYPE) == CortexSpiderGoal.WANDER,
        new ActionNode<>(wander, 5)
    ),
    new Condition<>(
        (agent, bb, cd) -> bb.get(CommonBlackboardKeys.ACTIVE_GOAL_TYPE) == CortexSpiderGoal.INVESTIGATE,
        new ActionNode<>(investigate, 8)
    ),
    hunt
);

WANDER and INVESTIGATE stay on the ordinary navigation path. HUNT_TARGET is the branch that uses the dedicated crawl action.

Investigate uses crawler-aware destination validation

InvestigateLastSeenTargetAction still uses AStarPathfinder.INSTANCE, but the spider supplies:

SpiderTraversalPredicates::standableForCrawler

That does not magically make the investigate action climb. It simply avoids rejecting wall/ceiling-adjacent search positions too early. The actual climb-capable execution remains scoped to the chase action.

5. The hunt branch

The spider has one melee attack profile and a crawl-aware chase action:

var chase = new CrawlToDestinationAction<CortexSpiderEntity, CortexSpiderGoal>(
    CrawlTraversalEvaluator.INSTANCE,
    0.35D,
    1,
    10,
    5
);

Those values currently mean:

  • speed cap: 0.35D
  • arrival radius: 1
  • minimum repath interval: 10 ticks
  • stuck timeout: 5 ticks

That short stuck timeout is intentional in the current example: if the direct execution stalls, the action fails fast so the planner/pathing flow can recover instead of leaving the spider pushing into a bad waypoint for several seconds.

6. CrawlToDestinationAction is now hybrid movement

The original version of this action was mostly "follow every crawl waypoint directly." The current version is more practical: it still follows the AzureCortex path waypoint-by-waypoint, but chooses the movement mode for each waypoint.

Each tick it determines whether the current waypoint is genuinely crawl-related using the crawl/traversal helpers. If it is, and the agent can wall-crawl, the action enables crawling and uses computeWallCrawlVelocity(...). Otherwise it uses its own ground-velocity path.

Conceptually:

var velocity = wallCrawling
    ? NavigationQueries.computeWallCrawlVelocity(agent, waypointCenter, speed)
    : computeGroundVelocity(agent, waypointCenter, speed);

The action then writes that velocity directly, marks the entity as having an impulse, and turns the mob toward its horizontal movement direction.

Facing follows movement

Because this action bypasses vanilla MoveControl, vanilla does not automatically rotate the mob toward the direction it is moving. faceMovementDirection(...) now updates body/head yaw from the horizontal velocity so a crawler no longer moves sideways or backwards while pursuing a target.

Purely vertical movement keeps the previous heading because there is no meaningful horizontal direction to face.

7. Ground fallback and low-step recovery

Crawl-aware A* is necessarily more expensive and has different costs from ordinary ground pathing. Uneven ground, hills, roots, and other mundane terrain can sometimes produce a weaker partial crawl path even though a plain walking route would work well.

For that reason, repathing now follows this pattern:

  1. Try CrawlTraversalEvaluator first, because only it can discover wall/ceiling routes.
  2. If that route is empty or ends too far from the destination, try AStarPathfinder.INSTANCE.
  3. Keep the ground path when it reaches closer to the destination than the crawl path.

This makes the action a crawl-first hybrid rather than a crawler that insists on treating every trip like a wall traversal problem.

Explicit one-block jumping

On ordinary ground waypoints, the action also detects a low obstruction immediately ahead. If the block at foot level is solid while the space above it is clear enough to step onto, the action supplies a jump impulse instead of waiting for a stuck timeout.

The test accounts for the mob's width rather than probing only a single center point. That matters for the spider's wide body: one side can be obstructed even when a narrow center-line probe looks clear.

8. Crawl traversal improvements

The current crawl implementation also includes supporting pathfinding fixes:

  • cling-surface checks include UP, improving ceiling/contact handling;
  • crawl search budget was increased;
  • partial-path selection is no longer rejected merely because the goal is vertically separated;
  • climb-neighbor generation was adjusted to make crawl routes less likely to terminate early;
  • ordinary A* received the same partial-path relaxation so the fallback can still return its best useful partial path.

These are pathfinding-layer changes; no special GOAP states are needed to benefit from them.

9. The entity

CortexSpiderEntity extends vanilla Spider primarily so the example can reuse vanilla's dimensions, attributes, renderer/model/texture, and other normal spider bookkeeping while replacing its decision-making AI.

It implements:

  • CrawlCapability, backed by a CrawlState
  • MovementCapability, for custom passable-solid/hazard rules

The example treats cobwebs as passable-solid and lava as a hazard fluid.

Step height

The current example raises step height:

public static AttributeSupplier.Builder createAttributes() {
    return Spider.createAttributes().add(Attributes.STEP_HEIGHT, 1.5F);
}

@Override
public float maxUpStep() {
    return 1.5F;
}

This helps ordinary terrain traversal, while the action's explicit low-step jump handles the cases where manually applied velocity prevents vanilla step assist from being sufficient on its own.

No custom travel(Vec3) override anymore

Older versions of this walkthrough required CortexSpiderEntity#travel(Vec3) to special-case wall crawling and apply getDeltaMovement() directly. The current example no longer contains that override.

Do not copy the old travel(Vec3) block from older versions of this wiki page into the current example. Movement execution is now handled by the updated crawl action/controller flow instead.

Tick integration

The entity still updates crawl state/controller state around the AzureCortex runtime:

crawlState.tick();
CrawlController.updateWallCrawlingPhysics(this);

if (!level().isClientSide() && isAlive() && !isNoAi()) {
    tickGoalPlanner();
    runtime.tick();
    CrawlController.updateCrawlOrientation(this, getDeltaMovement());
}

The periodic hook keeps DESTINATION synchronized with the current live target while HUNT_TARGET is active.

10. Registration

Registration follows the same pattern as the zombie/skeleton examples:

  • register the entity type and spawn egg;
  • register CortexSpiderEntity.createAttributes();
  • use ordinary ground spawn placement rules;
  • add the spawn egg to the desired creative tab;
  • register vanilla SpiderRenderer::new on the client;
  • provide the language and spawn-egg model resources.

No custom spider art assets are required by the bundled example.

What to take away

  • Decision layer: a crawler does not need crawler-specific goals merely because it can climb.
  • Sensing layer: target predicates can independently reproduce vanilla-like conditions such as nighttime hostility.
  • Pathfinding layer: use CrawlTraversalEvaluator where climbing is genuinely required, but allow a plain A* ground route to win when it is better.
  • Execution layer: crawl and ground waypoints need different velocity handling; the current CrawlToDestinationAction handles both and also supplies facing/step recovery.
  • Capability layer: CrawlCapability + CrawlState expose the synced crawl state while MovementCapability defines terrain-specific rules.
  • Entity integration: the current example no longer needs the old custom travel(Vec3) override.

Next

Clone this wiki locally