Beispiel #1
0
        internal void CheckWallCollisions(Vector3D moveVector,
                                        ref float halfSizeX, ref float halfSizeY,
                                        ref float[] data)
        {
            if (moveVector.Point2.GetDistanceSquare(_Box.CenterPoint) > CheckDistanceSquare)
             {
            return;
             }

             _CheckDelegate(moveVector, ref halfSizeX, ref halfSizeY, ref data);
        }
Beispiel #2
0
        /// <summary>
        /// Places or removes a block.
        /// </summary>
        /// <param name="place">True to place block</param>
        /// <param name="x">X coordinate of the placed/removed block</param>
        /// <param name="y">Y coordinate of the placed/removed block</param>
        /// <param name="z">Z coordinate of the placed/removed block</param>
        /// <param name="version">Current segment version</param>
        /// <returns>True if block has been placed/removed</returns>
        public bool PlaceOrRemoveBlock(bool place, out int x, out int y, out int z, out uint version)
        {
            x = -1;
             y = -1;
             z = -1;
             version = 0;

             if (!_CanPlaceBlocks)
             {
            return false;
             }

             // check closest intersection
             Point3D eyeLocation = new Point3D(Location, 0.0f, _EyeHeightFromCenter, 0.0f);
             Vector3D line = new Vector3D(eyeLocation, NewDirection);
             Intersection closest = new Intersection();
             List<Tuple<Box, int, int>> boxes = new List<Tuple<Box, int, int>>();

             // first add current segment's boxes which have 0 shift
             foreach (Box box in _CurrentSegment.GetBoxesSynchronized())
             {
            boxes.Add(Tuple.Create(box, 0, 0));
             }
             // now add other boxes and determine possible shift
             foreach (Segment neighbour in _CurrentSegmentNeighbours)
             {
            int shiftX = 0;
            if (_CurrentSegment.X - neighbour.X > WorldHelper.HalfSizeX)
            {
               shiftX = WorldHelper.SizeX;
            }
            else if (neighbour.X - _CurrentSegment.X > WorldHelper.HalfSizeX)
            {
               shiftX = -WorldHelper.SizeX;
            }

            int shiftZ = 0;
            if (_CurrentSegment.Z - neighbour.Z > WorldHelper.HalfSizeZ)
            {
               shiftZ = WorldHelper.SizeZ;
            }
            else if (neighbour.Z - _CurrentSegment.Z > WorldHelper.HalfSizeZ)
            {
               shiftZ = -WorldHelper.SizeZ;
            }

            foreach (Box box in neighbour.GetBoxesSynchronized())
            {
               boxes.Add(Tuple.Create(box, shiftX, shiftZ));
            }
             }

             if (eyeLocation.Y * eyeLocation.Y < BlockInteractionRange)
             {
            boxes.Add(Tuple.Create(Box.FloorBox, 0, 0));
             }

             int reverseShiftX = 0;
             int reverseShiftZ = 0;
             foreach (Tuple<Box, int, int> box in boxes)
             {
            Intersection intersection = box.Item1.GetIntersection(line, box.Item2, box.Item3);
            if (intersection.Distance < closest.Distance)
            {
               closest = intersection;
               reverseShiftX = -box.Item2;
               reverseShiftZ = -box.Item3;
            }
             }

             // check if there is a close intersection at all
             if (closest.IntersectionPoint == null || closest.Distance > BlockInteractionRange)
             {
            // not close enough or no point at all
            return false;
             }

             // adjust the reverse shift by accounting for reverse number truncating
             // when below 0
             if (closest.IntersectionPoint.X < 0 && closest.IntersectionPoint.X % 1 != 0)
             {
            reverseShiftX--;
             }
             if (closest.IntersectionPoint.Z < 0 && closest.IntersectionPoint.Z % 1 != 0)
             {
            reverseShiftZ--;
             }
             // calculate cube location without the shift
             x = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.X)) + reverseShiftX;
             y = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Y));
             z = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Z)) + reverseShiftZ;

             if (place)
             {
            // correct the location based on intersection side
            switch (closest.Side)
            {
               case Sides.FrontX:
                  x--;
                  break;
               case Sides.FrontY:
                  y--;
                  break;
               case Sides.FrontZ:
                  z--;
                  break;
            }
             }
             else
             {
            // correct the location based on intersection side
            switch (closest.Side)
            {
               case Sides.BackX:
                  x--;
                  break;
               case Sides.BackY:
                  y--;
                  break;
               case Sides.BackZ:
                  z--;
                  break;
            }
             }

             // check for floor/ceiling limits
             if (y < 0 || y > byte.MaxValue)
             {
            return false;
             }

             // adjust possible shift over the edge of the world after correction
             if (x < 0)
             {
            x += WorldHelper.SizeX;
             }
             else if (x >= WorldHelper.SizeX)
             {
            x -= WorldHelper.SizeX;
             }

             if (z < 0)
             {
            z += WorldHelper.SizeZ;
             }
             else if (z >= WorldHelper.SizeZ)
             {
            z -= WorldHelper.SizeZ;
             }

             // check if placing the block will clip into an entity
             if (place)
             {
            Box box = new Box(new Cube(x, y, z, 0), null);
            List<Entity> entities = WorldHelper.GetEntities(box.CenterPoint, BlockEntityCollisionSelectRange);

            bool collides = false;
            foreach (Entity entity in entities)
            {
               box.CheckSuffocation(entity.Location, ref entity._HalfSizeX, ref entity._HalfSizeY, ref collides);
               if (collides)
               {
                  // at least one entity collides with the newly placed box
                  return false;
               }
            }
             }

             // retrieve the destination segment and place or remove the block
             Segment destinationSegment = WorldHelper.GetSegment(x, y, z);
             version = destinationSegment.PlaceOrRemoveBlockAndUpdateVersion(place, x, y, z, GetSelectedMaterial());

             return true;
        }
