/// <summary> /// We first traverse to the root, then apply tasks from there to get them in the right order /// such that the last task on the queue is the task of our leaf node that we started with. /// </summary> /// <param name="node"></param> private void GeneratePlan(IContext ctx, GOAPNode node) { if (node != null && node.Task != null) { GeneratePlan(ctx, node.Parent); node.Task.ApplyEffects(ctx); Plan.Enqueue(node.Task); } }
private void FreeNode(IContext ctx, GOAPNode node) { var nextNode = node.Parent; ctx.Factory.Free(ref node); if (nextNode != null) { FreeNode(ctx, nextNode); } }
private GOAPNode GetCheapestLeaf(List <GOAPNode> leaves) { GOAPNode cheapestLeaf = null; foreach (var leaf in leaves) { if (cheapestLeaf != null) { if (leaf.RunningCost < cheapestLeaf.RunningCost) { cheapestLeaf = leaf; } } else { cheapestLeaf = leaf; } } return(cheapestLeaf); }
private bool TryBuildGraph(IContext ctx, GOAPNode parent, List <GOAPNode> leaves, List <ITask> openSubtasks) { var foundLeaf = false; for (var taskIndex = 0; taskIndex < openSubtasks.Count; taskIndex++) { var task = openSubtasks[taskIndex]; if (task.IsValid(ctx) == false) { continue; } if (task is IGOAPTask goapTask) { // Due to branching permutations of state, and multiple possible solutions // to the goal, where we want to end up with the shortest path, we need to // reset the state stack for every task we operate on. var oldStackDepth = ctx.GetWorldStateChangeDepth(ctx.Factory); goapTask.ApplyEffects(ctx); var node = ctx.Factory.Create <GOAPNode>(); { node.Parent = parent; node.RunningCost = parent.RunningCost + goapTask.Cost(ctx); node.Task = goapTask; } if (ValidatesGoal(ctx)) { leaves.Add(node); foundLeaf = true; } else { var subset = GetSubset(ctx, task, openSubtasks); if (TryBuildGraph(ctx, node, leaves, subset)) { foundLeaf = true; } else { // If we failed to find a valid branch for this node, // then it will no longer be referenced after this point. // Otherwise its still used as a parent reference in the // leaves list, and we can't return it to the factory yet. ctx.Factory.Free(ref node); } ctx.Factory.FreeList(ref subset); } // Because of the branching permutations of state with GOAP, // we must always reset the state stack back to the state it // was in previous to the changes applied by this particular // permutation. ctx.TrimToStackDepth(oldStackDepth); } } return(foundLeaf); }