Ray Tracing

Generically, ray tracing is a method of determining the path of a particle through a coordinate system. In SpongeAPI, this is implemented with the BlockRay class to discover blocks in the path of an arbitrary line in space. A common use case could be to find the block that a Player is looking at.

You can specify the origin of the ray using the BlockRay#from method, passing in either a Location, an Extent and a Vector3d, or an Entity. The method will return a BlockRay.BlockRayBuilder.

小訣竅

If you specify the origin of the ray to be an Entity, the default direction will be the direction in which the Entity is pointing.

To specify the end point, you can use the BlockRay.BlockRayBuilder#to(Vector3d) method, which will set both the direction and ending location. Alternatively, you can specify a direction using BlockRay.BlockRayBuilder#direction(Vector3d) and also a block limit using BlockRay.BlockRayBuilder#blockLimit(int).

備註

The default block limit is 1000 blocks as a safeguard to prevent infinite iteration. To disable the block limit, use a negative value with BlockRayBuilder#blockLimit(int).

Filtering

Filters determine what blocks are accepted by the BlockRay. To add a filter, use the BlockRayBuilder#filter method, passing in one or many Predicate<BlockRayHit<E>>s (where E extends Extent). For convenience, BlockRay contains the following methods for common filter use cases:

  • allFilter: returns a filter accepting all blocks
  • onlyAirFilter: returns a filter accepting only air
  • blockTypeFilter(BlockType): returns a filter accepting only the specified BlockType
  • maxDistanceFilter(Vector3d, double): returns a filter that stops at certain distance from the given Vector3d
  • continueAfterFilter(Predicate<BlockRayHit<E>>, int): returns a filter that continues past the given filter by the specified number of blocks.

Of course, you can also write your own Predicate<BlockRayHit<E>> filter.

Finally, use BlockRay.BlockRayBuilder#build() to finish building the BlockRay. An example usage of BlockRayBuilder to get the first non-air block a Player is looking at is provided below.

import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.util.blockray.BlockRay;
import org.spongepowered.api.world.World;

Player player;
BlockRay<World> blockRay = BlockRay.from(player)
    .filter(BlockRay.continueAfterFilter(BlockRay.onlyAirFilter(), 1)).build();

Using BlockRay

Since BlockRay implements Iterator, you can use such methods as hasNext and next (but not remove) to iterate through the BlockRayHits generated by the BlockRay. Additionally, you can use the BlockRay#reset() method to reset the iterator to the starting location. Rather than iterating through the BlockRayHits, you can also use the BlockRay#end() method to trace the block ray to the end of its path to get the last block accepted by the filter (or none if the block limit was reached).

Using BlockRayHit

BlockRayHit contains information about each block intersected by the ray. It contains the location of the block, the direction of the ray, the coordinates of the intersection of the ray and the block, and other similar data. The following code uses the BlockRay from the previous example to print out the location of the first non-air block in front of the player.

import org.spongepowered.api.util.blockray.BlockRayHit;
import java.util.Optional;

BlockRay<World> blockRay;
Optional<BlockRayHit<World>> hitOpt = blockRay.end();
if (hitOpt.isPresent()) {
    BlockRayHit<World> hit = hitOpt.get();
    System.out.println("Found " + hit.getLocation().getBlockType() + " block at "
        + hit.getLocation() + " with intersection at " + hit.getPosition());
}