예제 #1
0
        public static EnumIntersect AabbIntersect(Cuboidd aabb, Cuboidd aabb2, Vec3d motion)
        {
            bool beforeIntersect = aabb.Intersects(aabb2);

            if (beforeIntersect)
            {
                return(EnumIntersect.Stuck);
            }

            // X
            bool xIntersect =
                aabb.X1 <aabb2.X2 + motion.X &&
                         aabb.Y1 <aabb2.Y2 &&
                                  aabb.Z1 <aabb2.Z2 &&
                                           aabb.X2> aabb2.X1 + motion.X &&
                                  aabb.Y2> aabb2.Y1 &&
                         aabb.Z2> aabb2.Z1
            ;

            if (xIntersect)
            {
                return(EnumIntersect.IntersectX);
            }

            // Y
            bool yIntersect =
                aabb.X1 <aabb2.X2 &&
                         aabb.Y1 <aabb2.Y2 + motion.Y &&
                                  aabb.Z1 <aabb2.Z2 &&
                                           aabb.X2> aabb2.X1 &&
                                  aabb.Y2> aabb2.Y1 + motion.Y &&
                         aabb.Z2> aabb2.Z1
            ;

            if (yIntersect)
            {
                return(EnumIntersect.IntersectY);
            }

            // Z
            bool zIntersect =
                aabb.X1 <aabb2.X2 &&
                         aabb.Y1 <aabb2.Y2 &&
                                  aabb.Z1 <aabb2.Z2 + motion.Z &&
                                           aabb.X2> aabb2.X1 &&
                                  aabb.Y2> aabb2.Y1 &&
                         aabb.Z2> aabb2.Z1 + motion.Z
            ;

            if (zIntersect)
            {
                return(EnumIntersect.IntersectZ);
            }

            return(EnumIntersect.NoIntersect);
        }
예제 #2
0
        public bool RayIntersectsWithCuboid(Cuboidd selectionBox, ref BlockFacing hitOnBlockFace, ref Vec3d hitPosition)
        {
            if (selectionBox == null)
            {
                return(false);
            }

            double w = selectionBox.X2 - selectionBox.X1;
            double h = selectionBox.Y2 - selectionBox.Y1;
            double l = selectionBox.Z2 - selectionBox.Z1;

            for (int i = 0; i < BlockFacing.NumberOfFaces; i++)
            {
                BlockFacing blockSideFacing = BlockFacing.ALLFACES[i];
                Vec3i       planeNormal     = blockSideFacing.Normali;

                // Dot product of 2 vectors
                // If they are parallel the dot product is 1
                // At 90 degrees the dot product is 0
                double demon = planeNormal.X * ray.dir.X + planeNormal.Y * ray.dir.Y + planeNormal.Z * ray.dir.Z;

                // Does intersect this plane somewhere (only negative because we are not interested in the ray leaving a face, negative because the ray points into the cube, the plane normal points away from the cube)
                if (demon < -0.00001)
                {
                    Vec3d planeCenterPosition = blockSideFacing.PlaneCenter
                                                .ToVec3d()
                                                .Mul(w, h, l)
                                                .Add(selectionBox.X1, selectionBox.Y1, selectionBox.Z1)
                    ;

                    Vec3d  pt = Vec3d.Sub(planeCenterPosition, ray.origin);
                    double t  = (pt.X * planeNormal.X + pt.Y * planeNormal.Y + pt.Z * planeNormal.Z) / demon;

                    if (t >= 0)
                    {
                        hitPosition            = new Vec3d(ray.origin.X + ray.dir.X * t, ray.origin.Y + ray.dir.Y * t, ray.origin.Z + ray.dir.Z * t);
                        lastExitedBlockFacePos = Vec3d.Sub(hitPosition, planeCenterPosition);

                        // Does intersect this plane within the block
                        if (Math.Abs(lastExitedBlockFacePos.X) <= w / 2 && Math.Abs(lastExitedBlockFacePos.Y) <= h / 2 && Math.Abs(lastExitedBlockFacePos.Z) <= l / 2)
                        {
                            hitOnBlockFace = blockSideFacing;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
예제 #3
0
        /// <summary>
        /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that.
        /// </summary>
        /// <param name="blockAccessor"></param>
        /// <param name="entityBoxRel"></param>
        /// <param name="pos"></param>
        /// <param name="alsoCheckTouch"></param>
        /// <returns></returns>
        public Cuboidd GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true)
        {
            BlockPos blockPos    = new BlockPos();
            Vec3d    blockPosVec = new Vec3d();
            Cuboidd  entityBox   = entityBoxRel.ToDouble().Translate(pos);

            entityBox.Y1 = Math.Round(entityBox.Y1, 5); // Fix float/double rounding errors. Only need to fix the vertical because gravity.

            int minX = (int)(entityBoxRel.X1 + pos.X);
            int minY = (int)(entityBoxRel.Y1 + pos.Y - 1);  // -1 for the extra high collision box of fences
            int minZ = (int)(entityBoxRel.Z1 + pos.Z);
            int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X);
            int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y);
            int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z);

            for (int y = minY; y <= maxY; y++)
            {
                for (int x = minX; x <= maxX; x++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        Block block = blockAccessor.GetBlock(x, y, z);
                        blockPos.Set(x, y, z);
                        blockPosVec.Set(x, y, z);

                        Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos);

                        for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                        {
                            Cuboidf collBox = collisionBoxes[i];
                            if (collBox == null)
                            {
                                continue;
                            }

                            bool colliding = alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec);
                            if (colliding)
                            {
                                return(collBox.ToDouble().Translate(blockPos));
                            }
                        }
                    }
                }
            }

            return(null);
        }