Beispiel #3
0
        /// <summary>
        /// Handles the entity movement in the world.
        /// </summary>
        /// <returns>True if moved</returns>
        public bool HandleMovement()
        {
            bool moved = false;

             if (!_CanMove)
             {
            return moved;
             }

             // calculate movement
             _CurrentTime = Environment.TickCount;
             if (MoveX != 0 || MoveY != 0 || MoveZ != 0)
             {
            moved = true;

            if (_CurrentSegment == null)
            {
               CheckSegmentChanged();
            }

            double distance = (_CurrentTime - _LastMoveTime) * Speed.EntityBaseSpeed;
            Point3D move = new Point3D(MoveX * distance, MoveY * distance, MoveZ * distance);
            move.Rotate(ref _RotationLeft, ref _ZeroUpDownRotation);
            Point3D original = new Point3D(Location);
            Location += move;

            // check collisions and adjust location if needed
            Vector3D moveVector = new Vector3D(original, Location);
            List<Box> boxesForCheck = new List<Box>(_CurrentSegment.GetBoxesSynchronized());
            foreach (Segment neighbour in _CurrentSegmentNeighbours)
            {
               if (neighbour != null)
               {
                  boxesForCheck.AddRange(neighbour.GetBoxesSynchronized());
               }
            }

            // floor/ceiling collisions
            _Falling = true;
            foreach (Box box in boxesForCheck)
            {
               Location.Y += box.CheckFloorCeilingCollisions(moveVector, ref _HalfSizeX,
                                                             ref _HalfSizeY, ref _Falling);
            }
            // world floor/ceiling check
            if (Location.Y - _HalfSizeY < 0.0f)
            {
               Location.Y = _HalfSizeY;
            }
            else if (Location.Y + _HalfSizeY > 255.0f)
            {
               Location.Y = 255.0f - _HalfSizeY;
            }

            // assemble collision walls
            List<CollisionWall> walls = new List<CollisionWall>(_CurrentSegment.GetCollisionWalls());
            foreach (Segment neighbour in _CurrentSegmentNeighbours)
            {
               if (neighbour != null)
               {
                  walls.AddRange(neighbour.GetCollisionWalls());
               }
            }
            // walls.RemoveAll(w => w.GetBoxCenterPointDistanceSquare(Location) > 4.0f);
            // check wall collisions
            float[] xData = new float[] { 512.0f, 0.0f };
            float[] zData = new float[] { 512.0f, 0.0f };
            foreach (CollisionWall wall in walls)
            {
               if (wall.Side == Sides.FrontX || wall.Side == Sides.BackX)
               {
                  wall.CheckWallCollisions(moveVector, ref _HalfSizeX, ref _HalfSizeY, ref xData);
               }
               if (wall.Side == Sides.FrontZ || wall.Side == Sides.BackZ)
               {
                  wall.CheckWallCollisions(moveVector, ref _HalfSizeX, ref _HalfSizeY, ref zData);
               }
            }
            // apply shift based on wall collisons
            Location.X += xData[1];
            Location.Z += zData[1];

            // check suffocation
            _Suffocating = false;
            foreach (Box box in boxesForCheck)
            {
               box.CheckSuffocation(Location, ref _HalfSizeX, ref _HalfSizeY,
                                    ref _Suffocating);
            }

            // check move over map edge
            if (Location.X < 0)
            {
               Location.X += WorldHelper.SizeX;
            }
            else if (Location.X >= WorldHelper.SizeX)
            {
               Location.X -= WorldHelper.SizeX;
            }

            if (Location.Z < 0)
            {
               Location.Z += WorldHelper.SizeZ;
            }
            else if (Location.Z >= WorldHelper.SizeZ)
            {
               Location.Z -= WorldHelper.SizeZ;
            }

            // check if segment changed
            CheckSegmentChanged();
             }

             // calculate new direction
             moved |= HandleRotation();

             // update last moved time
             _LastMoveTime = _CurrentTime;

             return moved;
        }
