public Grid(IEnumerable <GamePiece> tiles, Vector2u gridSize, Vector2f scale, uint gridLayers = 1, DragManager mouseManager = null, int dragLayer = -1, int dropLayer = -1, Vector2f dropScale = default, Vector2u cellSize = default)
        {
            if (dropScale == default)
            {
                dropScale = scale;
            }

            window = mouseManager.Window;
            if (tiles == null)
            {
                this.tiles = new List <GamePiece>();
            }
            else
            {
                this.tiles = tiles.ToList();
            }
            this.mapSize = gridSize;
            this.scale   = scale;
            mapLayers    = gridLayers;
            map          = new int[gridSize.X, gridSize.Y, gridLayers];
            if (cellSize == default)
            {
                tileSize = this.tiles[0].TextureRect.GetSize().ToVector2f();
            }
            else
            {
                tileSize = (Vector2f)cellSize;
            }

            // apply scale to tiles
            for (var i = 0; i < this.tiles.Count; i++)
            {
                this.tiles[i].Scale = scale;
            }

            size           = new Vector2f(gridSize.X * tileSize.X, gridSize.Y * tileSize.Y);
            scaledSize     = new Vector2f(Size.X * scale.X, Size.Y * scale.Y);
            scaledTileSize = new Vector2f(tileSize.X * scale.X, tileSize.Y * scale.Y);

            // init map
            for (var z = 0; z < mapLayers; z++)
            {
                for (var y = 0; y < mapSize.Y; y++)
                {
                    for (var x = 0; x < mapSize.X; x++)
                    {
                        map[x, y, z] = -1;
                    }
                }
            }

            // mouse
            if (mouseManager != null)
            {
                if (dragLayer != -1)
                {
                    GamePiece       picked      = null;
                    int             pickedIndex = -1;
                    Action <Sprite> dropHandled = null;
                    Vector2f        dragOffset  = default;
                    Vector2i        pickCoords  = default;

                    mouseManager.DragStart += (object sender, DragEventArgs e) =>
                    {
                        if (Enabled)
                        {
                            if (e.Button == Mouse.Button.Left &&
                                e.DragStart.X >= Rect.Left &&
                                e.DragStart.Y >= Rect.Top &&
                                e.DragStart.X < Rect.Left + Rect.Width &&
                                e.DragStart.Y < Rect.Top + Rect.Height)
                            {
                                picked = SpritePicker(e.DragStart, dragLayer, out pickCoords);

                                if (picked != null)
                                {
                                    moves         = GetMoves(picked, pickCoords);
                                    movesOccupied = GetMovesOccupied(picked, pickCoords);
                                    Debug.WriteLine($"[Grid] Picked {pickCoords.X},{pickCoords.Y}");

                                    pickedIndex = map[pickCoords.X, pickCoords.Y, dragLayer];
                                    dropHandled = sprite =>
                                    {
                                        //map[pickCoords.X, pickCoords.Y, dragLayer] = -1;
                                    };
                                    picked.Color         = new Color(255, 255, 255, 0);
                                    draggingSprite       = new GamePiece(picked);
                                    draggingSprite.Color = new Color(255, 255, 255, 200);
                                    dragOffset           = (e.DragStart.ToVector2f() - draggingSprite.Position) * -1;

                                    // empty origial area
                                    var subgridSize = getSubGridSizeOfTile(picked);
                                    for (var y = 0; y < subgridSize.Y; y++)
                                    {
                                        for (var x = 0; x < subgridSize.X; x++)
                                        {
                                            map[pickCoords.X + x, pickCoords.Y + y, dragLayer] = -1;
                                        }
                                    }
                                }
                            }
                        }
                    };
                    mouseManager.Dragging += (object sender, DragEventArgs e) =>
                    {
                        if (Enabled && draggingSprite != null)
                        {
                            var dp = e.DragCurrent.ToVector2f();
                            draggingSprite.Position = dp + dragOffset;
                        }
                    };
                    mouseManager.DragEnd += (object sender, DragEventArgs e) =>
                    {
                        if (Enabled)
                        {
                            if (picked != null)
                            {
                                picked.Color  = new Color(255, 255, 255, 255);
                                picked        = null;
                                moves         = null;
                                movesOccupied = null;
                            }
                            if (draggingSprite != null)
                            {
                                if (!mouseManager.Drop(this, draggingSprite, dropHandled, e))
                                {
                                    // if the drop was unhandled, restore the item to its original location
                                    var subgridSize = getSubGridSizeOfTile(draggingSprite);
                                    if (subgridSize.X > 1 || subgridSize.Y > 1)
                                    {
                                        for (var y = 0; y < subgridSize.Y; y++)
                                        {
                                            for (var x = 0; x < subgridSize.X; x++)
                                            {
                                                map[pickCoords.X + x, pickCoords.Y + y, dropLayer] = pickedIndex - int.MinValue;
                                            }
                                        }
                                    }
                                    map[pickCoords.X, pickCoords.Y, dropLayer] = pickedIndex;
                                }
                                draggingSprite = null;
                            }
                        }
                    };
                }
                if (dropLayer != -1)
                {
                    mouseManager.Dropped += (object sender, DropEventArgs e) =>
                    {
                        if (Enabled)
                        {
                            if (e.DragStop.X >= Rect.Left && e.DragStop.Y >= Rect.Top &&
                                e.DragStop.X < Rect.Left + Rect.Width &&
                                e.DragStop.Y < Rect.Top + Rect.Height)
                            {
                                var p = e.Sprite.GetGlobalBounds().GetCenter().ToVector2i()
                                        + new Vector2i(0, 32); // move the drop point down so it is centered on the base of the chess piece
                                                               //var p = (Vector2i)(e.Sprite.Position + (cellSize.ToVector2f() / 2.0f));
                                var tpi = ScreenToGridCoordinates(p);
                                Debug.WriteLine($"[Grid] Dropped {tpi.X},{tpi.Y}");

                                var subgridSize = getSubGridSizeOfTile(e.Sprite);
                                if (tpi.X >= 0 && tpi.X + (subgridSize.X - 1) < mapSize.X && tpi.Y >= 0 && tpi.Y + (subgridSize.Y - 1) < mapSize.Y)
                                {
                                    var obstacleFound = false;

                                    /*
                                     * for (var y=tpi.Y; y<tpi.Y+subgridSize.Y; y++){
                                     *  for (var x=tpi.X; x<tpi.X+subgridSize.X; x++){
                                     *      if (map[x, y, dropLayer] != -1){
                                     *          obstacleFound=true;
                                     *          break;
                                     *      }
                                     *  }
                                     * }
                                     */

                                    // check if move is valid according to board state
                                    if (!obstacleFound)
                                    {
                                        obstacleFound = !IsMoveAllowed(e.Sprite, ScreenToGridCoordinates(e.DragStart), tpi);
                                    }
                                    //var index = map[tpi.X, tpi.Y, dropLayer];
                                    //if (index == -1)
                                    if (!obstacleFound)
                                    {
                                        e.Sprite.Color = new Color(255, 255, 255, 255);
                                        if (!this.tiles.Contains(e.Sprite))
                                        {
                                            this.tiles.Add(e.Sprite);
                                        }

                                        var tileIndex = this.tiles.IndexOf(e.Sprite);

                                        // if this item is larger than 1x1 fill the other grid cells with "shadow" indeces
                                        // so that items will not be able to overlap

                                        if (subgridSize.X > 1 || subgridSize.Y > 1)
                                        {
                                            for (var y = 0; y < subgridSize.Y; y++)
                                            {
                                                for (var x = 0; x < subgridSize.X; x++)
                                                {
                                                    map[tpi.X + x, tpi.Y + y, dropLayer] = tileIndex - int.MinValue;
                                                }
                                            }
                                        }

                                        map[tpi.X, tpi.Y, dropLayer] = tileIndex;

                                        e.Sprite.Scale = dropScale;
                                        if (e.OnHandled != null)
                                        {
                                            e.OnHandled.Invoke(e.Sprite);
                                            e.Handled = true;
                                            OnMoved();
                                        }
                                    }
                                }
                            }
                        }
                    };
                }
            }

            moveMarker = new CircleShape(13);
            moveMarker.OutlineThickness = 1;
            moveMarker.FillColor        = new Color(0, 0, 0, 64);
            moveMarker.OutlineColor     = new Color(0, 0, 0, 32);
            moveMarker.Origin           = moveMarker.GetGlobalBounds().GetCenter();

            moveMarkerOccupied                  = new CircleShape(24);
            moveMarkerOccupied.FillColor        = new Color(0, 0, 0, 0);
            moveMarkerOccupied.OutlineThickness = 6;
            moveMarkerOccupied.OutlineColor     = new Color(0, 0, 0, 64);
            moveMarkerOccupied.Origin           = moveMarkerOccupied.GetGlobalBounds().GetCenter();
        }
