Ejemplo n.º 1
0
        protected virtual void GenerateCollisionBoxList(IBlockAccessor blockAccessor, double motionX, double motionY, double motionZ, float stepHeight, float yExtra)
        {
            minPos.Set(
                (int)(entityBox.X1 + Math.Min(0, motionX)),
                (int)(entityBox.Y1 + Math.Min(0, motionY) - yExtra), // yExtra for the extra high collision box of fences
                (int)(entityBox.Z1 + Math.Min(0, motionZ))
                );

            double y2 = Math.Max(entityBox.Y1 + stepHeight, entityBox.Y2);

            maxPos.Set(
                (int)(entityBox.X2 + Math.Max(0, motionX)),
                (int)(y2 + Math.Max(0, motionY)),
                (int)(entityBox.Z2 + Math.Max(0, motionZ))
                );

            CollisionBoxList.Clear();
            blockAccessor.WalkBlocks(minPos, maxPos, (block, bpos) => {
                Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccessor, bpos);

                if (collisionBoxes != null)
                {
                    for (int i = 0; i < collisionBoxes.Length; i++)
                    {
                        CollisionBoxList.Add(collisionBoxes[i], bpos, block);
                    }
                }
            }, true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Get all blocks colliding with entityBoxRel
        /// </summary>
        /// <param name="blockAccessor"></param>
        /// <param name="entityBoxRel"></param>
        /// <param name="pos"></param>
        /// <param name="blocks">The found blocks</param>
        /// <param name="alsoCheckTouch"></param>
        /// <returns>If any blocks have been found</returns>
        public bool GetCollidingCollisionBox(IBlockAccessor blockAccessor, Cuboidf entityBoxRel, Vec3d pos, out CachedCuboidList blocks, bool alsoCheckTouch = true)
        {
            blocks = new CachedCuboidList();
            BlockPos blockPos    = new BlockPos();
            Vec3d    blockPosVec = new Vec3d();
            Cuboidd  entityBox   = entityBoxRel.ToDouble().Translate(pos);


            int minX = (int)(entityBoxRel.MinX + pos.X);
            int minY = (int)(entityBoxRel.MinY + pos.Y - 1);  // -1 for the extra high collision box of fences
            int minZ = (int)(entityBoxRel.MinZ + pos.Z);
            int maxX = (int)Math.Ceiling(entityBoxRel.MaxX + pos.X);
            int maxY = (int)Math.Ceiling(entityBoxRel.MaxY + pos.Y);
            int maxZ = (int)Math.Ceiling(entityBoxRel.MaxZ + 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)
                            {
                                blocks.Add(collBox, x, y, z, block);
                            }
                        }
                    }
                }
            }

            return(blocks.Count > 0);
        }
