예제 #1
0
        protected override void UpdatePosition()
        {
            var potentialX = X + _changeX;
            var potentialY = Y + _changeY;
            var trajectory = GetTrajectory(potentialX, potentialY);

            // Apply collision logic to tiles
            var intersecting = from tile in CurrentLevel.CurrentScreen.Tiles
                               from wall in tile.Boundary
                               let intersection = Geometry.GetIntersection(trajectory, wall)
                                                  where intersection != null
                                                  let distance = Geometry.GetDistance(new Point(potentialX, potentialY), intersection)
                                                                 orderby distance
                                                                 select new { Tile = tile, Wall = wall, intersection, distance };
            var closest = intersecting.FirstOrDefault();

            if (closest != null)
            {
                var wall = closest.Wall;
                var tile = closest.Tile;

                if (Math.Abs(wall.X1 - wall.X2) < FloatTolerance)                                  // vertical wall
                {
                    if (X < wall.X1 && tile.Boundary.All(w => w.X1 >= wall.X1 && w.X2 >= wall.X1)) // ball --> wall
                    {
                        X = wall.X1 - BallRadius;
                    }
                    else if (tile.Boundary.All(w => w.X1 <= wall.X1 && w.X2 <= wall.X1)) // wall <-- ball
                    {
                        X = wall.X1 + BallRadius;
                    }

                    _changeX    = 0;
                    _collisionX = true;
                    _collisionY = false;
                }
                else if (Math.Abs(wall.Y1 - wall.Y2) < FloatTolerance)                             // horizontal wall
                {
                    if (Y < wall.Y1 && tile.Boundary.All(w => w.Y1 >= wall.Y1 && w.Y2 >= wall.Y1)) // ball ^^ wall
                    {
                        Y = wall.Y1 - BallRadius;
                    }
                    else if (tile.Boundary.All(w => w.Y1 <= wall.Y1 && w.Y2 <= wall.Y1))
                    {
                        Y = wall.Y1 + BallRadius;
                    }

                    _changeY    = 0;
                    _collisionX = false;
                    _collisionY = true;
                }
                else // diagonal wall
                {
                    if (wall.Y1 > wall.Y2) // diagonal \
                    {
                        if (tile.Boundary.All(w => w.X1 <= wall.X2 && w.X2 <= wall.X2)) // bottom-left filled in
                        {
                            X += BallRadius;
                            Y += BallRadius;
                        }
                        else // top-right filled in
                        {
                            X -= BallRadius;
                            Y -= BallRadius;
                        }
                    }
                    else if (wall.Y1 < wall.Y2)                                         // diagonal /
                    {
                        if (tile.Boundary.All(w => w.X1 <= wall.X1 && w.X2 <= wall.X1)) // top-left filled in
                        {
                            X += BallRadius;
                            Y -= BallRadius;
                        }
                        else // bottom-right filled in
                        {
                            X -= BallRadius;
                            Y += BallRadius;
                        }
                    }

                    _changeX    = 0;
                    _changeY    = 0;
                    _collisionX = true;
                    _collisionY = true;
                }
            }
            else
            {
                _collisionX = false;
                _collisionY = false;
            }

            // If no collision, move ball normally
            if (!_collisionX)
            {
                X = potentialX;
            }

            if (!_collisionY)
            {
                Y = potentialY;
            }
            else
            {
                _changeX /= Friction;
            }

            // Apply gravity
            if (Math.Abs(_changeY) > 1 || Y < CurrentLevel.ScreenHeight - BallRadius)
            {
                _changeY -= _gravity;
            }

            // If edge of screen hit, switch screens and continue
            Side?side     = null;
            Line boundary = null;

            if (Y >= CurrentLevel.ScreenHeight)
            {
                side     = Side.Top;
                boundary = new Line(0, CurrentLevel.ScreenHeight, CurrentLevel.ScreenWidth, CurrentLevel.ScreenHeight);
            }
            else if (Y <= 0)
            {
                side     = Side.Bottom;
                boundary = new Line(0, 0, CurrentLevel.ScreenWidth, 0);
            }
            else if (X >= CurrentLevel.ScreenWidth)
            {
                side     = Side.Right;
                boundary = new Line(CurrentLevel.ScreenWidth, 0, CurrentLevel.ScreenWidth, CurrentLevel.ScreenHeight);
            }
            else if (X <= 0)
            {
                side     = Side.Left;
                boundary = new Line(0, 0, 0, CurrentLevel.ScreenHeight);
            }

            if (side.HasValue)
            {
                var intersection = Geometry.GetIntersection(trajectory, boundary);
                CurrentLevel.MoveBallToScreen(side.Value);
                CurrentLevel.InitialisePlayerPosition(side.Value, intersection, this);
            }
        }