GOAPState Apply(IGOAPAction action) { //Add preconditions of the action as goals to the next state var newCurrentValues = new Map <GOAPKeyEnum, object>(currentValues); var newGoalValues = new Map <GOAPKeyEnum, Func <object, bool> >(goalValues); var completeGoal = true; foreach (var effect in action.Effects) { newCurrentValues[effect.Key] = effect.Value(currentValues[effect.Key]); if (goalValues.ContainsKey(effect.Key) && !goalValues[effect.Key](newCurrentValues[effect.Key])) { completeGoal = false; } } foreach (var precondition in action.Preconditions) { if (completeGoal) { newGoalValues[precondition.Key] = precondition.Value; } } return(new GOAPState( actions, newCurrentValues, //.Merge(action.Effects), newGoalValues, //.Merge(action.Preconditions), action, heuristic )); }
public GOAPState(IEnumerable <IGOAPAction> actions, Map <GOAPKeyEnum, object> initialValues, Map <GOAPKeyEnum, Func <object, bool> > goalValues, IGOAPAction generatingAction, Func <IGraphNode <GOAPState>, float> heuristic) { this.actions = actions; this.currentValues = initialValues; this.goalValues = goalValues; this.heuristic = heuristic; GeneratingAction = generatingAction; }
// REMEMBER: This is building a path in reverse. successor -> predecessor private IGOAPAction FindSuccessor(IGOAPAction successor = default) { return(successor != default && successor.IsFinal ? default : (from predecessor in actions let priority = predecessor.Priority(successor) where priority != null || priority != float.NaN orderby priority descending select predecessor).FirstOrDefault()); }
// ==================================================================== #region Waiting For Target private float?PFWaitingForTargetPriority(IGOAPAction next) { if (next?.Name?.Equals("RequestingPath") == true) { return(1); } else { return(null); } }
// ==================================================================== #region Waiting For Path private float?PFWaitingForPathPriority(IGOAPAction next) { if (next?.Name?.Equals("FollowingPath") == true) { return(1); } else { return(null); } }
public void Add(IGOAPAction action) { var effect = ((GOAPStateStorageSingle)action.Effect).GetState(); if (!_effectsAndActions.ContainsKey(effect)) { _effectsAndActions.Add(effect, new List <IGOAPReadOnlyAction>()); } _effectsAndActions[effect].Add(action); _actions.Add(action); }
private void SwitchStack() { Stack <IGOAPAction> actionStack = new Stack <IGOAPAction>(); IGOAPAction bestSuccessor = default; int loop = 1000; while (loop-- > 0 && (bestSuccessor = FindSuccessor(bestSuccessor)) != default) { actionStack.Push(bestSuccessor); } CurrentAction?.OnEnd(); this.actionStack = actionStack; CurrentAction?.OnStart(); }
public void GOAPUpdate() { switch (CurrentAction != null ? CurrentAction.Update() : GOAPStatus.Fail) { case GOAPStatus.Running: break; case GOAPStatus.Continue: IGOAPAction action = actionStack?.Pop(); action?.OnEnd(); CurrentAction?.OnStart(); break; case GOAPStatus.Fail: default: SwitchStack(); break; } }
public float?Priority(IGOAPAction successor) => priority?.Invoke(successor) ?? null;
// ==================================================================== #region Following Path private float?PFFollowingPathPriority(IGOAPAction next) { return(next == null ? (float?)1f : null); }
public void Add(IGOAPAction action) { _actions.Add(action); }