public void ShouldFindPath_GraphWithDeadEnds() { var nodeCenter = new Node(new Position(10, 10)); var nodeLeft = new Node(new Position(0, 10)); var nodeRight = new Node(new Position(20, 10)); var nodeAbove = new Node(new Position(10, 0)); var nodeBelow = new Node(new Position(10, 20)); nodeCenter.Connect(nodeLeft, Velocity.FromMetersPerSecond(1)); nodeLeft.Connect(nodeCenter, Velocity.FromMetersPerSecond(1)); nodeCenter.Connect(nodeRight, Velocity.FromMetersPerSecond(1)); nodeRight.Connect(nodeCenter, Velocity.FromMetersPerSecond(1)); nodeCenter.Connect(nodeAbove, Velocity.FromMetersPerSecond(1)); nodeAbove.Connect(nodeCenter, Velocity.FromMetersPerSecond(1)); nodeCenter.Connect(nodeBelow, Velocity.FromMetersPerSecond(1)); nodeBelow.Connect(nodeCenter, Velocity.FromMetersPerSecond(1)); var path = this.PathFinder.FindPath(nodeLeft, nodeBelow, Velocity.FromMetersPerSecond(1)); Assert.That(path.Type, Is.EqualTo(PathType.Complete)); Assert.That(path.Edges.Count, Is.EqualTo(2)); Assert.That(path.Distance, Is.EqualTo(Distance.FromMeters(20))); Assert.That(path.Duration, Is.EqualTo(Duration.FromSeconds(20))); }
Grid GetMapGrid(int frame) { if (MapLastUpdate < frame) { var gridSize = new GridSize(columns: MapData.MapWidth, rows: MapData.MapHeight); var cellSize = new Size(Distance.FromMeters(1), Distance.FromMeters(1)); var traversalVelocity = Velocity.FromMetersPerSecond(1); WalkGrid = Grid.CreateGridWithLateralAndDiagonalConnections(gridSize, cellSize, traversalVelocity); for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { if (!MapData.Map[x][y].Walkable) { WalkGrid.DisconnectNode(new GridPosition(x, y)); //DebugService.DrawSphere(new Point { X = x, Y = y, Z = MapData.Map[x][y].TerrainHeight + 1 }, 2, new Color { R = 0, G = 255, B = 0 }); } else { //DebugService.DrawSphere(new Point { X = x, Y = y, Z = MapData.Map[x][y].TerrainHeight + 1 }, 2, new Color { R = 255, G = 0, B = 0 }); } } } } return(WalkGrid); }
Grid GetGroundGrid(int frame) { Node [,] nodes = new Node[MapData.MapWidth, MapData.MapHeight]; if (GroundGridLastUpdate < frame) { for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { var node = new Node(new Position(x, y)); nodes[x, y] = node; } } for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { if (MapData.Map[x][y].Walkable && !MapData.Map[x][y].PathBlocked) { var speed = BaseSpeed - MapData.Map[x][y].EnemyGroundDpsInRange + MapData.Map[x][y].SelfGroundDpsInRange; if (MapData.Map[x][y].InSelfVision) { speed += FriendlyVisionSpeed; } if (MapData.Map[x][y].InEnemyVision) { speed += EnemyVisionSpeed; } //if (MapData.Map[x][y].SelfDetection) // TODO: Self detection //{ // speed += FriendlyDetectionSpeed; //} if (MapData.Map[x][y].InEnemyDetection) { speed += EnemyDetectionSpeed; } if (speed < MinimumSpeed) { speed = MinimumSpeed; } // TODO: low ground near high ground, add a high ground proximity to the MapCell foreach (Node neighbor in GetNeighbors(x, y, 1, nodes)) { if (MapData.Map[(int)neighbor.Position.X][(int)neighbor.Position.Y].Walkable && !MapData.Map[(int)neighbor.Position.X][(int)neighbor.Position.Y].PathBlocked) { var node = nodes[x, y]; node.Connect(neighbor, Velocity.FromMetersPerSecond(speed)); } } } } } GroundGrid = Grid.CreateGridFrom2DArrayOfNodes(nodes); GroundGridLastUpdate = frame; } return(GroundGrid); }
public void ShouldFindPath__StartNodeIsEndNode() { var node = new Node(Position.Zero); var path = this.PathFinder.FindPath(node, node, Velocity.FromMetersPerSecond(1)); Assert.That(path.Type, Is.EqualTo(PathType.Complete)); Assert.That(path.Edges.Count, Is.EqualTo(0)); Assert.That(path.Distance, Is.EqualTo(Distance.FromMeters(0))); Assert.That(path.Duration, Is.EqualTo(Duration.Zero)); }
Grid GetAirGrid(int frame) { Node[,] nodes = new Node[MapData.MapWidth, MapData.MapHeight]; if (AirGridLastUpdate < frame) { for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { var node = new Node(new Position(x, y)); nodes[x, y] = node; } } for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { var speed = BaseSpeed - MapData.Map[x][y].EnemyAirDpsInRange + MapData.Map[x][y].SelfAirDpsInRange; if (MapData.Map[x][y].InSelfVision) { speed += FriendlyVisionSpeed; } if (MapData.Map[x][y].InEnemyVision) { speed += EnemyVisionSpeed; } //if (MapData.Map[x][y].SelfDetection) // TODO: Self detection //{ // speed += FriendlyDetectionSpeed; //} if (MapData.Map[x][y].InEnemyDetection) { speed += EnemyDetectionSpeed; } if (speed < MinimumSpeed) { speed = MinimumSpeed; } foreach (Node neighbor in GetNeighbors(x, y, 1, nodes)) { var node = nodes[x, y]; node.Connect(neighbor, Velocity.FromMetersPerSecond(speed)); } } } AirGrid = Grid.CreateGridFrom2DArrayOfNodes(nodes); AirGridLastUpdate = frame; } return(AirGrid); }
public WorldGrid(int columns, int rows, float cellDimensions, float traversalVelocity, Vector3 offset) { var gridSize = new GridSize(columns, rows); this.CellSize = new Size(Distance.FromMeters(cellDimensions), Distance.FromMeters(cellDimensions)); this.MaximumVelocity = Velocity.FromMetersPerSecond(traversalVelocity); // TODO: if we create a grid with lateral and diagonal connections paths look a lot better // however we have to take into account 'crossing over' other cells when reserving. this.Grid = Grid.CreateGridWithLateralConnections(gridSize, this.CellSize, this.MaximumVelocity); this.PathFinder = new PathFinder(); this.Reservations = new Entity[columns, rows]; this.Offset = offset; this.CellOffset = new Vector3(this.CellSize.Width.Meters * 0.5f, 0, this.CellSize.Height.Meters * 0.5f); }
public static Grid MapToGrid(this AreaMap areaMap) { var rows = areaMap.Map.GetLength(0); var columns = areaMap.Map[0].GetLength(0); var nodes = new Node[columns, rows]; for (var i = 0; i < columns; i++) { for (var j = 0; j < rows; j++) { nodes[i, j] = new Node(new Position((float)i * DistanceBetweenCells, (float)j * DistanceBetweenCells)); } } for (var i = 0; i < columns; i++) { for (var j = 0; j < rows; j++) { if (!IsMovable(areaMap.Map[j][i])) { continue; } var fromNode = nodes[i, j]; var speed = GetVelocityWithAdjacency(areaMap, j, i, rows, columns); if (i + 1 < columns && IsMovable(areaMap.Map[j][i + 1])) { var toNode = nodes[i + 1, j]; var velocity = Velocity.FromMetersPerSecond(speed); fromNode.Connect(toNode, velocity); toNode.Connect(fromNode, velocity); } if (j + 1 < rows && IsMovable(areaMap.Map[j + 1][i])) { var toNode = nodes[i, j + 1]; var velocity = Velocity.FromMetersPerSecond(speed); fromNode.Connect(toNode, velocity); toNode.Connect(fromNode, velocity); } } } var grid = Grid.CreateGridFrom2DArrayOfNodes(nodes); return(grid); }
public void ShouldFindPath_AcyclicGraph() { var nodeA = new Node(new Position(0, 0)); var nodeB = new Node(new Position(10, 0)); var nodeC = new Node(new Position(20, 0)); nodeA.Connect(nodeB, Velocity.FromMetersPerSecond(1)); nodeB.Connect(nodeC, Velocity.FromMetersPerSecond(1)); var path = this.PathFinder.FindPath(nodeA, nodeC, Velocity.FromMetersPerSecond(1)); Assert.That(path.Type, Is.EqualTo(PathType.Complete)); Assert.That(path.Edges.Count, Is.EqualTo(2)); Assert.That(path.Distance, Is.EqualTo(Distance.FromMeters(20))); Assert.That(path.Duration, Is.EqualTo(Duration.FromSeconds(20))); }
public MainWindowViewModel() { this.PathFinder = new PathFinder(); this.Models = new ObservableCollection <ReactiveObject>(); this.Random = new Random(); this.outcome = string.Empty; this.ExitCommand = ReactiveCommand.Create(() => { Application.Current.Shutdown(); }); this.OpenGitHubCommand = ReactiveCommand.Create(() => { var psi = new ProcessStartInfo { FileName = "cmd", WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, CreateNoWindow = true, Arguments = $"/c start http://github.com/roy-t/AStar" }; Process.Start(psi); }); this.ResetCommand = ReactiveCommand.Create(() => this.CreateNodes(Connections.LateralAndDiagonal)); this.LateralCommand = ReactiveCommand.Create(() => this.CreateNodes(Connections.Lateral)); this.DiagonalCommand = ReactiveCommand.Create(() => this.CreateNodes(Connections.Diagonal)); this.RandomizeCommand = ReactiveCommand.Create(() => this.SetSpeedLimits(() => { var value = this.Random.Next((int)Settings.MinSpeed.MetersPerSecond, (int)Settings.MaxSpeed.MetersPerSecond + 1); return(Velocity.FromMetersPerSecond(value)); })); this.MaxCommand = ReactiveCommand.Create(() => this.SetSpeedLimits(() => Settings.MaxSpeed)); this.MinCommand = ReactiveCommand.Create(() => this.SetSpeedLimits(() => Settings.MinSpeed)); this.SaveGridCommand = ReactiveCommand.Create(this.SaveGrid); this.OpenGridCommand = ReactiveCommand.Create(this.OpenGrid); this.CreateNodes(Connections.LateralAndDiagonal); }
Grid GetAirDamageGrid(int frame) { if (AirDamageLastUpdate < frame) { var gridSize = new GridSize(columns: MapData.MapWidth, rows: MapData.MapHeight); var cellSize = new Size(Distance.FromMeters(1), Distance.FromMeters(1)); var traversalVelocity = Velocity.FromMetersPerSecond(1); AirDamageGrid = Grid.CreateGridWithLateralAndDiagonalConnections(gridSize, cellSize, traversalVelocity); for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { if (MapData.Map[x][y].EnemyAirDpsInRange > 0) { AirDamageGrid.DisconnectNode(new GridPosition(x, y)); } } } AirDamageLastUpdate = frame; } return(AirDamageGrid); }
Grid GetGroundDetectionGrid(int frame) { if (GroundDetectionLastUpdate < frame) { var gridSize = new GridSize(columns: MapData.MapWidth, rows: MapData.MapHeight); var cellSize = new Size(Distance.FromMeters(1), Distance.FromMeters(1)); var traversalVelocity = Velocity.FromMetersPerSecond(1); GroundDetectionGrid = Grid.CreateGridWithLateralAndDiagonalConnections(gridSize, cellSize, traversalVelocity); for (var x = 0; x < MapData.MapWidth; x++) { for (var y = 0; y < MapData.MapHeight; y++) { if (!MapData.Map[x][y].Walkable || MapData.Map[x][y].InEnemyDetection) { GroundDetectionGrid.DisconnectNode(new GridPosition(x, y)); } } } GroundDetectionLastUpdate = frame; } return(GroundDetectionGrid); }
private static Velocity FromDto(this VelocityDto velocity) { return(Velocity.FromMetersPerSecond(velocity.MetersPerSecond)); }
void UpdateEnemyVisionGrid(IEnumerable <UnitCalculation> enemyUnits) { EnemyVisionGrid = Grid.CreateGridWithLateralAndDiagonalConnections(WalkGrid.GridSize, new Size(Distance.FromMeters(1), Distance.FromMeters(1)), Velocity.FromMetersPerSecond(1)); foreach (var enemy in enemyUnits) { var nodes = GetNodesInRange(enemy.Unit.Pos, 11, EnemyVisionGrid.Columns, EnemyVisionGrid.Rows); // TODO: get sight range of every unit, // TODO: units on low ground can't see high ground foreach (var node in nodes) { EnemyVisionGrid.DisconnectNode(node); } } }