Skip to main content

tile-node-network

Tile Node Network in FlatRedBall2. Use when working with A* pathfinding, TileNodeNetwork, TileNode, enemy navigation, or grid-based pathfinding. Trigger on any pathfinding or enemy-follows-player question.

Aller à l'installation

Informations de source

Dépôt
vchelaru/FlatRedBall2
Dernière activité de la source
3 août 2026 à 00:23
Langue détectée de SKILL.md
anglais
Étoiles
14
Forks
8

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
tile-node-network
description
Tile Node Network in FlatRedBall2. Use when working with A* pathfinding, TileNodeNetwork, TileNode, enemy navigation, or grid-based pathfinding. Trigger on any pathfinding or enemy-follows-player question.
# Tile Node Network (A* Pathfinding) ## Key Types - `FlatRedBall2.AI.TileNodeNetwork` — the grid; builds and queries the A* graph - `FlatRedBall2.AI.TileNode` — one cell; has `Position`, `Tag`, `Neighbors` - `FlatRedBall2.AI.DirectionalType` — `Four` (cardinal only) or `Eight` (+ diagonals) ## Standard Setup The standard FlatRedBall2 tile size is **16 units**. Node origins are offset by half a tile from the `TileShapes` corner, so node centers fall at 8, 24, 40, … (i.e. `tileCollection.X + 8`, `tileCollection.Y + 8`). ```csharp var network = new TileNodeNetwork( xOrigin: tilesOriginX + 8f, // center of first column yOrigin: tilesOriginY + 8f, // center of bottom row gridSpacing: 16f, xCount: gridCols, yCount: gridRows, directionalType: DirectionalType.Eight); network.FillCompletely(); // Remove nodes where walls are (call after all wall tiles are placed) foreach (var (col, row) in wallCells) network.RemoveAt(col, row); // For 8-way: prevent squeezing diagonally through wall corners network.EliminateCutCorners(); ``` ## Getting a Path ```csharp // Allocating — returns a new List<Vector2> List<Vector2> path = network.GetPath(startNode, endNode); // Non-allocating — clears and fills an existing list; returns true if path found bool found = network.GetPath(startNode, endNode, _path); ``` The **start node is excluded**; the end node is the last entry. Returns empty / false if no path exists. ## Finding Nodes ```csharp TileNode? node = network.NodeAt(col, row); // by grid index, null if empty TileNode? node = network.NodeAtWorld(worldX, worldY); // by world position, null if empty TileNode? node = network.GetClosestNode(worldX, worldY); // nearest occupied node ``` Use `GetClosestNode` to find the start/end nodes from entity world positions. ## TileNode.Tag Attach game data to nodes (terrain type, waypoint markers, etc.): ```csharp node.Tag = MyTerrainType.Mud; ``` ## Typical Enemy AI Pattern Refresh the path on a timer (not every frame) to limit A* cost: ```csharp private readonly List<Vector2> _path = new(); private int _waypointIndex; private float _pathTimer; void Activity(FrameTime time) { _pathTimer -= time.DeltaSeconds; if (_pathTimer <= 0f) { var start = _network.GetClosestNode(X, Y); var end = _network.GetClosestNode(_target.X, _target.Y); if (start != null && end != null) _network.GetPath(start, end, _path); _waypointIndex = 0; _pathTimer = 1f; // refresh once per second } // Advance past reached waypoints while (_waypointIndex < _path.Count) { float dx = _path[_waypointIndex].X - X; float dy = _path[_waypointIndex].Y - Y; if (dx * dx + dy * dy <= WaypointRadius * WaypointRadius) _waypointIndex++; else break; } var dest = _waypointIndex < _path.Count ? _path[_waypointIndex] : new Vector2(_target.X, _target.Y); // path exhausted — steer directly // Apply velocity toward dest … } ``` ## Gotchas - **A* state is stored on nodes** — `GetPath` resets all node state at the start of each call. Concurrent calls on the same network (same frame, multiple enemies) are fine because the game loop is single-threaded and each call resets before using. - **Diagonal cost is √2 × gridSpacing** naturally — node positions are used for distance, so diagonals cost more without any extra configuration. - **`RemoveAt` unlinks neighbors** — removing a node severs all its connections. You do not need to call `EliminateCutCorners` again after individual removals.
Voir sur GitHub