我想获取玩家视线所对的生物。于是我使用
World.rayTraceResult()
于是我将它单独写到一个类里面。
复制代码
之后,我就调用这个方法。但是,会出现一个BUG。
当你离生物体太近,会出现
hit到东西了,但返回的是null
我以为是bukkit自带的BUG,于是我就再写了一次。
复制代码
但是,无论你靠得多近,返回的都是实体,并没有出现 hit到东西了,返回null的情况。
注:这里的返回null是指 result 是 null 的,但判断时,result却不是null。
World.rayTraceResult()
于是我将它单独写到一个类里面。
- public Entity getEntity(){
- result = this.player.getWorld().rayTraceEntities(this.playerEye.add(this.playerEyeDirection) ,
- this.playerEyeDirection , 20.0);
- if (result != null){ // Hit到东西了
- if (result.getHitBlock() != null){ // Hit到方块了
- if (this.blockDistanceIsFarther(result.getHitBlock().getLocation() ,
- Objects.requireNonNull(result.getHitEntity()).getLocation() , this.playerEye)){ // 方块距离比较远吗?
- return result.getHitEntity();
- } else {
- if (this.whetherItIsVisualSquare(result.getHitBlock().getType())){ //是否是透明方块
- return result.getHitEntity();
- }
- }
- return null;
- }
- return result.getHitEntity(); // 只Hit到实体
- }
- return null; // 没Hit到东西
- }
之后,我就调用这个方法。但是,会出现一个BUG。
当你离生物体太近,会出现
hit到东西了,但返回的是null
我以为是bukkit自带的BUG,于是我就再写了一次。
- RayTraceResult result = player.getWorld().rayTraceEntities(player.getEyeLocation().add(player.getEyeLocation().getDirection()) ,
- player.getEyeLocation().getDirection() , 20.0);
- if (result != null){
- player.sendMessage(result.getHitEntity().toString());
- }
但是,无论你靠得多近,返回的都是实体,并没有出现 hit到东西了,返回null的情况。
注:这里的返回null是指 result 是 null 的,但判断时,result却不是null。
之前帖子里的这个代码使用会出现问题吗复制代码
- Player player;
- World world = player.getWorld();
- Location location = player.getEyeLocation();
- Vector direction = location.getDirection();
- location.add(direction);
- RayTraceResult rayTraceEntities = world.rayTraceEntities(location, location.getDirection(), 10.0D);
- Entity hitEntity = rayTraceEntities.getHitEntity();
本帖最后由 结冰的离季 于 2021-7-23 19:06 编辑
你要知道为什么我用的是rayTraceEntities,因为他只会检查实体,同样rayTraceBlocks只会检查方块,但你的代码中使用了rayTraceEntities但还执行result.getHitBlock()得到的结果肯定不对。要同时检查block和entity的话应该用rayTrace。
至于太近的问题,还是起始位置的关系,玩家眼睛位置是位于头部中心,如果从玩家眼部位置为起始点的话,有可能第一个结果就是玩家本身,正好direction是一个单位向量,我把eyelocation加上direction之后就刚好是玩家前面一个方块的位置,但是玩家的头部的长度一半是小于一个方块的长度的,所以如果太近的话起始点并没有接触到实体,是有可能为null的。
以下是CraftBukkit的代码实现。点击查看
复制代码
通过查看CraftBukkit的源代码可以知道,他的原理还是getNearbyEntities 然后进行逐个判断,所以他的检查顺序并不是从这条光线的起始位置开始,而是getNearbyEntities返回集合中的第一个结果,而根据我的经验,getNearbyEntities中的第一个Entity永远是最新生成的实体,这就是导致了我们的结果不同的原因。
同时通过这个代码可知,rayTraceEntities 中的 RayTraceResult 的gethitBlock是没有经过初始化的
你要知道为什么我用的是rayTraceEntities,因为他只会检查实体,同样rayTraceBlocks只会检查方块,但你的代码中使用了rayTraceEntities但还执行result.getHitBlock()得到的结果肯定不对。要同时检查block和entity的话应该用rayTrace。
至于太近的问题,还是起始位置的关系,玩家眼睛位置是位于头部中心,如果从玩家眼部位置为起始点的话,有可能第一个结果就是玩家本身,正好direction是一个单位向量,我把eyelocation加上direction之后就刚好是玩家前面一个方块的位置,但是玩家的头部的长度一半是小于一个方块的长度的,所以如果太近的话起始点并没有接触到实体,是有可能为null的。
以下是CraftBukkit的代码实现。点击查看
- @Override
- public RayTraceResult rayTraceEntities(Location start, Vector direction, double maxDistance, double raySize, Predicate<Entity> filter) {
- Validate.notNull(start, "Start location is null!");
- Validate.isTrue(this.equals(start.getWorld()), "Start location is from different world!");
- start.checkFinite();
- Validate.notNull(direction, "Direction is null!");
- direction.checkFinite();
- Validate.isTrue(direction.lengthSquared() > 0, "Direction's magnitude is 0!");
- if (maxDistance < 0.0D) {
- return null;
- }
- Vector startPos = start.toVector();
- Vector dir = direction.clone().normalize().multiply(maxDistance);
- BoundingBox aabb = BoundingBox.of(startPos, startPos).expandDirectional(dir).expand(raySize);
- Collection<Entity> entities = this.getNearbyEntities(aabb, filter);
- Entity nearestHitEntity = null;
- RayTraceResult nearestHitResult = null;
- double nearestDistanceSq = Double.MAX_VALUE;
- for (Entity entity : entities) {
- BoundingBox boundingBox = entity.getBoundingBox().expand(raySize);
- RayTraceResult hitResult = boundingBox.rayTrace(startPos, direction, maxDistance);
- if (hitResult != null) {
- double distanceSq = startPos.distanceSquared(hitResult.getHitPosition());
- if (distanceSq < nearestDistanceSq) {
- nearestHitEntity = entity;
- nearestHitResult = hitResult;
- nearestDistanceSq = distanceSq;
- }
- }
- }
- return (nearestHitEntity == null) ? null : new RayTraceResult(nearestHitResult.getHitPosition(), nearestHitEntity, nearestHitResult.getHitBlockFace());
- }
通过查看CraftBukkit的源代码可以知道,他的原理还是getNearbyEntities 然后进行逐个判断,所以他的检查顺序并不是从这条光线的起始位置开始,而是getNearbyEntities返回集合中的第一个结果,而根据我的经验,getNearbyEntities中的第一个Entity永远是最新生成的实体,这就是导致了我们的结果不同的原因。
同时通过这个代码可知,rayTraceEntities 中的 RayTraceResult 的gethitBlock是没有经过初始化的
结冰的离季 发表于 2021-7-23 18:36
你要知道为什么我用的是rayTraceEntities,因为他只会检查实体,同样rayTraceBlocks只会检查方块,但你的代 ...
前辈,我明白了。
难怪他会出现明明已经不是null了,却在执行时返回null的情况。
谢谢!
厉害我基本都不会这东西的
我想问怎么做的可以教我吗
你们谁可以教我我什么都不会
你们都好厉害但是我不会啊