sfml a* path finding in csharp

Here is a sample code showing how to perform A* path finding in C# using SFML library:

main.cs
using System;
using System.Collections.Generic;
using SFML.Graphics;
using SFML.System;

namespace AStarDemo
{
    class Program
    {
        private static readonly int tileSize = 32; // size of each tile

        static void Main(string[] args)
        {
            RenderWindow window = new RenderWindow(new VideoMode(640, 640), "A* Path Finding Demo");
            window.Closed += Window_Closed;

            // create the grid of tiles
            int rowCount = window.Size.X / tileSize;
            int colCount = window.Size.Y / tileSize;
            Tile[,] tiles = new Tile[rowCount, colCount];
            for (int row = 0; row < rowCount; ++row)
            {
                for (int col = 0; col < colCount; ++col)
                {
                    tiles[row, col] = new Tile(TileType.Floor, new Vector2i(row, col));
                }
            }
            tiles[2, 2].Type = TileType.Block; // add an obstacle
            tiles[3, 2].Type = TileType.Block;
            tiles[4, 2].Type = TileType.Block;
            tiles[5, 2].Type = TileType.Block;

            // perform A* path finding
            List<Tile> path = AStar(tiles, new Vector2i(0, 0), new Vector2i(rowCount-1, colCount-1));

            // draw the tiles and the path in the window
            while (window.IsOpen)
            {
                window.DispatchEvents();
                window.Clear(Color.White);

                for (int row = 0; row < rowCount; ++row)
                {
                    for (int col = 0; col < colCount; ++col)
                    {
                        RectangleShape shape = new RectangleShape(new Vector2f(tileSize, tileSize));
                        shape.Position = new Vector2f(row * tileSize, col * tileSize);
                        if (tiles[row, col].Type == TileType.Block)
                        {
                            shape.FillColor = Color.Black;
                        }
                        else
                        {
                            shape.FillColor = Color.White;
                        }
                        window.Draw(shape);
                    }
                }

                for (int i = 0; i < path.Count; ++i)
                {
                    CircleShape shape = new CircleShape(tileSize / 2);
                    shape.Origin = shape.Radius * Vector2f.One;
                    shape.Position = new Vector2f(path[i].Position.X * tileSize + tileSize / 2, path[i].Position.Y * tileSize + tileSize / 2);
                    shape.FillColor = Color.Red;
                    window.Draw(shape);
                }

                window.Display();
            }
        }

        private static List<Tile> AStar(Tile[,] tiles, Vector2i start, Vector2i end)
        {
            // initialize the start and end tiles
            Tile startTile = tiles[start.X, start.Y];
            startTile.GScore = 0;
            startTile.FScore = startTile.GScore + Heuristic(startTile, tiles[end.X, end.Y]);
            Tile endTile = tiles[end.X, end.Y];
            endTile.GScore = float.MaxValue; // infinity

            // initialize the list of open and closed tiles
            List<Tile> openSet = new List<Tile> { startTile };
            List<Tile> closedSet = new List<Tile>();

            while (openSet.Count > 0)
            {
                // get the tile with the lowest f-score
                Tile currentTile = GetLowestFScoreTile(openSet);

                // if the current tile is the end tile, then we have found a path
                if (currentTile == endTile)
                {
                    return ReconstructPath(endTile);
                }

                // move the current tile from open to closed set
                openSet.Remove(currentTile);
                closedSet.Add(currentTile);

                // process the neighbors of the current tile
                foreach (Tile neighbor in GetNeighbors(currentTile, tiles))
                {
                    // skip the neighbor if it has already been evaluated
                    if (closedSet.Contains(neighbor))
                    {
                        continue;
                    }

                    // calculate the tentative g-score
                    float tentativeGScore = currentTile.GScore + 1f;

                    // add the neighbor to the open set if it is a new tile
                    if (!openSet.Contains(neighbor))
                    {
                        openSet.Add(neighbor);
                    }
                    else if (tentativeGScore >= neighbor.GScore)
                    {
                        continue;
                    }

                    // update the neighbor's g-score and f-score
                    neighbor.Parent = currentTile;
                    neighbor.GScore = tentativeGScore;
                    neighbor.FScore = neighbor.GScore + Heuristic(neighbor, endTile);
                }
            }

            // no path found
            return null;
        }

        private static Tile GetLowestFScoreTile(List<Tile> tiles)
        {
            Tile lowest = tiles[0];
            for (int i = 1; i < tiles.Count; ++i)
            {
                if (tiles[i].FScore < lowest.FScore)
                {
                    lowest = tiles[i];
                }
            }
            return lowest;
        }

        private static float Heuristic(Tile a, Tile b)
        {
            return MathF.Sqrt((a.Position.X - b.Position.X) * (a.Position.X - b.Position.X) + (a.Position.Y - b.Position.Y) * (a.Position.Y - b.Position.Y));
        }

        private static List<Tile> GetNeighbors(Tile tile, Tile[,] tiles)
        {
            List<Tile> neighbors = new List<Tile>();
            int rowCount = tiles.GetLength(0);
            int colCount = tiles.GetLength(1);
            Vector2i[] offsets = new Vector2i[]
            {
                new Vector2i(-1, 0),
                new Vector2i(1, 0),
                new Vector2i(0, -1),
                new Vector2i(0, 1)
            };
            foreach (Vector2i offset in offsets)
            {
                Vector2i position = tile.Position + offset;
                if (position.X >= 0 && position.X < rowCount && position.Y >= 0 && position.Y < colCount)
                {
                    neighbors.Add(tiles[position.X, position.Y]);
                }
            }
            return neighbors;
        }

        private static List<Tile> ReconstructPath(Tile endTile)
        {
            List<Tile> path = new List<Tile>();
            Tile currentTile = endTile;
            while (currentTile != null)
            {
                path.Insert(0, currentTile);
                currentTile = currentTile.Parent;
            }
            return path;
        }

        private static void Window_Closed(object sender, EventArgs e)
        {
            RenderWindow window = (RenderWindow)sender;
            window.Close();
        }
    }

    enum TileType
    {
        Floor,
        Block
    }

    class Tile
    {
        public TileType Type { get; set; }
        public Vector2i Position { get; set; }
        public float GScore { get; set; } = float.MaxValue; // infinity
        public float FScore { get; set; } = float.MaxValue; // infinity
        public Tile Parent { get; set; }

        public Tile(TileType type, Vector2i position)
        {
            Type = type;
            Position = position;
        }
    }
}
7503 chars
215 lines

Note that this is just a basic example of A* path finding using SFML in C#. You may need to modify the code to suit your specific requirements.

gistlibby LogSnag