예제 #4
0
        public Block GetCollidingBlock(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, bool alsoCheckTouch = true)
        {
            Cuboidd entityBox = tmpBox.SetAndTranslate(entityBoxRel, pos);

            int minX = (int)(entityBox.X1);
            int minY = (int)(entityBox.Y1) - 1;  // -1 for the extra high collision box of fences
            int minZ = (int)(entityBox.Z1);

            int maxX = (int)(entityBox.X2);
            int maxY = (int)(entityBox.Y2);
            int maxZ = (int)(entityBox.Z2);

            for (int y = minY; y <= maxY; y++)
            {
                for (int x = minX; x <= maxX; x++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        Block block = blockAccessor.GetBlock(x, y, z);
                        blockPos.Set(x, y, z);

                        Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos);
                        if (collisionBoxes == null || collisionBoxes.Length == 0)
                        {
                            continue;
                        }

                        blockPosVec.Set(x, y, z);
                        for (int i = 0; i < collisionBoxes.Length; i++)
                        {
                            Cuboidf collBox = collisionBoxes[i];
                            if (collBox == null)
                            {
                                continue;
                            }

                            if (alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec))
                            {
                                return(block);
                            }
                        }
                    }
                }
            }

            return(null);
        }
예제 #5
0
        /// <summary>
        /// Tests given cuboidf collides with the terrain. By default also checks if the cuboid is merely touching the terrain, set alsoCheckTouch to disable that.
        /// </summary>
        /// <param name="blockAccessor"></param>
        /// <param name="entityBoxRel"></param>
        /// <param name="pos"></param>
        /// <param name="alsoCheckTouch"></param>
        /// <returns></returns>
        public bool GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, ref Cuboidd intoCubuid, bool alsoCheckTouch = true)
        {
            BlockPos blockPos    = new BlockPos();
            Vec3d    blockPosVec = new Vec3d();
            Cuboidd  entityBox   = entityBoxRel.ToDouble().Translate(pos);

            int minX = (int)(entityBoxRel.X1 + pos.X);
            int minY = (int)(entityBoxRel.Y1 + pos.Y - 1);  // -1 for the extra high collision box of fences
            int minZ = (int)(entityBoxRel.Z1 + pos.Z);
            int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X);
            int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y);
            int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z);

            for (int y = minY; y <= maxY; y++)
            {
                for (int x = minX; x <= maxX; x++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        Block block = blockAccessor.GetBlock(x, y, z);
                        blockPos.Set(x, y, z);
                        blockPosVec.Set(x, y, z);

                        Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, blockPos);

                        for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                        {
                            Cuboidf collBox = collisionBoxes[i];
                            if (collBox == null)
                            {
                                continue;
                            }

                            bool colliding = alsoCheckTouch ? entityBox.IntersectsOrTouches(collBox, blockPosVec) : entityBox.Intersects(collBox, blockPosVec);
                            if (colliding)
                            {
                                intoCubuid.Set(collBox).Translate(blockPos);
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
예제 #6
0
        public static bool RayInteresectWithCuboidSlabMethod(Cuboidd b, Ray r)
        {
            double tx1 = (b.X1 - r.dir.X) / r.dir.X;
            double tx2 = (b.X2 - r.dir.X) / r.dir.X;

            double tmin = Math.Min(tx1, tx2);
            double tmax = Math.Max(tx1, tx2);

            double ty1 = (b.Y1 - r.dir.Y) / r.dir.Y;
            double ty2 = (b.Y2 - r.dir.Y) / r.dir.Y;

            tmin = Math.Max(tmin, Math.Min(ty1, ty2));
            tmax = Math.Min(tmax, Math.Max(ty1, ty2));

            double tz1 = (b.Z1 - r.dir.Z) / r.dir.Z;
            double tz2 = (b.Z2 - r.dir.Z) / r.dir.Z;

            tmin = Math.Max(tmin, Math.Min(tz1, tz2));
            tmax = Math.Min(tmax, Math.Max(tz1, tz2));

            return(tmax >= tmin);
        }