public GOAP_State(GOAP_State reference) { foreach (KeyValuePair <string, PriorityValue> pair in reference.Conditions) { Conditions [pair.Key] = pair.Value; // set value } }
public IEnumerable <GOAP_GraphNode> Neighbors(GOAP_GraphNode Item) { if (Item.LeftPreConditions == null || Item.LeftPreConditions.Count <= 0) // solve left priorities { foreach (GOAP_Action Action in PossibleActions(Item)) { var SortedConditions = Action.PreConditions.GetSortedList(); var LeftConditions = new GOAP_State(Item.LeftConditions); GOAP_State Combined = Item.State + Action.Effects; // the combined conditions of the current state of the parrent and the effects of the new action LeftConditions.RemoveConditions(Combined.Conditions); yield return(new GOAP_GraphNode(LeftConditions, Item.Agent, Item, Action, SortedConditions)); // this is a neighbor of the parent node } } else // first solve preconditions { foreach (GOAP_Action Action in PossibleActions(Item, Item.LeftPreConditions)) { GOAP_State Combined = Item.State + Action.Effects; // the combined conditions of the current state of the parrent and the effects of the new action var CopyList = new List <KeyValuePair <string, GOAP_State.PriorityValue> > (Item.LeftPreConditions); // copy left preconditions bool SubstractedPreconditions = Combined.RemoveSelfInOrderFromList(ref CopyList); // remove from combined state if (SubstractedPreconditions) // combined effects satisfy the first or more preconditions of the previous action { var SortedConditions = Action.PreConditions.GetSortedList(); // set sorted list of preconditios from this action SortedConditions.AddRange(CopyList); // add copy list to preconditions of action yield return(new GOAP_GraphNode(Item.LeftConditions, Item.Agent, Item, Action, SortedConditions)); // this is a neighbor of the parent node } } } }
public void Plan(GOAP_Goal Goal, GOAP_Agent Agent, System.Action <Queue <GOAP_ActionState>, GOAP_Goal> OnDone) { GOAP_State GoalState = Goal.Goal.RemoveConditions(Agent.Memory.State.Conditions); // remove already satisfied goals based on agent memory if (IsAchievable(GoalState, Agent)) // first check wheter with the given actions the disired goal can be achived before forcing it with a* { GOAP_Searcher Searcher = new GOAP_Searcher(); // create new A* GOAP searches Queue <GOAP_ActionState> NewPlan = Searcher.Solve <GOAP_ActionState>( new GOAP_Graph(), // initialize new goap graph (GOAP_GraphNode Node) => { return(Node.ConnectionAction); }, new GOAP_GraphNode(GoalState, Agent, null, null), // start state is the goal cause of backwards searching new GOAP_GraphNode(Agent.Memory.State, Agent, null, null), // goal state is the current state cuase of backwards searching false, false, // include start in the que 500 // max 500 iterations before force exit ); // solve plan finding if (NewPlan != null) { OnDone.Invoke(NewPlan, Goal); return; } // created plan invoke } // could not find a plan OnDone.Invoke(null, Goal); }
public bool IsAchievable(GOAP_State GoalState, GOAP_Agent Agent) { if (GoalState.Conditions.Count <= 0) { return(false); } // goalstate is already reached GOAP_State CopyState = new GOAP_State(GoalState); for (int i = 0; i < Agent.Actions.Length; i++) { if (CopyState.Count <= 0) { return(true); } // if goal state count is lower the zero then its achievable Agent.Actions [i].UpdateEffectsAndConditions(true, CopyState); // pre calculations done before checking if (!Agent.Actions[i].CheckProceduralUsablity(CopyState)) { continue; } // check if action is runnable or not CopyState.RemoveConditions(Agent.Actions[i].Effects.Conditions); // remove conditions of state based on effects of actions } return(CopyState.Count <= 0); }
public GOAP_GraphNode(GOAP_State Left, GOAP_Agent Agent, GOAP_GraphNode Parent, GOAP_Action ConnectionAction, List <KeyValuePair <string, GOAP_State.PriorityValue> > LeftPreConditions = default(List <KeyValuePair <string, GOAP_State.PriorityValue> >)) { this._Agent = Agent; // the agent of which to take its actions this._LeftConditions = new GOAP_State(Left); // the goal state represents the state you want to achieve using the actions of the agent. this._Parent = Parent; // the parents effect is used to meet the preconditions of this node. If parent is equal to null that means its the beginning point of the search. this._LeftPreConditions = LeftPreConditions; // temp float G = 0; if (Parent != null && ConnectionAction != null) { G = ConnectionAction.Cost; // set new cost _LeftConditions.RemoveConditions(ConnectionAction.Effects.Conditions); // remove effects from left state _LeftConditions += ConnectionAction.PreConditions; // add the pre conditions of the connection action _State = Parent.State + ConnectionAction.Effects; // the new state is the state of the parrent with the connection action effects applied if (Parent.ConnectionAction != null && Parent.ConnectionAction.Action != null) { _State.ReplaceGenData(Parent.ConnectionAction.Action.PreConditions); // replace pre conditions gen data } } else { _State = Agent.Memory.State; // if parent is equal to null. It means this is the start node. The state of the start node is always the memory of the agent. } this._ConnectionAction = new GOAP_ActionState(ConnectionAction, new GOAP_State(this._State)); // the connection action is the action used to get from the parent state to this state. _H = _LeftConditions.Count; // the heuristic is the count of conditions left to solve _Cost = G + _H; }
public void UpdateEffectsAndConditions(bool SetDefaults, GOAP_State GoalState) { if (SetDefaults) { SetDefaultValues(); } // set default values before pre calculations PreCalculations(GoalState); }
public void ReplaceGenData(GOAP_State State) { foreach (var Item in State.Conditions) { if (Conditions.ContainsKey(Item.Key)) { Conditions [Item.Key].SetGenData(State.Conditions[Item.Key].GenData); } } }
public static GOAP_State operator +(GOAP_State a, GOAP_State b) { GOAP_State result = new GOAP_State(a); foreach (var pair in b.Conditions) { result.Conditions [pair.Key] = pair.Value; } return(result); }
public bool HasKeyMatch(GOAP_State Other) { foreach (KeyValuePair <string, PriorityValue> pair in Other.Conditions) { if (_Conditions.ContainsKey(pair.Key)) { return(true); // is equal, has key match } } return(false); }
public void UpdateAction(GOAP_State GoalState) { _CurrentSkipDelay -= 1 * DeltaTime; if (_CurrentSkipDelay <= 0) { _CurrentSkipDelay = SkipDelay; SkipUpdate(GoalState); // call the skip update } Update(GoalState); // call abstract update }
/// <summary> /// Determines wheter this state has a matching condition with the other state /// </summary> /// <returns><c>true</c> if this instance has match the specified Other; otherwise, <c>false</c>.</returns> /// <param name="Other">Other.</param> public bool HasMatch(GOAP_State Other) { foreach (KeyValuePair <string, PriorityValue> pair in Other.Conditions) { if (_Conditions.ContainsKey(pair.Key)) { if (PairEquals(pair, new KeyValuePair <string, PriorityValue> (pair.Key, _Conditions [pair.Key]))) { return(true); // is equal, has match } } } return(false); }
public IEnumerable <GOAP_Action> PossibleActions(GOAP_GraphNode Node, List <KeyValuePair <string, GOAP_State.PriorityValue> > LeftPreconditions) { GOAP_Action[] Actions = Node.Agent.Actions; // get all possible actions of agent for (int i = 0; i < Actions.Length; i++) { var PossibleAction = Actions[i]; GOAP_State State = new GOAP_State(LeftPreconditions); // create left state based on preconditions PossibleAction.UpdateEffectsAndConditions(true, State); // update action conditions if (PossibleAction.Effects.HasMatch(State) && PossibleAction.CheckProceduralUsablity(State)) // if has matching effect and possible action is possible { yield return(PossibleAction); // this is a possible action } } }
protected abstract void Enter(GOAP_State GoalState);
/// <summary> /// Calculations to do just before comparison state / effects comparisons /// </summary> /// <param name="Agent">Agent.</param> /// <param name="GoalState">Goal state.</param> protected virtual void PreCalculations(GOAP_State GoalState) { }
public void InterruptAction(GOAP_State GoalState) { OnInterruption(GoalState); }
public void ExitAction(GOAP_State GoalState) { Exit(GoalState); }
public void EnterAction(GOAP_State GoalState) { _CurrentSkipDelay = 0f; // reset skip delay to call directly Enter(GoalState); }
protected abstract void Exit(GOAP_State GoalState);
protected virtual void OnInterruption(GOAP_State GoalState) { }
/// <summary> /// Determines wheter the action is done performing /// </summary> /// <value><c>true</c> if this instance is done; otherwise, <c>false</c>.</value> public abstract bool IsDone(GOAP_State GoalState);
public GOAP_ActionState(GOAP_Action Action, GOAP_State GoalState) { this._Action = Action; this._GoalState = GoalState; }
/// <summary> /// This check is performed when switching to this action. It is only called once. /// </summary> /// <returns><c>true</c>, if procedural switch was checked, <c>false</c> otherwise.</returns> /// <param name="Agent">Agent.</param> /// <param name="GoalState">Goal state.</param> public virtual bool CheckProceduralSwitch(GOAP_State GoalState) { return(true); }
/// <summary> /// Checks the procedural precondition, determines wheter this action is still runnable or not. /// </summary> /// <returns><c>true</c>, if procedural precondition was checked, <c>false</c> otherwise.</returns> /// <param name="Agent">Agent.</param> /// <param name="GoalState">Goal state.</param> public virtual bool CheckProceduralPrecondition(GOAP_State GoalState) { return(true); }
/// <summary> /// Checks whether this action is usable during the planning of a goal /// </summary> /// <returns><c>true</c>, if procedural usablity was checked, <c>false</c> otherwise.</returns> /// <param name="Agent">Agent.</param> /// <param name="GoalState">Goal state.</param> public virtual bool CheckProceduralUsablity(GOAP_State GoalState) { return(true); }
/// <summary> /// Skip update is called not every frame but based on the "SkipDelay" value /// </summary> /// <param name="Agent">Agent.</param> /// <param name="GoalState">Goal state.</param> protected virtual void SkipUpdate(GOAP_State GoalState) { }
protected abstract void Update(GOAP_State GoalState);
/// <summary> /// Returns wheter this action is interruptable at this given moment in time. Always called before changing to new state /// </summary> /// <returns><c>true</c>, if for interruption was asked, <c>false</c> otherwise.</returns> /// <param name="Agent">Agent.</param> /// <param name="GoalState">Goal state.</param> public virtual bool AskForInterruption(GOAP_State GoalState) { return(true); }