Трассировка лучей
В общем случае трассировка лучей является методом определения траектории частицы через систему координат. В SpongeAPI это реализовано с помощью класса BlockRay для обнаружения блоков на пути произвольной линии в пространстве. Частым случаем использования может быть поиск блока, на который смотрит Player.
Вы можете указать источник луча, используя метод BlockRay#from
, передавая либо Location, Extent и Vector3d
, либо Entity. Метод вернёт BlockRay.BlockRayBuilder.
Совет
Если вы указываете начало луча как Entity
, то направление по умолчанию будет направлением, в которое смотрит Entity
.
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
: возвращает фильтр, принимающий все блоки
onlyAirFilter
: возвращает фильтр, принимающий только воздух (air)
blockTypeFilter(BlockType)
: возвращает фильтр, принимающий только указанный BlockType
maxDistanceFilter(Vector3d, double)
: returns a filter that stops at certain distance from the givenVector3d
continueAfterFilter(Predicate<BlockRayHit<E>>, int)
: возвращает фильтр, который продолжает выполняться после фильтра на указанное количество блоков.
Вы также можете написать свой собственный фильтр Predicate<BlockRayHit<E>>
.
Наконец, используйте:javadoc:BlockRay.BlockRayBuilder#build() для завершения построения BlockRay
. Пример использования BlockRayBuilder
для получения первого не пустого блока, на который смотрит Player
, выглядит следующим образом.
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();
Использование BlockRay
Поскольку BlockRay
реализует Iterator
, вы можете использовать такие методы, как hasNext
и next
(но не remove
) для итерации через BlockRayHit сгенерированный с помощью BlockRay
. Кроме того, вы можете использовать метод BlockRay#reset(), чтобы сбросить итератор в исходное положение. Вместо того, чтобы выполнять итерацию через BlockRayHit
, вы также можете использовать метод BlockRay#end() для отслеживания луча до конца его пути и получить последний блок, принятый фильтром (или none, если был достигнут предел блоков).
Использование BlockRayHit
BlockRayHit
содержит информацию о каждом блоке, пересекаемом лучом. Он содержит расположение блока, направление луча, координаты пересечения луча и блока и другие подобные данные. В следующем коде используется BlockRay
из предыдущего примера, чтобы вывести расположение первого блока не воздуха перед игроком.
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());
}