Ejemplo n.º 3
0
        public void ApplyTerrainCollision(Entity entity, EntityPos entitypos, float dtFac, ref Vec3d outposition, float stepHeight = 1)
        {
            IWorldAccessor worldaccess = entity.World;
            Vec3d          pos         = entitypos.XYZ;

            // Full stop when already inside a collisionbox, but allow a small margin of error
            // Disabled. Causes too many issues

            /*(if (blockWhenInside && IsColliding(worldaccess.BlockAccessor, entity.CollisionBox, pos, false))
             * {
             *  entity.CollidedVertically = true;
             *  entity.CollidedVertically = true;
             *  outposition.Set(pos);
             *  return;
             * }*/

            //  entitypos.Motion.X = GameMath.Clamp(entitypos.Motion.X, -1, 1);
            //  entitypos.Motion.Y = GameMath.Clamp(entitypos.Motion.Y, -1, 1);
            //  entitypos.Motion.Z = GameMath.Clamp(entitypos.Motion.Z, -1, 1);

            tmpPositionVec.Set(pos);

            entityBox.Set(
                entity.CollisionBox.X1 + tmpPositionVec.X,
                entity.CollisionBox.Y1 + tmpPositionVec.Y,
                entity.CollisionBox.Z1 + tmpPositionVec.Z,
                entity.CollisionBox.X2 + tmpPositionVec.X,
                entity.CollisionBox.Y2 + tmpPositionVec.Y,
                entity.CollisionBox.Z2 + tmpPositionVec.Z
                );

            CollisionBoxList.Clear();
            outposition.Set(tmpPositionVec.X + entitypos.Motion.X * dtFac, tmpPositionVec.Y + entitypos.Motion.Y * dtFac, tmpPositionVec.Z + entitypos.Motion.Z * dtFac);

            minPos.Set(
                (int)(entityBox.X1 + Math.Min(0, entitypos.Motion.X * dtFac)),
                (int)(entityBox.Y1 + Math.Min(0, entitypos.Motion.Y * dtFac) - 1), // -1 for the extra high collision box of fences
                (int)(entityBox.Z1 + Math.Min(0, entitypos.Motion.Z * dtFac))
                );

            double y2 = Math.Max(entityBox.Y1 + stepHeight, entityBox.Y2);

            maxPos.Set(
                (int)(entityBox.X2 + Math.Max(0, entitypos.Motion.X * dtFac)),
                (int)(y2 + Math.Max(0, entitypos.Motion.Y * dtFac)),
                (int)(entityBox.Z2 + Math.Max(0, entitypos.Motion.Z * dtFac))
                );

            worldaccess.BlockAccessor.WalkBlocks(minPos, maxPos, (block, bpos) => {
                Cuboidf[] collisionBoxes = block.GetCollisionBoxes(worldaccess.BlockAccessor, bpos);

                for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                {
                    CollisionBoxList.Add(collisionBoxes[i], bpos, block);
                }
            }, true);


            tmpPosDelta.Set(entitypos.Motion.X * dtFac, entitypos.Motion.Y * dtFac, entitypos.Motion.Z * dtFac);


            // Y - Collision (Vertical)
            bool collided = false;

            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                tmpPosDelta.Y = CollisionBoxList.cuboids[i].pushOutY(entityBox, tmpPosDelta.Y, ref pushDirection);
                if (pushDirection == EnumPushDirection.None)
                {
                    continue;
                }

                collided = true;

                CollisionBoxList.blocks[i].OnEntityCollide(
                    worldaccess,
                    entity,
                    CollisionBoxList.positions[i],
                    pushDirection == EnumPushDirection.Negative ? BlockFacing.UP : BlockFacing.DOWN,
                    tmpPosDelta,
                    !entity.CollidedVertically
                    );
            }

            entity.CollidedVertically = collided;
            entityBox.Translate(0, tmpPosDelta.Y, 0);


            var horizontalBlocked = false;
            var entityBoxMovedXZ  = entityBox.OffsetCopy(tmpPosDelta.X, 0, tmpPosDelta.Z);

            foreach (var cuboid in CollisionBoxList.cuboids)
            {
                if (cuboid.Intersects(entityBoxMovedXZ))
                {
                    horizontalBlocked = true;
                    break;
                }
            }

            // No collisions for the entity found when testing horizontally, so skip this.
            // This allows entities to move around corners without falling down on a certain axis.
            collided = false;
            if (horizontalBlocked)
            {
                // X - Collision (Horizontal)

                for (int i = 0; i < CollisionBoxList.Count; i++)
                {
                    tmpPosDelta.X = CollisionBoxList.cuboids[i].pushOutX(entityBox, tmpPosDelta.X, ref pushDirection);

                    if (pushDirection == EnumPushDirection.None)
                    {
                        continue;
                    }

                    collided = true;

                    CollisionBoxList.blocks[i].OnEntityCollide(
                        worldaccess,
                        entity,
                        CollisionBoxList.positions[i],
                        pushDirection == EnumPushDirection.Negative ? BlockFacing.EAST : BlockFacing.WEST,
                        tmpPosDelta,
                        !entity.CollidedHorizontally
                        );
                }

                entityBox.Translate(tmpPosDelta.X, 0, 0);

                // Z - Collision (Horizontal)

                for (int i = 0; i < CollisionBoxList.Count; i++)
                {
                    tmpPosDelta.Z = CollisionBoxList.cuboids[i].pushOutZ(entityBox, tmpPosDelta.Z, ref pushDirection);
                    if (pushDirection == EnumPushDirection.None)
                    {
                        continue;
                    }

                    collided = true;

                    CollisionBoxList.blocks[i].OnEntityCollide(
                        worldaccess,
                        entity,
                        CollisionBoxList.positions[i],
                        pushDirection == EnumPushDirection.Negative ? BlockFacing.SOUTH : BlockFacing.NORTH,
                        tmpPosDelta,
                        !entity.CollidedHorizontally
                        );
                }
            }

            entity.CollidedHorizontally = collided;

            //fix for player on ladder clipping into block above issue  (caused by the .CollisionBox not always having height precisely 1.85)
            if (entity.CollidedVertically && tmpPosDelta.Y > 0)
            {
                tmpPosDelta.Y -= entity.LadderFixDelta;
            }

            outposition.Set(tmpPositionVec.X + tmpPosDelta.X, tmpPositionVec.Y + tmpPosDelta.Y, tmpPositionVec.Z + tmpPosDelta.Z);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Updates the velocity vector according to the amount of passed time, gravity and terrain collision.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="motion"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public EnumCollideFlags UpdateMotion(Vec3d pos, Vec3f motion, float size)
        {
            particleCollBox.Set(
                pos.X - size / 2, pos.Y - 0 / 2, pos.Z - size / 2,
                pos.X + size / 2, pos.Y + size / 2, pos.Z + size / 2
                );

            motion.X = GameMath.Clamp(motion.X, -MotionCap, MotionCap);
            motion.Y = GameMath.Clamp(motion.Y, -MotionCap, MotionCap);
            motion.Z = GameMath.Clamp(motion.Z, -MotionCap, MotionCap);

            EnumCollideFlags flags = 0;

            minPos.Set(
                (int)(particleCollBox.X1 + Math.Min(0, motion.X)),
                (int)(particleCollBox.Y1 + Math.Min(0, motion.Y) - 1), // -1 for the extra high collision box of fences
                (int)(particleCollBox.Z1 + Math.Min(0, motion.Z))
                );

            maxPos.Set(
                (int)(particleCollBox.X2 + Math.Max(0, motion.X)),
                (int)(particleCollBox.Y2 + Math.Max(0, motion.Y)),
                (int)(particleCollBox.Z2 + Math.Max(0, motion.Z))
                );

            CollisionBoxList.Clear();
            BlockAccess.WalkBlocks(minPos, maxPos, (cblock, bpos) => {
                Cuboidf[] collisionBoxes = cblock.GetParticleCollisionBoxes(BlockAccess, bpos);

                for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                {
                    CollisionBoxList.Add(collisionBoxes[i], bpos, cblock);
                }
            }, false);


            //  Y - Collision (Vertical)
            EnumPushDirection pushDirection = EnumPushDirection.None;

            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.Y = (float)blockCollBox.pushOutY(particleCollBox, motion.Y, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideY;
                }
            }


            particleCollBox.Translate(0, motion.Y, 0);


            // X - Collision (Horizontal)
            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.X = (float)blockCollBox.pushOutX(particleCollBox, motion.X, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideX;
                }
            }

            particleCollBox.Translate(motion.X, 0, 0);


            // Z - Collision (Horizontal)
            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.Z = (float)blockCollBox.pushOutZ(particleCollBox, motion.Z, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideZ;
                }
            }


            return(flags);
        }