using System; using System.Collections.Generic; using Godot; public class ExploreNode : ProgramNode { public Vector3 startPosition; public Vector3I targetPosition; public List pathPoints; public ExploreNode() { DisplayText = "Explore"; TooltipText = "Explores nearby unknown tiles around the robot and reveals them for future navigation. \rContinues exploration until no unvisited tile is left."; } public override NodeResult Execute(Robot robot, double delta) { if (pathPoints == null && !TrySelectTarget()) { lastExecutionMessage = "No tiles left to explore"; return NodeResult.SUCCESS; } if (pathPoints == null) { pathPoints = new List( Pathfinding.GetPath(Pathfinding.GetClosestStartPoint(robot.Position), targetPosition) ); } if (pathPoints.Count <= 0) { lastExecutionMessage = $"No path available {targetPosition}"; return NodeResult.FAILURE; } return MoveAlongPath(robot, delta); } private bool TrySelectTarget() { int safetyCounter = 0; int maximumAttempts = (int)Math.Pow(GameData.layerSize, 2) * 2; while (safetyCounter <= maximumAttempts) { targetPosition = new Vector3I( GameData.rand.Next(GameData.layerSize), GameData.rand.Next(GameData.lowestLayer + 1), GameData.rand.Next(GameData.layerSize) ); if (!GameData.map[targetPosition.Y].tiles[targetPosition.X, targetPosition.Z].wasVisited) { return true; } safetyCounter++; } return false; } private NodeResult MoveAlongPath(Robot robot, double delta) { startPosition = robot.Position; Vector3 target = pathPoints[0] - startPosition; float distance = target.Length(); float movementSpeed = robot.GetMovementSpeed(); if (distance < 0.1f * Mathf.Sqrt(movementSpeed)) { return FinishCurrentStep(robot); } Vector3 direction = target / distance; RotateRobot(robot, direction); robot.GlobalPosition += direction * (float)delta * movementSpeed; return NodeResult.RUNNING; } private NodeResult FinishCurrentStep(Robot robot) { robot.Position = pathPoints[0]; VisitCurrentTile(robot); pathPoints.RemoveAt(0); if (pathPoints.Count > 0) { lastExecutionMessage = ""; return NodeResult.RUNNING; } lastExecutionMessage = "Current exploration finished"; pathPoints = null; return NodeResult.RUNNING; } private void VisitCurrentTile(Robot robot) { Vector3I mapIndex = Pathfinding.GetClosestStartPoint(robot.Position); Tile tile = GameData.map[mapIndex.Y].tiles[mapIndex.X, mapIndex.Z]; if (!tile.wasVisited) { tile.VisitTile(); } } private void RotateRobot(Robot robot, Vector3 direction) { Vector3 lookDirection = new Vector3(direction.X, 0, direction.Z); if (lookDirection.Length() <= 0.1f) return; robot.LookAt(robot.GlobalPosition + lookDirection, Vector3.Up); } public override ProgramNode Duplicate() { return new ExploreNode { targetPosition = targetPosition }; } public override string Save() { return $"Name: {DisplayText}"; } }