public Map(byte[,] table) { tileList = new Tile[table.GetLength(0), table.GetLength(1)]; for (int y = 0; y < table.GetLength(0); y++) for (int x = 0; x < table.GetLength(1); x++) tileList[y, x] = new Tile(y, x, table[y, x]); }
public Node(Tile tile, Node parent, Tile destination) { this.tile = tile; this.parent = parent; this.estimatedMovement = (int) (Math.Abs(destination.Position.X - tile.Position.X) + Math.Abs(destination.Position.Y - tile.Position.Y)); }
protected override void Initialize() { heros = new Hero(0, 13, 4); cost = new Cost(heros); startTile = map.TileList[heros.Y, heros.X]; base.Initialize(); }
public static List<Node> PossibleNode = new List<Node>(); // Les noeuds possibles (cases adjacentes de tout le chemin) #endregion Fields #region Methods public static MyLinkedList<Tile> CalculatePathWithAStar(Map map, Tile startTile, Tile endTile) { PossibleNode.Clear(); NodeList<Node> openList = new NodeList<Node>(); // Contiens tout les noeuds candidat (qui vont être examinés) NodeList<Node> closedList = new NodeList<Node>(); // Contiens la liste des meilleurs noeuds (le resultat du plus cours chemin) List<Node> possibleNodes; // cases adjacentes du noeud courant // Le noeud de départ Node startNode = new Node(startTile, null, endTile); // FIXME : on recupère le noeud de départ /**********************************/ /* Traitement des noeuds candidat */ /**********************************/ openList.Add(startNode); while (openList.Count > 0) // Tant que la liste ouverte contient des éléments { Node current = openList[0]; openList.RemoveAt(0); closedList.Add(current); if (current.Tile == endTile) // si l'élément courant est la case destination { MyLinkedList<Tile> solution = new MyLinkedList<Tile>(); // on reverse la liste fermée et on la retourne pour l'avoir dans le bonne ordre while (current.Parent != null) { solution.AddFirst(current.Tile); current = current.Parent; } return solution; } possibleNodes = current.GetPossibleNode(map, endTile); // FIXME : recupère la listes des cases adjacentes // on ajoute cette liste a notre variable static qui contient l'ensemble des listes adjacentes (gestion de l'affichage) PossibleNode.AddRange(possibleNodes) ; /***************************************/ /* Ajout des noeuds adjacents candidat */ /***************************************/ for (int i = 0; i < possibleNodes.Count; i++) // on vérifie que chaque noeuds adjacent (possibleNodes) { if (!closedList.Contains(possibleNodes[i])) // n'existe pas dans la liste fermée (eviter la redondance) { if (openList.Contains(possibleNodes[i])) // FIXME : Si il existe dans la liste ouverte on vérifie { if (possibleNodes[i].EstimatedMovement < openList[possibleNodes[i]].EstimatedMovement) // si le cout de deplacement du // noeud est inferieur a un coût calculer précedement, dance cas la on remonte le chemin dans la liste ouverte openList[possibleNodes[i]].Parent = current; } else openList.DichotomicInsertion(possibleNodes[i]); } } } return null; }
// recupère les 8 cases adjacentes public List<Node> GetPossibleNode(Map map, Tile destination) { List<Node> result = new List<Node>(); // Bottom if (map.ValidCoordinates(tile.X, tile.Y + 1) && map.TileList[tile.Y + 1, tile.X].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y + 1, tile.X], this, destination)); // Right if (map.ValidCoordinates(tile.X + 1, tile.Y) && map.TileList[tile.Y, tile.X + 1].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y, tile.X + 1], this, destination)); // Top if (map.ValidCoordinates(tile.X, tile.Y - 1) && map.TileList[tile.Y - 1, tile.X].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y - 1, tile.X], this, destination)); // Left if (map.ValidCoordinates(tile.X - 1, tile.Y) && map.TileList[tile.Y, tile.X - 1].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y, tile.X - 1], this, destination)); // Bottom Left if (map.ValidCoordinates(tile.X - 1, tile.Y + 1) && map.TileList[tile.Y + 1, tile.X - 1].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y + 1, tile.X - 1], this, destination)); // Bottom Right if (map.ValidCoordinates(tile.X + 1, tile.Y + 1) && map.TileList[tile.Y + 1, tile.X + 1].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y + 1, tile.X + 1], this, destination)); // Top Left if (map.ValidCoordinates(tile.X - 1, tile.Y - 1) && map.TileList[tile.Y - 1, tile.X - 1].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y - 1, tile.X - 1], this, destination)); // Top Right if (map.ValidCoordinates(tile.X + 1, tile.Y - 1) && map.TileList[tile.Y - 1, tile.X + 1].Type != TileType.Wall) result.Add(new Node(map.TileList[tile.Y - 1, tile.X + 1], this, destination)); return result; }
public void aStar() { int min = minimum(), cost; Tile current = new Tile(Vector2.Zero, false); List<Tile> neighbors; while (min >= 0 && open[min].pos != goalTile.pos) { current = open[min]; open.RemoveAt(min); close.Add(current); neighbors = neighborTiles(current); foreach (Tile neighbor in neighbors) { int gkost = g(current), mkost = movementCost(current, neighbor), gnkost = g(neighbor); cost = gkost + mkost; if (open.Contains(neighbor) && cost < gnkost) open.Remove(neighbor); if (close.Contains(neighbor) && cost < gnkost) close.Remove(neighbor); if (!(open.Contains(neighbor) || close.Contains(neighbor))) { int hkost = h(neighbor); cost = gnkost; neighbor.rank = gnkost + hkost; neighbor.pre = current; open.Add(neighbor); } } min = minimum(); } walker = null; if (min < 0) return; walker = open[min]; if (walker != null) walker = reverseConstruct(walker); }
public Tile(Vector2 position, bool isBlocked) { pos = position; blocked = isBlocked; pre = null; rank = 0; }
// Constructs the path in the opposite direction private Tile reverseConstruct(Tile src) { Tile tmp = null; while (src != null) { Tile tmp2 = src.pre; src.pre = tmp; tmp = src; src = tmp2; } return tmp; }
private List<Tile> neighborTiles(Tile source) { int xCoor, yCoor; List<Tile> neighbors = new List<Tile>(); ; xCoor = (int)source.pos.X / 19; yCoor = (int)source.pos.Y / 19; // This A* takes manhattan distance approach, // the node can only go in 4 directions if (xCoor + 1 <= x - 1 && !world[xCoor + 1, yCoor].blocked) neighbors.Add(world[xCoor+1, yCoor]); if (xCoor - 1 >= 0 && !world[xCoor - 1, yCoor].blocked) neighbors.Add(world[xCoor-1, yCoor]); if (yCoor + 1 <= y - 1 && !world[xCoor, yCoor + 1].blocked) neighbors.Add(world[xCoor, yCoor + 1]); if (yCoor - 1 >= 0 && !world[xCoor, yCoor - 1].blocked) neighbors.Add(world[xCoor, yCoor - 1]); return neighbors; }
// cost from src to dst private int movementCost(Tile src, Tile dst) { return (int)Math.Abs((Math.Abs(src.pos.X - dst.pos.X) - Math.Abs(src.pos.Y - dst.pos.Y))/19); }
// cost from src to goal private int h(Tile src) { return (int)Math.Abs((Math.Abs(src.pos.X - goalTile.pos.X) - Math.Abs(src.pos.Y - goalTile.pos.Y)))/19; }
// cost from start to current private int g(Tile current) { return (int)(Math.Abs(startTile.pos.X - current.pos.X) + Math.Abs(startTile.pos.Y - current.pos.Y))/19; //the sum of x and y coordinate divided by 19, each block is 19 by 19 pixels }
protected internal override void Initialize() { x = graphics.GraphicsDevice.Viewport.Width / 19; y = graphics.GraphicsDevice.Viewport.Height / 19; world = new Tile[x,y]; for (int i = 0; i < x; i++) for (int j = 0; j < y; j++) world[i, j] = new Tile(new Vector2(i * 19, j * 19), rand.NextDouble() > 1-rateOfBlocks); startTile = world[3, 3]; goalTile = world[x - 4, y-4]; open = new List<Tile>(); close = new List<Tile>(); stepPos = new Vector2(750, 15); robPos = new Vector2(400, 15); viewport = new Rectangle(0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height); fontPos = new Vector2(viewport.Width / 2 - 200, viewport.Height / 2 - 10); //msec = 0; step = 0; path.Clear(); restartPos = new Vector2(viewport.Width / 2 - 300, viewport.Height - 100); open.Add(startTile); LoadContent(); //base.Initialize(); aStar(); }
protected override void Update(GameTime gameTime) { if (ServiceHelper.Get<IMouseService>().LeftButtonHasBeenPressed()) { startTile.Color = Color.White; startTile = map.TileList[heros.Y, heros.X]; if (heros.Lastpath != null) // suppression des couleurs sur l'ancien chemin { MyNode<Tile> head = heros.Lastpath.Head; while (head != null) { head.Data.Color = Color.White; head = head.NextNode; } } if (heros.WalkingList != null) // suppression des couleurs sur le chemin si on relance un astar en plein calcul. { MyNode<Tile> head = heros.WalkingList.Head; while (head != null) { head.Data.Color = Color.White; head = head.NextNode; } } mouseX = (int)ServiceHelper.Get<IMouseService>().GetCoordinates().X / 50; // on recupere la case destination mouseY = (int)ServiceHelper.Get<IMouseService>().GetCoordinates().Y / 50; if (heros.X != mouseX || heros.Y != mouseY) { heros.Lastpath.Clear(); heros.WalkingList = Pathfinding.CalculatePathWithAStar(map, heros, map.TileList[mouseY, mouseX]); } if (heros.WalkingList != null && heros.WalkingList.Size != 0) { MyNode<Tile> head = heros.WalkingList.Head; startTile.Color = Color.Red; while (head != null) { head.Data.Color = Color.Orange; head = head.NextNode; } } } cost.Update(heros); heros.Update(gameTime); base.Update(gameTime); }