Skip to content
Benjamin Sommerfeld edited this page Nov 20, 2025 · 2 revisions

The raw output of an A* algorithm is mathematically correct, but aesthetically "meh". It consists of grid coordinates (integers), meaning your entities will move in zig-zag lines and stand exactly in the corner of blocks.

PathUtils is your cosmetic surgeon. It takes a raw path and makes it smooth, centered, or compressed.

[!NOTE] All methods in PathUtils are immutable. They do not modify the original path; they return a new, better one.

Interpolation (Smoothing)

A* thinks in blocks. Real movement happens in curves. interpolate adds intermediate points between the grid nodes. Use this if you render movement client-side and want to avoid the "robot walk" effect.

Path rawPath = result.getPath();

// Insert points so that no two steps are further than 0.5 units apart.
// Turns a 10-step path into a 50-step smooth curve.
Path smoothPath = PathUtils.interpolate(rawPath, 0.5);

Simplification (Compression)

Sometimes you have too much data. If you are sending paths over the network, you don't need every single step on a straight line. simplify throws away points based on an epsilon (sampling density).

// Keep only ~10% of the points (epsilon = 0.1)
// Useful for minimaps or low-bandwidth updates.
Path lightPath = PathUtils.simplify(rawPath, 0.1);

Mutation (Centering)

This is the most critical feature for Minecraft/Voxel games. A* returns block coordinates like (1, 64, 1). If you teleport a zombie there, it stands in the corner of the block. You usually want (1.5, 64, 1.5).

mutatePositions lets you apply a function to every point.

// "Centering" the path
Path centerPath = PathUtils.mutatePositions(rawPath, pos -> {
    return new PathPosition(
        pos.getX() + 0.5,
        pos.getY(),      // Don't change Y (unless you want them floating)
        pos.getZ() + 0.5
    );
});

Surgical Tools (Trim & Join)

Sometimes you need to stitch paths together or cut them short.

  • join(pathA, pathB): Glues two paths together.

  • trim(path, maxLength): Cuts the path off after N steps. Useful if the target is moving and you only want to walk the first few steps before recalculating.

// Walk the first 10 steps, then recalculate
Path shortPath = PathUtils.trim(longPath, 10);

Clone this wiki locally