Skip to main content

Overview

Movement utilities provide functions for calculating movement angles, directional input, edge detection, and velocity manipulation.

Key Functions

getDegreesRelativeToView

Calculates the yaw angle difference between the player’s view and a target position.
fun getDegreesRelativeToView(
    positionRelativeToPlayer: Vec3,
    yaw: Float = RotationManager.currentRotation?.yaw ?: player.yRot
): Float
Parameters:
  • positionRelativeToPlayer - Relative position to the player
  • yaw - Reference yaw angle (defaults to current rotation)
Returns: Angle in degrees (-180 to 180) Example:
val targetPos = target.position().subtract(player.position())
val degrees = getDegreesRelativeToView(targetPos)

if (abs(degrees) < 45f) {
    // Target is in front of player
}

getDirectionalInputForDegrees

Converts an angle to directional input (forward/back/left/right).
fun getDirectionalInputForDegrees(
    directionalInput: DirectionalInput,
    dgs: Float,
    deadAngle: Float = 20.0F
): DirectionalInput
Parameters:
  • directionalInput - Current directional input
  • dgs - Degrees relative to view
  • deadAngle - Dead zone angle (default 20°)
Returns: Modified DirectionalInput with appropriate directions Example:
val targetDegrees = getDegreesRelativeToView(targetRelativePos)
val newInput = getDirectionalInputForDegrees(
    directionalInput = DirectionalInput.NONE,
    dgs = targetDegrees
)

// newInput now has correct forward/back/left/right for moving toward target

findEdgeCollision

Detects collision with edges while moving from one position to another.
fun findEdgeCollision(
    from: Vec3,
    to: Vec3,
    allowedDropDown: Float = 0.5F
): Vec3?
Parameters:
  • from - Starting position
  • to - Target position
  • allowedDropDown - How far player can drop (blocks)
Returns: Position where edge collision occurs, or null if path is safe Example:
val currentPos = player.position()
val targetPos = currentPos.add(moveVector)

val edgePos = findEdgeCollision(currentPos, targetPos)

if (edgePos != null) {
    // Would fall off edge at edgePos
    // Stop or change direction
}

stopXZVelocity

Stops horizontal velocity while preserving vertical velocity.
fun LocalPlayer.stopXZVelocity()
Example:
player.stopXZVelocity()
// Player stops moving horizontally but continues falling/jumping

DirectionalInput

Represents keyboard movement input.
data class DirectionalInput(
    val forwards: Boolean,
    val backwards: Boolean,
    val left: Boolean,
    val right: Boolean
)

Common Patterns

// No movement
val noInput = DirectionalInput(false, false, false, false)

// Move forward
val forwardInput = DirectionalInput(true, false, false, false)

// Strafe right
val strafeRight = DirectionalInput(false, false, false, true)

// Forward + right (diagonal)
val diagonalInput = DirectionalInput(true, false, false, true)

Movement Calculations

Strafe Movement

Moving in a direction while looking elsewhere:
val handler = handler<MovementInputEvent> { event ->
    val targetPos = target.position().subtract(player.position())
    val degrees = getDegreesRelativeToView(targetPos)
    
    // Calculate input to move toward target
    event.directionalInput = getDirectionalInputForDegrees(
        directionalInput = event.directionalInput,
        dgs = degrees
    )
}

Safe Walk Implementation

val safeWalkHandler = handler<PlayerMoveEvent> { event ->
    val currentPos = player.position()
    val nextPos = currentPos.add(event.movement)
    
    val wouldFall = findEdgeCollision(
        from = currentPos,
        to = nextPos,
        allowedDropDown = 0.5f
    )
    
    if (wouldFall != null) {
        // Stop movement to prevent falling
        event.movement = Vec3.ZERO
    }
}

Speed Calculation

fun getSpeed(): Double {
    val dx = player.x - player.xOld
    val dz = player.z - player.zOld
    return sqrt(dx * dx + dz * dz)
}

Direction Angle

fun getMovementDirection(): Float {
    var yaw = player.yRot
    
    if (player.input.left) yaw -= 90f
    if (player.input.right) yaw += 90f
    
    if (player.input.backwards) yaw += 180f
    if (player.input.left && player.input.backwards) yaw += 45f
    if (player.input.right && player.input.backwards) yaw -= 45f
    
    return yaw
}

Velocity Manipulation

Setting Velocity

// Set horizontal velocity
player.deltaMovement = Vec3(
    x = sin(-yaw.toRadians()) * speed,
    y = player.deltaMovement.y,
    z = cos(-yaw.toRadians()) * speed
)

Boost Velocity

fun boost(multiplier: Double) {
    player.deltaMovement = player.deltaMovement.multiply(
        multiplier,
        1.0,  // Don't affect Y velocity
        multiplier
    )
}

Jump Boost

val jumpHandler = handler<PlayerJumpEvent> { event ->
    // Increase jump height
    event.motion *= 1.2f
}

Movement Events

MovementInputEvent

Modify movement input before processing:
val inputHandler = handler<MovementInputEvent> { event ->
    // Force forward movement
    event.directionalInput = DirectionalInput(
        forwards = true,
        backwards = false,
        left = false,
        right = false
    )
}

PlayerMoveEvent

Modify movement vector:
val moveHandler = handler<PlayerMoveEvent> { event ->
    // Double movement speed
    event.movement = event.movement.scale(2.0)
}

PlayerVelocityStrafe

Modify strafe velocity:
val strafeHandler = handler<PlayerVelocityStrafe> { event ->
    // Custom strafe calculation
    val customYaw = RotationManager.currentRotation?.yaw ?: player.yRot
    
    event.velocity = Entity.getInputVector(
        event.movementInput,
        event.speed,
        customYaw
    )
}

PlayerStepEvent

Modify step height:
val stepHandler = handler<PlayerStepEvent> { event ->
    // Increase step height to 1 block
    event.height = 1.0f
}

Advanced Examples

Scaffold Walk Pattern

val scaffoldHandler = handler<PlayerMoveEvent> { event ->
    val belowPos = player.blockPosition().below()
    val isAir = world.getBlockState(belowPos).isAir
    
    if (isAir) {
        // Check if movement would cause fall
        val nextPos = player.position().add(event.movement)
        val edge = findEdgeCollision(
            player.position(),
            nextPos,
            allowedDropDown = 0.1f
        )
        
        if (edge != null) {
            // Slow down at edges
            event.movement = event.movement.scale(0.3)
        }
    }
}

Sprint in All Directions

val handler = handler<MovementInputEvent> { event ->
    if (event.directionalInput.backwards ||
        event.directionalInput.left ||
        event.directionalInput.right) {
        // Convert any movement to forward for sprint speed
        event.directionalInput = DirectionalInput(
            forwards = true,
            backwards = false,
            left = false,
            right = false
        )
    }
}

Auto-Jump

val jumpHandler = handler<GameTickEvent> {
    if (player.horizontalCollision && player.onGround()) {
        player.jumpFromGround()
    }
}

Best Practices

Use findEdgeCollision for safe walk implementations to prevent falling off blocks.
Manipulating velocity directly can conflict with other movement modules. Use events when possible.
Movement calculations should account for rotation differences when using silent aim or rotation modifications.

See Also

Build docs developers (and LLMs) love