Skip to content
This repository was archived by the owner on Nov 19, 2018. It is now read-only.

Entity Movement And Physics

NSDex edited this page Jul 8, 2016 · 7 revisions

Analysis is based on the decompiled source of the vanilla b1.7.3 client.

Note: Minecraft Entity movement and physics code is a tangled mess. I will need to refer to specific method/variable in order to explain it well. Some of these names are the original MCP names (because I couldn't think of a different one that conveys the same meaning), others I have changed.

Physics

Minecraft lacks a discreet physics system. Gravity, collision, and translation of input into movement are often handled in the same methods as non-physics entity updates such as dealing fire damage when inside of a burning block.

Collision

Collision detection and resolution is primarily handled in the Entity::moveEntity method. Given the entity's current bounding box and a proposed deltaX/Y/Z (translation) for said bounding box, this method determines what blocks or entities exist in the in-between space and modifies the deltaX/Y/Z to avoid a collision. It then translates the entity's current bounding box by the (potentially modified) deltaX/Y/Z thereby moving the entity to its new position.

  1. Create a copy of the entity's current bounding box. Extend this bounding box by the proposed deltaX/Y/Z using the implementation shown below:
BoundingBox::extend(dx, dy, dz)
{
    if dx < 0.0 then
        minimumX := minimumX + dx;
    if dx > 0.0 then
        maximumX := maximumX + dx;
        
    if dy < 0.0 then
        minimumY := minimumY + dy;
    if dy > 0.0 then
        maximumY := maximumY + dy;
        
    if dz < 0.0 then
        minimumZ := minimumZ + dz;
    if dz > 0.0 then
        maximumZ := maximumZ + dz;
}
  1. Collect all potentially colliding bounding boxes from blocks or entities within the extended bounding box from [1]. When searching the world for potentially colliding entities, Notch temporarily expands the query bounding box (from [1]) by 0.25 in all directions. In Minecraft, entities can have both a bounding box and a collision bounding box, though the latter appears to only be used for resolving some implementation issues with Boats and Minecarts. Both of these bounding boxes checked for intersection with the query bounding box.

  2. Iterate over all the bounding boxes from the previous step. For each bounding box, determine whether its distance to the bounding box from [1] along the Y-axis is less than the proposed deltaY using the implementation shown below. If the computed distance is less than the proposed deltaY, reduce deltaY to the computed distance. At the end of this step, deltaY should be equal to the distance to the nearest bound box from the previous step along the Y-axis. Offset the entities bounding box (not the copy) by the final deltaY. Repeat this step for the X-axis and Z-axis in that order.

// NearbyBoundingBox is the bounding box from the current iteration
// QueryBoundingBox is the bounding box from [1].
BoundingBox::calculateYOffset(NearbyBoundingBox, QueryBoundingBox, deltaY)
{
    // Bail out if not within the same X/Z plane.
    if QueryBoundingBox.maxX <= NearbyBoundingBox.minX or QueryBoundingBox.minX >= NearbyBoundingBox.maxX then
        return deltaY
    if QueryBoundingBox.maxZ <= NearbyBoundingBox.minZ or QueryBoundingBox.minZ >= NearbyBoundingBox.maxZ then
        return deltaY
        
    // The entity is moving UP and is currently below NearbyBoundingBox.
    if deltaY > 0 and QueryBoundingBox.maxY <= NearbyBoundingBox.minY then
    {
        let difference := NearbyBoundingBox.minY - QueryBoundingBox.maxY
        
        if difference < deltaY then
            deltaY := difference
    }
    
    // The entity is moving DOWN and is currently above NearbyBoundingBox.
    if deltaY < 0 and QueryBoundingBox.minY >= NearbyBoundingBox.maxY then
    {
        let difference := NearbyBoundingBox.maxY - QueryBoundingBox.minY
        
        if difference > deltaY then
            deltaY := difference
    }
    
    return deltaY
}

Clone this wiki locally