private static bool CollideWithTerrainAABB(int axis, AABB aabb, IWorld world, PhysicMaterial material, float time, ref float velocity, out float movement) { movement = velocity * time; if (movement == 0) { return(false); } Vector3Int start = default; Vector3Int end = default; Vector3Int step = default; if (movement > 0) { for (int i = 0; i < 3; i++) { if (axis == i) { start[i] = Mathf.FloorToInt(aabb.Max[i]); end[i] = Mathf.FloorToInt(aabb.Max[i] + movement); } else { start[i] = Mathf.FloorToInt(aabb.Min[i]); end[i] = Mathf.FloorToInt(aabb.Max[i]); } step[i] = 1; } } else { for (int i = 0; i < 3; i++) { if (axis == i) { end[i] = Mathf.FloorToInt(aabb.Min[i] + movement); step[i] = -1; } else { end[i] = Mathf.FloorToInt(aabb.Max[i]); step[i] = 1; } start[i] = Mathf.FloorToInt(aabb.Min[i]); } } end += step; for (int x = start.x; x != end.x; x += step.x) { for (int z = start.z; z != end.z; z += step.z) { for (int y = start.y; y != end.y; y += step.y) { BlockData block = world.RWAccessor.GetBlock(x, y, z); AABB? blockAABB = block.GetBoundingBox(x, y, z, world, true); if (blockAABB == null) { continue; } AABB blockBB = blockAABB.Value; bool flag = true; for (int i = 0; i < 3; i++) { if (i != axis) { flag &= blockBB.Max[i] > aabb.Min[i] && blockBB.Min[i] < aabb.Max[i]; } } if (!flag) { continue; } if (movement > 0 && aabb.Max[axis] <= blockBB.Min[axis]) { float maxMovement = blockBB.Min[axis] - aabb.Max[axis]; if (movement > maxMovement) { CalculateVelocityAfterCollisionWithTerrain(material, block, ref velocity); movement = maxMovement; return(true); } } else if (movement < 0 && aabb.Min[axis] >= blockBB.Max[axis]) { float maxMovement = blockBB.Max[axis] - aabb.Min[axis]; if (movement < maxMovement) { CalculateVelocityAfterCollisionWithTerrain(material, block, ref velocity); movement = maxMovement; return(true); } } } } } return(false); }
public static CollisionFlags CollideWithTerrainAABB(Vector3 position, AABB aabb, IWorld world, PhysicMaterial material, float time, ref Vector3 velocity, out Vector3 movement) { aabb += position; for (int i = 0; i < 3; i++) { if (Mathf.Abs(velocity[i]) <= Mathf.Epsilon) { velocity[i] = 0; } } CollisionFlags flags = CollisionFlags.None; bool negativeY = velocity.y < 0; movement = default; if (CollideWithTerrainAABB(1, aabb, world, material, time, ref velocity.y, out movement.y)) { flags |= negativeY ? CollisionFlags.Below : CollisionFlags.Above; } aabb += new Vector3(0, movement.y, 0); if (CollideWithTerrainAABB(0, aabb, world, material, time, ref velocity.x, out movement.x)) { flags |= CollisionFlags.Sides; } aabb += new Vector3(movement.x, 0, 0); if (CollideWithTerrainAABB(2, aabb, world, material, time, ref velocity.z, out movement.z)) { flags |= CollisionFlags.Sides; } return(flags); }