From 8367cf66c4b391f0692287eb52899d319382c405 Mon Sep 17 00:00:00 2001 From: Conor Edmonds Date: Mon, 1 Jun 2026 18:29:21 -0400 Subject: [PATCH] working on pathfinding --- Enemy.cs | 81 +++++++++++++++++++++++++++++++++++++++++++-- EnemyController.cs | 39 +++++++++++++++++----- GridMap2D.cs | 11 ++++-- GridMarker.cs | 19 +++++++++-- PlayerController.cs | 4 +-- grid_marker.tscn | 2 +- project.godot | 4 +++ 7 files changed, 141 insertions(+), 19 deletions(-) diff --git a/Enemy.cs b/Enemy.cs index 30107f4..fd0cc8e 100644 --- a/Enemy.cs +++ b/Enemy.cs @@ -1,15 +1,22 @@ using Godot; using System; +using System.Collections.Generic; +using System.Linq; public partial class Enemy : StaticBody2D { [Signal] public delegate void DeathEventHandler(Enemy THIS); - public int _damage = 1, _health = 2; - public Vector2 _speed = Vector2.Up, _range = Vector2.Up; + public int _damage = 1, _health = 2, _speed; + public Vector2I _range = Vector2I.Up; public float _movement = 0; public GridMarker _gridMarker; public Commander _commander; + + public override void _Ready() + { + base._Ready(); + } public override void _PhysicsProcess(double delta) { base._PhysicsProcess(delta); @@ -25,6 +32,76 @@ public partial class Enemy : StaticBody2D } + public List Pathfinding(List DESTINATIONS, bool INCLUDE_SELF = false) + { + PriorityQueue queue = new(); + queue.Enqueue(_gridMarker, 0f); + Dictionary cameFrom = new(), best = new(); + Dictionary costSoFar = new(); + cameFrom[_gridMarker] = null; + costSoFar[_gridMarker] = 0f; + GridMarker current; + float newCost, priority; + + for (int i = 0; i < DESTINATIONS.Count; i++) + { + GridMarker destination = DESTINATIONS[i]; + while (queue.Count > 0) + { + current = queue.Dequeue(); + if (current == destination) + { + best = cameFrom; + GD.Print("breaking at line 56"); + continue; + } + + List neighbors = current.GetMarkersInRange(1.5f); + for (int j = 0; j < neighbors.Count; j++) + { + GridMarker next = neighbors[j]; + if (next._occupant != null) + { + continue; + } + newCost = costSoFar[current] + 1; + if (best.Count > 0 && newCost >= best.Count) + { + GD.Print("breaking at line 70"); + break; + } + if (!costSoFar.TryGetValue(next, out float value) || newCost < value) + { + costSoFar[next] = newCost; + priority = newCost; + queue.Enqueue(next, priority); + cameFrom[next] = current; + } + } + } + } + + GD.Print(best.Last().Value._address); + List path = new(); + GridMarker pathMarker = best.Last().Value; + + if (best.TryGetValue(pathMarker, out GridMarker marker)) + { + while (pathMarker != null) + { + path.Add(pathMarker); + pathMarker = marker; + } + path.Reverse(); + if (!INCLUDE_SELF) + { + path.Remove(_gridMarker); + } + } + + return path; + } + public void TakeDamage(int DAMAGE, Commander ATTACKER) { GD.Print(_health, _health - DAMAGE); diff --git a/EnemyController.cs b/EnemyController.cs index 38de617..78a488e 100644 --- a/EnemyController.cs +++ b/EnemyController.cs @@ -19,6 +19,8 @@ public partial class EnemyController : TurnController List lastRow = _grid._gridMarkers.Last(); List unoccupiedMarkers = [.. lastRow.Where(m => m._occupant == null).Cast()]; GridMarker randomMarker = unoccupiedMarkers[Globals._rng.Next(unoccupiedMarkers.Count)]; + newEnemy._speed = Globals._rng.Next(2,4+1); + newEnemy.Modulate = new Color(newEnemy._speed == 2 ? "#FF0000" : newEnemy._speed == 3 ? "#00FF00" : "#0000FF"); WarpEnemy(newEnemy, randomMarker); _enemies.Add(newEnemy); AddChild(newEnemy); @@ -30,24 +32,43 @@ public partial class EnemyController : TurnController AddEnemies(3); } - public void MoveEnemy(Enemy ENEMY) - { - ENEMY._gridMarker = _grid.GetMarkerByAddress((Vector2I)(ENEMY._gridMarker._address + ENEMY._speed)); - Tween tween = CreateTween(); - tween.TweenProperty(ENEMY, "global_position", ENEMY._gridMarker.GlobalPosition, 1.0f); - } + // public void MoveEnemy(Enemy ENEMY) + // { + // ENEMY._gridMarker = _grid.GetMarkerFromOffset(ENEMY._gridMarker, ENEMY._speed); + // Tween tween = CreateTween(); + // tween.TweenProperty(ENEMY, "global_position", ENEMY._gridMarker.GlobalPosition, 1.0f); + // } public void MoveEnemies(List ENEMIES = null) { ENEMIES ??= _enemies; + ENEMIES = [.. ENEMIES.OrderByDescending(e => e._gridMarker._address.Y).ThenByDescending(e => e._gridMarker._address.X)]; Tween tween = CreateTween(); tween.SetParallel(); + Dictionary> enemyPaths = new(); + for (int i = 0; i < ENEMIES.Count; i++) { - ENEMIES[i]._gridMarker = _grid.GetMarkerByAddress((Vector2I)(ENEMIES[i]._gridMarker._address + ENEMIES[i]._speed)); - tween.TweenProperty(ENEMIES[i], "global_position", ENEMIES[i]._gridMarker.GlobalPosition, 0.4f); + enemyPaths[ENEMIES[i]] = ENEMIES[i].Pathfinding(_grid._gridMarkers.ToList()); + } + + int maxSteps = enemyPaths.Select(p => p.Value.Count).Max(); + GD.Print(enemyPaths.Count, " ", maxSteps); + + for (int i = 0; i < maxSteps; i++) + { + Dictionary> qualifyingPaths = (Dictionary>)enemyPaths.Where(p => p.Value.Count <= maxSteps); + for (int j = 0; j < qualifyingPaths.Count; j++) + { + Enemy enemy = qualifyingPaths.ElementAt(j).Key; + GridMarker marker = qualifyingPaths.ElementAt(j).Value.ElementAt(i); + if (j == 0) + { + tween.Chain(); + } + tween.TweenProperty(enemy, "global_position", enemy._gridMarker.GlobalPosition, 0.4f); + } } - tween.TweenCallback(Callable.From(() => EmitSignal(SignalName.TurnDone))); } public void RemoveEnemy(Enemy ENEMY_TO_REMOVE) diff --git a/GridMap2D.cs b/GridMap2D.cs index e93aaae..79ef905 100644 --- a/GridMap2D.cs +++ b/GridMap2D.cs @@ -34,7 +34,7 @@ public partial class GridMap2D : Node2D for (int j = 0; j < _sizeInCells.X; j++) { GridMarker newGridMarker = (GridMarker)_gridMarker.Duplicate(); - newGridMarker._address = new Vector2(j, i); + newGridMarker._address = new Vector2I(j, i); newGridMarker.Position = new Vector2(_playArea.Position.X - playAreaBounds.Shape.GetRect().Size.X / 2 + (j+.5f)*_cellSize, _playArea.Position.Y - playAreaBounds.Shape.GetRect().Size.Y / 2 + (i+.5f)*_cellSize); _gridMarkers[i].Add(newGridMarker); AddChild(newGridMarker); @@ -67,8 +67,13 @@ public partial class GridMap2D : Node2D return _gridMarkers[COORDINATES.Y][COORDINATES.X]; } - public GridMarker GetGridMarkerRelativeToAnother(GridMarker GRID_MARKER, Vector2I STEP) + public GridMarker GetMarkerFromOffset(GridMarker GRID_MARKER, Vector2I STEP) { - return _gridMarkers[(int)GRID_MARKER._address.Y + STEP.Y][(int)GRID_MARKER._address.X + STEP.X]; + return _gridMarkers[GRID_MARKER._address.Y + STEP.Y][GRID_MARKER._address.X + STEP.X]; + } + + public List GetMarkerInRange(GridMarker GRID_MARKER, int RANGE) + { + return [.. _gridMarkers.SelectMany(m => m).Where(m => (GRID_MARKER._address - m._address).Length() <= RANGE).Cast()]; } } diff --git a/GridMarker.cs b/GridMarker.cs index 1c24048..173ab90 100644 --- a/GridMarker.cs +++ b/GridMarker.cs @@ -1,10 +1,25 @@ using Godot; using System; +using System.Collections.Generic; +using System.Linq; public partial class GridMarker : Marker2D { - public Vector2 _address; + public Vector2I _address; public Node _occupant; - // public GridMarker Get + public List _gridMarkers; + + public override void _Ready() + { + base._Ready(); + } + + public List GetMarkersInRange(float RANGE = 1.0f){ + if (_gridMarkers == null || _gridMarkers.Count == 0) + { + _gridMarkers = [.. GetTree().GetNodesInGroup("GridMarkers").Cast()]; + } + return [.. _gridMarkers.Where(m => m._address.Length() <= RANGE).Cast()]; + } } diff --git a/PlayerController.cs b/PlayerController.cs index 45c0e82..d3f857d 100644 --- a/PlayerController.cs +++ b/PlayerController.cs @@ -18,7 +18,7 @@ public partial class PlayerController : TurnController { if (_towers.Where(t => t._commander != null).ToList().All(t=>t._commander._actions == 0)) { - EmitSignal(SignalName.TurnDone); + EmitSignal(SignalName.TurnDone); } } @@ -47,7 +47,7 @@ public partial class PlayerController : TurnController public override void StartTurn() { - _towers.Where(t=> t._commander != null).ToList().ForEach(t=>t._commander._actions = t._commander._actionsMax); + _towers.Where(t=> t._commander != null).ToList().ForEach(t=>t._commander._actions = t._commander._actionsMax); } } diff --git a/grid_marker.tscn b/grid_marker.tscn index 636bb76..5e9dfbe 100644 --- a/grid_marker.tscn +++ b/grid_marker.tscn @@ -2,5 +2,5 @@ [ext_resource type="Script" uid="uid://cob0pwghnubxa" path="res://GridMarker.cs" id="1_u0re5"] -[node name="GridMarker" type="Marker2D" unique_id=1390656323] +[node name="GridMarker" type="Marker2D" unique_id=1390656323 groups=["GridMarkers"]] script = ExtResource("1_u0re5") diff --git a/project.godot b/project.godot index 84e0849..80cda47 100644 --- a/project.godot +++ b/project.godot @@ -25,6 +25,10 @@ window/size/mode=3 project/assembly_name="PeggleRoguelike" +[global_group] + +GridMarkers="" + [input] leftClick={