public override IEnumerable <Status> Run() { while (true) { Creature.AI.Blackboard.Erase(PathName); Agent.Blackboard.SetData <bool>("NoPath", false); PlanAct planAct = new PlanAct(Creature.AI, PathName, VoxelName, PlanType) { Radius = Radius, MaxTimeouts = MaxTimeouts }; planAct.Initialize(); bool planSucceeded = false; while (true) { Act.Status planStatus = planAct.Tick(); if (planStatus == Status.Fail) { yield return(Act.Status.Running); break; } else if (planStatus == Status.Running) { yield return(Act.Status.Running); } else if (planStatus == Status.Success) { planSucceeded = true; break; } yield return(Act.Status.Running); } if (!planSucceeded && planAct.LastResult == AStarPlanner.PlanResultCode.MaxExpansionsReached) { yield return(Act.Status.Running); Creature.CurrentCharacterMode = CharacterMode.Idle; Creature.Physics.Velocity = Vector3.Zero; Timer planTimeout = new Timer(MathFunctions.Rand(30.0f, 120.0f), false, Timer.TimerMode.Real); List <VoxelHandle> exploredVoxels = new List <VoxelHandle>(); Color debugColor = new Color(MathFunctions.RandVector3Cube() + Vector3.One * 0.5f); float debugScale = MathFunctions.Rand() * 0.5f + 0.5f; while (!planTimeout.HasTriggered) { // In this case, try to follow a greedy path toward the entity instead of just failing. var greedyPath = planAct.ComputeGreedyFallback(20, exploredVoxels); var goal = planAct.GetGoal(); Creature.AI.Blackboard.SetData("GreedyPath", greedyPath); var greedyPathFollow = new FollowPathAct(Creature.AI, "GreedyPath") { //BlendEnd = true, //BlendStart = false }; greedyPathFollow.Initialize(); foreach (var currStatus in greedyPathFollow.Run()) { if (Debugger.Switches.DrawPaths) { foreach (var voxel in exploredVoxels) { Drawer3D.DrawBox(voxel.GetBoundingBox().Expand(-debugScale), debugColor, 0.05f, false); } } if (!exploredVoxels.Contains(Agent.Physics.CurrentVoxel)) { exploredVoxels.Add(Agent.Physics.CurrentVoxel); } if (Debugger.Switches.DrawPaths) { Drawer3D.DrawLine(Agent.Position, goal.GetVoxel().WorldPosition, debugColor, 0.1f); } if (goal.IsInGoalRegion(Agent.Physics.CurrentVoxel)) { yield return(Act.Status.Success); yield break; } yield return(Act.Status.Running); } planTimeout.Update(DwarfTime.LastTime); } continue; } else if (!planSucceeded) { Agent.Blackboard.SetData <bool>("NoPath", true); yield return(Act.Status.Fail); yield break; } yield return(Act.Status.Success); yield break; } }
public IEnumerable <Act.Status> GreedyFallbackBehavior(Creature agent) { var edgeGoal = new EdgeGoalRegion(); while (true) { DieTimer.Update(DwarfTime.LastTime); if (DieTimer.HasTriggered) { foreach (var status in Die(agent)) { continue; } yield break; } var creatureVoxel = agent.Physics.CurrentVoxel; List <MoveAction> path = new List <MoveAction>(); var storage = new MoveActionTempStorage(); for (int i = 0; i < 10; i++) { if (edgeGoal.IsInGoalRegion(creatureVoxel)) { foreach (var status in Die(agent)) { continue; } yield return(Act.Status.Success); yield break; } var actions = agent.AI.Movement.GetMoveActions(new MoveState { Voxel = creatureVoxel }, new List <GameComponent>(), storage); float minCost = float.MaxValue; var minAction = new MoveAction(); bool hasMinAction = false; foreach (var action in actions) { var vox = action.DestinationVoxel; float cost = edgeGoal.Heuristic(vox) * 10 + MathFunctions.Rand(0.0f, 0.1f) + agent.AI.Movement.Cost(action.MoveType); if (cost < minCost) { minAction = action; minCost = cost; hasMinAction = true; } } if (hasMinAction) { path.Add(minAction); creatureVoxel = minAction.DestinationVoxel; } else { foreach (var status in Die(agent)) { continue; } yield return(Act.Status.Success); yield break; } } if (path.Count == 0) { foreach (var status in Die(agent)) { continue; } yield return(Act.Status.Success); yield break; } agent.AI.Blackboard.SetData("GreedyPath", path); var pathAct = new FollowPathAct(agent.AI, "GreedyPath"); pathAct.Initialize(); foreach (Act.Status status in pathAct.Run()) { yield return(Act.Status.Running); } yield return(Act.Status.Running); } }