我想获取玩家视线所对的生物。于是我使用
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的情况。
谢谢!
厉害我基本都不会这东西的
我想问怎么做的可以教我吗
你们谁可以教我我什么都不会
你们都好厉害但是我不会啊