Beispiel #4
0
        /// <summary>
        /// Gets the line fragment intersection with a triangle (if any).
        /// </summary>
        /// <param name="triangle">Triangle defined by 3 points</param>
        /// <param name="line">Line fragment defined by 2 points</param>
        /// <returns>First item = 0 --> no intersetion; first item = 1 --> one
        /// intersection in the second item; first item = 2 --> line is on the
        /// plane</returns>
        public static Tuple<int, Point3D> GetTriangleIntersection(Tuple<Point3D, Point3D, Point3D> triangle, Vector3D line)
        {
            #if DIAG
             _IntersectCounter++;
            #endif

             Point3D vU1U2 = line.Point2 - line.Point1;
             Point3D vU1P1 = triangle.Item2 - line.Point1;
             Point3D norm = GetPlanesNormal(triangle);

             float lenNormU1U2 = norm.DotProduct(vU1U2);
             float lenNormU1P1 = norm.DotProduct(vU1P1);

             // normala dotProduct usecka  =>  kdyz je to 0, jsou kolme, normala je kolma na plochu, tedy usecka a plocha jsou paralelni
             if (lenNormU1U2.EqEps(0))
             {
            if (lenNormU1P1.EqEps(0))
            {
               // usecka lezi v rovine definovane trojuhelnikem.... detekuj si prunik usecky strojuhelnikem sam :-)
               return Tuple.Create<int, Point3D>(2, null);
            }
            else
            {
               // usecka je paralelni s rovinou, takze nic se nikdy neprotne
               return Tuple.Create<int, Point3D>(0, null);
            }
             }

             // 0 zacatek, 1 konec usecky... uzavreny interval [0;1] == na usecce :-)
             float position = lenNormU1P1 / lenNormU1U2;

             if (0 <= position && position <= 1)
             {
            // ha!, usecka protina rovinu definovanou trojuhelnikem.... ted jen zjistit jestli ten bod je v tom trojuhelniku
            // měla by platit rovnost pro všechny 4 body roviny:
            // NBx = ZjistiNormaluPlochuDefinovanouTremiBodyVole(plocha)
            // NBx.Item1.DotProduct( [ plocha.Item1 ...až plocha.Item3 a bodPruniku] ) == NBx.Item3
            // jestli ne, mám něco blbě, což by nebylo nic zvláštního :)
            Point3D intersection = line.Point1 + vU1U2 * position;
            if (IsPointInTriangle(intersection, triangle))
            {
               return Tuple.Create(1, intersection);
            }
            return Tuple.Create<int, Point3D>(0, null);
             }
             // usecka NEprotina plochu, ale kdybys ji prodlouzil (kdyby to byla primka), tak by rovinu protnula v bode (usecka.Item1 + vU1U2 * pozice)
             return Tuple.Create<int, Point3D>(0, null);
        }
Beispiel #5
0
        /// <summary>
        /// Gets the line fragment intersection with a rectangle (if any).
        /// </summary>
        /// <param name="rectangle">Rectangle defined by 4 points (either in
        /// clockwise or counterclockwise direction)</param>
        /// <param name="line">Line fragment defined by 2 points</param>
        /// <returns>First item = 0 --> no intersetion; first item = 1 --> one
        /// intersection in the second item; first item = 2 --> line is on the
        /// plane</returns>
        public static Tuple<int, Point3D> GetRectangleIntersection(Tuple<Point3D, Point3D, Point3D, Point3D> rectangle, Vector3D line)
        {
            var result = GetTriangleIntersection(Tuple.Create(rectangle.Item1, rectangle.Item2, rectangle.Item3), line);
             if (result.Item1 == 0)
             {
            result = GetTriangleIntersection(Tuple.Create(rectangle.Item1, rectangle.Item4, rectangle.Item3), line);
             }

             return result;
        }