Example #2
0
        static void Main(string[] args)
        {
            //perfTest();return;

            var appStartTime = DateTime.Now;

            RenderWindow window = new RenderWindow(new VideoMode(768, 768), "Derpy Chess");

            window.SetFramerateLimit(40);
            window.SetActive();
            window.Closed += (object sender, EventArgs e) => window.Close();

            var parchment        = FileSystem.LoadSprite("./data/parchment.png");
            var backgroundSprite = FileSystem.LoadSprite("./data/background_512x512.png");
            var vignette         = FileSystem.LoadSprite("./data/vignette_512x512.png");
            var mouseManager     = new DragManager(window);
            var storybookFont    = FileSystem.LoadFont("./data/storybook.ttf");
            var oldenglishFont   = FileSystem.LoadFont("./data/oldenglish.ttf");
            var boardSprite      = FileSystem.LoadSprite("./data/board_512x552.png");
            var blackSprites     = FileSystem.LoadTiles("./data/black2_128x128.png", 128, 128);
            var whiteSprites     = FileSystem.LoadTiles("./data/white3_128x128.png", 128, 128);

            var       pixelFont     = FileSystem.LoadFont("./data/rainyhearts.ttf");
            GameBoard board         = new GameBoard(boardSprite, blackSprites, whiteSprites, pixelFont, new Vector2f(), new Vector2u(8, 8), new Vector2f(1, 1), 1, mouseManager, 0, 0, new Vector2f(1, 1), new Vector2u(64, 64));;
            var       busyIndicator = new BusyIndicator();

            var resize = new Action <float, float>((float width, float height) =>
            {
                window.SetView(new View(new FloatRect(0, 0, width, height)));
                vignette.Scale         = window.Size.ToVector2f().Div(vignette.TextureRect.GetSize().ToVector2f());
                board.Position         = ((window.Size.ToVector2f() * 0.5f) - (boardSprite.TextureRect.GetSize().ToVector2f() * 0.5f)) + new Vector2f(0, 16);
                parchment.Position     = (window.Size.ToVector2f() * 0.5f) - (parchment.TextureRect.GetSize().ToVector2f() * 0.5f);
                busyIndicator.Position = new Vector2f(window.Size.X / 2, board.Position.Y - 72);
            });

            resize(window.Size.X, window.Size.Y);
            window.Resized += (object sender, SizeEventArgs e) => resize(e.Width, e.Height);


            // --- logo -----------
            var logo = FileSystem.LoadSprite("./data/retrodactyl_logo.png");

            logo.Scale    = new Vector2f(2, 2);
            logo.Origin   = logo.TextureRect.GetSize().ToVector2f() * 0.5f;
            logo.Position = window.Size.ToVector2f() * 0.5f - new Vector2f(0, 25);
            logo.Color    = new Color(255, 255, 255, 0);
            var      viewingLogo   = true;
            var      logoFade      = false;
            DateTime logoFadeStart = DateTime.MaxValue;

            while (window.IsOpen && viewingLogo)
            {
                window.Clear(new Color(0xe5f1fdff));
                window.DispatchEvents();
                logo.Draw(window, RenderStates.Default);
                window.Display();

                if ((Keyboard.IsKeyPressed(Keyboard.Key.Enter) || Keyboard.IsKeyPressed(Keyboard.Key.Space) || Mouse.IsButtonPressed(Mouse.Button.Left)))
                {
                    logoFade      = true;
                    logoFadeStart = DateTime.MinValue;
                }

                if (logoFade && logoFadeStart < DateTime.Now)
                {
                    logo.Color -= new Color(0, 0, 0, 5);
                    if (logo.Color.A < 1)
                    {
                        viewingLogo = false;
                    }
                }

                if (!logoFade)
                {
                    logo.Color += new Color(0, 0, 0, 5);
                    if (logo.Color.A >= 254)
                    {
                        logoFadeStart = DateTime.Now + TimeSpan.FromSeconds(2);
                        logoFade      = true;
                    }
                }
            }

            // ---- story ---------------------------------------------------------------------------------------

            /*
             * var storybookText = new Text();
             * storybookText.Font = oldenglishFont;
             * storybookText.FillColor = new Color(48,32,32, 200);
             * storybookText.OutlineColor = new Color(48, 32, 32, 64);
             * storybookText.OutlineThickness = 1;
             * storybookText.CharacterSize = 48;
             * storybookText.DisplayedString =
             *  "Once upon a time," + Environment.NewLine +
             *  "there was a dude who" + Environment.NewLine +
             *  "liked to play chess but" + Environment.NewLine +
             *  "really sucked at it..." + Environment.NewLine + Environment.NewLine +
             *  "He never enjoyed chess" + Environment.NewLine +
             *  "because he never won." + Environment.NewLine + Environment.NewLine +
             *  "This game is dedicated" + Environment.NewLine +
             *  "to that guy.";
             *
             * storybookText.Position = parchment.Position + new Vector2f(80,64);
             *
             * bool viewingStory = true;
             * bool storyFade = false;
             * while (window.IsOpen && viewingStory)
             * {
             *  window.Clear();
             *  window.DispatchEvents();
             *
             *  for (var y = 0; y < window.Size.Y; y += backgroundSprite.TextureRect.Height)
             *  {
             *      for (var x = 0; x < window.Size.X; x += backgroundSprite.TextureRect.Width)
             *      {
             *          backgroundSprite.Position = new Vector2f(x, y);
             *          backgroundSprite.Draw(window, RenderStates.Default);
             *      }
             *  }
             *  vignette.Draw(window, RenderStates.Default);
             *  parchment.Draw(window, RenderStates.Default);
             *  storybookText.Draw(window, RenderStates.Default);
             *  window.Display();
             *
             *  if ((Keyboard.IsKeyPressed(Keyboard.Key.Enter) || Keyboard.IsKeyPressed(Keyboard.Key.Space) || Mouse.IsButtonPressed(Mouse.Button.Left)))
             *  {
             *      storyFade = true;
             *  }
             *  if (storyFade) {
             *      parchment.Color -= new Color(0, 0, 0, 3);
             *      storybookText.FillColor -= new Color(0, 0, 0, 4);
             *      storybookText.OutlineColor -= new Color(0, 0, 0, 4);
             *      if (parchment.Color.A < 1)
             *      {
             *          viewingStory = false;
             *      }
             *  }
             * }
             */

            // --- title ------------------------------------------------------------------------------------
            var titleText = new Text();

            titleText.Font             = oldenglishFont;
            titleText.FillColor        = new Color(48, 32, 32, 200);
            titleText.OutlineColor     = new Color(48, 32, 32, 64);
            titleText.OutlineThickness = 1;
            titleText.CharacterSize    = 92;
            titleText.DisplayedString  = "Derpy Chess";
            titleText.Position         = new Vector2f(10 + parchment.GetGlobalBounds().GetCenter().X - titleText.GetGlobalBounds().GetCenter().X, parchment.Position.Y + 64);

            var playGameText = new Text();

            playGameText.Font             = oldenglishFont;
            playGameText.FillColor        = new Color(48, 32, 32, 200);
            playGameText.OutlineColor     = new Color(48, 32, 32, 64);
            playGameText.OutlineThickness = 1;
            playGameText.CharacterSize    = 48;
            playGameText.DisplayedString  = "Play Game";
            //playGameText.Origin = playGameText.GetGlobalBounds().GetSize() * 0.5f;
            //playGameText.Position = window.Size.ToVector2f() * 0.5f;
            playGameText.Position =
                new Vector2f(10, 0)
                + parchment.GetGlobalBounds().GetCenter()
                - playGameText.GetGlobalBounds().GetCenter();


            bool viewingTitle = true;
            bool titleFade    = false;

            while (window.IsOpen && viewingTitle)
            {
                window.Clear();
                window.DispatchEvents();

                for (var y = 0; y < window.Size.Y; y += backgroundSprite.TextureRect.Height)
                {
                    for (var x = 0; x < window.Size.X; x += backgroundSprite.TextureRect.Width)
                    {
                        backgroundSprite.Position = new Vector2f(x, y);
                        backgroundSprite.Draw(window, RenderStates.Default);
                    }
                }
                vignette.Draw(window, RenderStates.Default);
                parchment.Draw(window, RenderStates.Default);
                titleText.Draw(window, RenderStates.Default);
                playGameText.Draw(window, RenderStates.Default);

                window.Display();

                if ((Keyboard.IsKeyPressed(Keyboard.Key.Enter) || Keyboard.IsKeyPressed(Keyboard.Key.Space) || Mouse.IsButtonPressed(Mouse.Button.Left)))
                {
                    titleFade = true;
                }
                if (titleFade)
                {
                    parchment.Color           -= new Color(0, 0, 0, 3);
                    titleText.FillColor       -= new Color(0, 0, 0, 4);
                    titleText.OutlineColor    -= new Color(0, 0, 0, 4);
                    playGameText.FillColor    -= new Color(0, 0, 0, 4);
                    playGameText.OutlineColor -= new Color(0, 0, 0, 4);
                    if (parchment.Color.A < 1)
                    {
                        viewingTitle = false;
                    }
                }
                else
                {
                    parchment.Color += new Color(0, 0, 0, 3);
                    if (playGameText.GetGlobalBounds().Contains(Mouse.GetPosition(window)))
                    {
                        playGameText.FillColor    = new Color(150, 0, 32, 200);
                        playGameText.OutlineColor = new Color(150, 0, 32, 64);
                    }
                    else
                    {
                        playGameText.FillColor    = new Color(48, 32, 32, 200);
                        playGameText.OutlineColor = new Color(48, 32, 32, 64);
                    }
                }
            }

            // --- game ------------------------------------------------------------------------
            var debugText = new Text();

            debugText.Font          = storybookFont;
            debugText.FillColor     = new Color(0, 255, 0, 255);
            debugText.CharacterSize = 16;


            if (window.IsOpen)
            {
                // play game
                var endgameText = new Text();
                endgameText.Font             = storybookFont;
                endgameText.FillColor        = Color.White;
                endgameText.OutlineColor     = Color.Black;
                endgameText.OutlineThickness = 2;
                endgameText.CharacterSize    = 48;
                endgameText.DisplayedString  = "Checkmate!";

                board.Enabled = true;
                while (window.IsOpen)
                {
                    window.Clear();
                    window.DispatchEvents();

                    for (var y = 0; y < window.Size.Y; y += backgroundSprite.TextureRect.Height)
                    {
                        for (var x = 0; x < window.Size.X; x += backgroundSprite.TextureRect.Width)
                        {
                            backgroundSprite.Position = new Vector2f(x, y);
                            backgroundSprite.Draw(window, RenderStates.Default);
                        }
                    }
                    vignette.Draw(window, RenderStates.Default);
                    board.Draw(window, RenderStates.Default);
                    busyIndicator.Visible = board.aiThinking;
                    busyIndicator.Draw(window, RenderStates.Default);
                    if (board.GameEndText != null)
                    {
                        endgameText.DisplayedString = board.GameEndText;
                        var textBounds = endgameText.GetGlobalBounds();
                        endgameText.Position = new Vector2f(
                            (window.Size.X * 0.5f) - (textBounds.Width * 0.5f),
                            window.Size.Y - textBounds.Height - 32);//(window.Size.Y * 0.5f) - (textBounds.Height * 0.5f));
                        endgameText.Draw(window, RenderStates.Default);
                    }

                    // debug view
                    if (Keyboard.IsKeyPressed(Keyboard.Key.D))
                    //#if DEBUG
                    {
                        var labels = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "8", "7", "6", "5", "4", "3", "2", "1" };
                        int i      = 0;
                        for (var x = board.Position.X; x < board.Position.X + board.Rect.Width; x += board.Rect.Width / 8)
                        {
                            debugText.DisplayedString = labels[i++];
                            debugText.Position        = new Vector2f(x + 32 - debugText.GetGlobalBounds().Width * 0.5f, board.Position.Y - 32 - debugText.GetGlobalBounds().Height * 0.5f);
                            debugText.Draw(window, RenderStates.Default);
                            debugText.Position = new Vector2f(x + 32 - debugText.GetGlobalBounds().Width * 0.5f, board.Position.Y + board.Rect.Height + 32 - debugText.GetGlobalBounds().Height * 0.5f);
                            debugText.Draw(window, RenderStates.Default);
                        }
                        for (var y = board.Position.Y; y < board.Position.Y + board.Rect.Height; y += board.Rect.Height / 8)
                        {
                            debugText.DisplayedString = labels[i++];
                            debugText.Position        = new Vector2f(board.Position.X - 32 - debugText.GetGlobalBounds().Width * 0.5f, y + 32 - debugText.GetGlobalBounds().Height * 0.5f);
                            debugText.Draw(window, RenderStates.Default);
                            debugText.Position = new Vector2f(board.Position.X + board.Rect.Width + 32 - debugText.GetGlobalBounds().Width * 0.5f, y + 32 - debugText.GetGlobalBounds().Height * 0.5f);
                            debugText.Draw(window, RenderStates.Default);
                        }
                    }
                    //#endif

                    window.Display();
                }
            }
        }
        public GameBoard(Sprite board, Sprite[] black, Sprite[] white, Font labelFont, Vector2f position, Vector2u gridSize, Vector2f scale, uint gridLayers = 1, DragManager mouseManager = null, int dragLayer = -1, int dropLayer = -1, Vector2f dropScale = default, Vector2u cellSize = default)
            : base(null, gridSize, scale, gridLayers, mouseManager, dragLayer, dropLayer, dropScale, cellSize)
        {
            font             = labelFont;
            boardSquareLabel = new Text("", font, 17);
            //boardSquareLabel.Style = Text.Styles.Bold;

            boardSquareLabel.OutlineThickness = 1;

            boardSprite = board;
            Position    = position;
            chessBoard  = new Board(true);
            //chessBoard = new Board("rnb1k1nr/ppppbppp/8/4Q3/8/4P3/PPP2qPP/RNB1KBNR w 11");

            /*** setup "tiles" (the game piece sprites) ******************************************/
            blackRook   = new Sprite(black[11]);
            blackBishop = new Sprite(black[00]);
            blackKnight = new Sprite(black[06]);
            blackQueen  = new Sprite(black[10]);
            blackKing   = new Sprite(black[08]);
            blackPawn   = new Sprite(black[12]);
            whitePawn   = new Sprite(white[12]);
            whiteRook   = new Sprite(white[11]);
            whiteBishop = new Sprite(white[00]);
            whiteKnight = new Sprite(white[05]);
            whiteQueen  = new Sprite(white[10]);
            whiteKing   = new Sprite(white[08]);
            //shadow = new Sprite(black[13]);

            blackPieces = new Dictionary <int, Sprite>()
            {
                { PieceType.Bishop, blackBishop },
                { PieceType.King, blackKing },
                { PieceType.Knight, blackKnight },
                { PieceType.Pawn, blackPawn },
                { PieceType.Queen, blackQueen },
                { PieceType.Rook, blackRook },
            };

            whitePieces = new Dictionary <int, Sprite>()
            {
                { PieceType.Bishop, whiteBishop },
                { PieceType.King, whiteKing },
                { PieceType.Knight, whiteKnight },
                { PieceType.Pawn, whitePawn },
                { PieceType.Queen, whiteQueen },
                { PieceType.Rook, whiteRook },
            };

            updateBoardFromGameState();
        }