Beispiel #6
0
        public void GetRectangleIntersectionTest()
        {
            Point3D pl1 = new Point3D(-5, 0, -5);
             Point3D pl2 = new Point3D(5, 0, -5);
             Point3D pl3 = new Point3D(5, 0, 5);
             Point3D pl4 = new Point3D(-5, 0, 5);
             var pl = Tuple.Create(pl1, pl2, pl3, pl4);

             // one intersection at [-4; 0; 4]
             Point3D u1 = new Point3D(-4, 2, 4);
             Point3D u2 = new Point3D(-4, -2, 4);
             var u = new Vector3D(u1, u2);

             var result = Point3D.GetRectangleIntersection(pl, u);
             Assert.IsTrue(result.Item1 == 1);
             Assert.AreEqual<Point3D>(result.Item2, new Point3D(-4, 0, 4));

             // one intersection at [-4; 0; 4]
             u1 = new Point3D(-5, 2, 5);
             u2 = new Point3D(-3, -2, 3);
             u = new Vector3D(u1, u2);

             result = Point3D.GetRectangleIntersection(pl, u);
             Assert.IsTrue(result.Item1 == 1);
             Assert.AreEqual<Point3D>(result.Item2, new Point3D(-4, 0, 4));

             // one intersection at [0; 0; 0]
             u1 = new Point3D(0, 2, 0);
             u2 = new Point3D(0, -2, 0);
             u = new Vector3D(u1, u2);

             result = Point3D.GetRectangleIntersection(pl, u);
             Assert.IsTrue(result.Item1 == 1);
             Assert.AreEqual<Point3D>(result.Item2, new Point3D(0, 0, 0));

             // no intersection
             u1 = new Point3D(-4, -1, 4);
             u2 = new Point3D(-4, -2, 4);
             u = new Vector3D(u1, u2);

             result = Point3D.GetRectangleIntersection(pl, u);
             Assert.IsTrue(result.Item1 == 0);
             Assert.IsNull(result.Item2);

             // no intersection
             u1 = new Point3D(-5.5, 2, 5);
             u2 = new Point3D(-5, -2, 5);
             u = new Vector3D(u1, u2);

             result = Point3D.GetRectangleIntersection(pl, u);
             Assert.IsTrue(result.Item1 == 0);
             Assert.IsNull(result.Item2);

             // line is in the plane
             u1 = new Point3D(4, 0, 4);
             u2 = new Point3D(3, 0, 3);
             u = new Vector3D(u1, u2);

             result = Point3D.GetRectangleIntersection(pl, u);
             Assert.IsTrue(result.Item1 == 2);
             Assert.IsNull(result.Item2);
        }
Beispiel #7
0
        private void CheckFrontZCollisions(Vector3D moveVector,
                                         ref float halfSizeX, ref float halfSizeY,
                                         ref float[] data)
        {
            float x1, x2, y1, y2, z1, z2;
             GetPoints(halfSizeX, halfSizeY, out x1, out x2, out y1, out y2, out z1, out z2);

             if (moveVector.Point1.Z > z1)
             {
            return;
             }

             if (_Box.CenterPoint.X - moveVector.Point1.X > WorldHelper.HalfSizeX)
             {
            x1 -= WorldHelper.SizeX;
            x2 -= WorldHelper.SizeX;
             }
             else if (moveVector.Point1.X - _Box.CenterPoint.X > WorldHelper.HalfSizeX)
             {
            x1 += WorldHelper.SizeX;
            x2 += WorldHelper.SizeX;
             }

             Tuple<int, Point3D> result = Point3D.GetRectangleIntersection(Tuple.Create(
            new Point3D(x1, y1, z1),
            new Point3D(x1, y2, z1),
            new Point3D(x2, y2, z1),
            new Point3D(x2, y1, z1)),
            moveVector);
             if (result.Item1 == 1)
             {
            float dist = result.Item2.GetDistanceSquare(moveVector.Point1);
            if (dist < data[0])
            {
               float diff = moveVector.Point2.Z - result.Item2.Z;
               if (diff > ErrorTolerances.FloatEpsilon)
               {
                  data[0] = dist;
                  data[1] = -diff;
               }
            }
             }
        }