public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { //target a visible enemy //if there is only one enemy visible, target it if (_worldState.enemyData.Count == 1) { core.actor.targetEnemy = _worldState.enemyData[0].enemy; } else //if there are more, choose the closest { ActorBase closest = null; float closestDistance = float.PositiveInfinity; foreach (EnemyPosition _enemyData in _worldState.enemyData) { float testDistance = Vector3.Distance(core.actor.transform.position, _enemyData.enemy.transform.position); if (testDistance < closestDistance) { closest = _enemyData.enemy; closestDistance = testDistance; } } core.actor.targetEnemy = closest; } return true; }
/// <summary> /// compare the fed worldstate to a newly generated one, if they have different enemy data, replan. /// </summary> /// <param name="_worldState">World state.</param> public override bool Sense(GoapPlan _currentPlan, GoapWorldstate _worldState) { bool changeSensed = false; GoapWorldstate oldState = _worldState, newState = new GoapWorldstate(); //generate a new worldstate newState.generateWorldState(core.actor); //if the enemy data is different, the enemies have changed and a new plan should be forged if (CompareEnemyData(oldState.enemyData, newState.enemyData)) { //drop the current target enemy core.actor.targetEnemy = null; changeSensed = true; } //push the new worldstate into the core core.setWorldState(newState); //return the verdict return changeSensed; }
/// <summary> /// Proceeds the along path. /// </summary> /// <returns><c>true</c>, if progress along the path was made, <c>false</c> otherwise.</returns> protected bool ProceedAlongPath(GoapPlan _currentPlan) { //find the next GO on the currentPath GameObject targetTroct = _currentPlan.plannedPath.Value[0]; Vector3 towardsTarget = (targetTroct.transform.position - core.actor.currentTrOct.transform.position).normalized; //is this actor facing the troct? if (towardsTarget == core.actor.transform.forward) { //if so, try move forwards if (core.actor.TryMoveForwards()) { _currentPlan.plannedPath.Value.RemoveAt(0); //see if the target node has been reached if (_currentPlan.plannedPath.Value.Count == 0) { KeyValuePair<string, List<GameObject>> tempPath = new KeyValuePair<string, List<GameObject>>(_currentPlan.plannedPath.Key, null); _currentPlan.plannedPath = tempPath; } return true; //return a successful progression along the path } else { return false; // return an unsuccessful progression along the path } } else //turn to face the next TrOct { return core.actor.TryRotate(targetTroct.transform); //return the result of attempting to look at the next troct. } }
public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { GameObject goalNode = null; //if the path has not already been made if (_currentPlan.plannedPath.Value == null || _currentPlan.plannedPath.Key != actionName) { KeyValuePair<string, List<GameObject>> tempPath = new KeyValuePair<string, List<GameObject>>(actionName, _currentPlan.plannedPath.Value); _currentPlan.plannedPath = tempPath; TruncOct enemyTroct= core.actor.targetEnemy.currentTrOct.GetComponent<TruncOct>(); List<TruncOct> inLineTrocts = new List<TruncOct>(); //List all trocts leading from enemy location //loop through all faces of the troct for (int i = 0; i < enemyTroct.Faces.Count; i++) { //if the current face has no connection, continue to the next face. if (enemyTroct.connections[i] != TruncOct.connectionState.Connected) { continue; } else //else it it connected and should be pushed as far as it can go outwards { //get the next troct TruncOct newTroct = _worldState.topology[enemyTroct.connectionObjects[i]].GetComponent<TruncOct>(); List<TruncOct> direction = new List<TruncOct>(); direction.Add(newTroct); inLineTrocts.AddRange (TroctsInDirection(direction, i, newTroct, _worldState)); } } //find the closest one that is avaliable float closestDistance = float.MaxValue; TruncOct closestTroct; for (int i = 0; i < inLineTrocts.Count; i++) { float tempDist = Vector3.Distance(core.actor.currentTrOct.transform.position, inLineTrocts[i].transform.position); if (tempDist < closestDistance) { closestDistance = tempDist; closestTroct = inLineTrocts[i]; goalNode = closestTroct.gameObject; } } //now plot a route to A* pathfind to _currentPlan.plotRoute(core.actor, core.actor.currentTrOct, goalNode); } //try to follow the A* path return ProceedAlongPath(_currentPlan); }
public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { //if we have 2 action points left, heal otherwise remove last action points and continue if (!core.actor.TryToRepair()) { core.actor.actionPoints = 0; return false; } return true; }
public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { GameObject goalNode = null; //if there is not currently a path, plot a course towards a random undiscovered area if (_currentPlan.plannedPath.Value == null) { //compile a list of all trocts concealed by the fow List<GameObject> undiscoveredTrocts = new List<GameObject>(); foreach (GameObject _trOctObj in _worldState.topology) { if (_trOctObj.GetComponent<TruncOct>().inFow) { undiscoveredTrocts.Add(_trOctObj); } } //find the one with the largest combined distance from all allies float biggestDistance = 0f; GameObject furthestTroct; for (int i = 0; i < undiscoveredTrocts.Count; i++) { float totalDistance = 0f; for (int j = 0; j < _worldState.allies.Count; j++) { totalDistance += Vector3.Distance(undiscoveredTrocts[i].transform.position, _worldState.allies[j].currentTrOct.transform.position); } if (totalDistance > biggestDistance) { furthestTroct = undiscoveredTrocts[i]; biggestDistance = totalDistance; //this will be the goal TrOct goalNode = furthestTroct; } } //plot a route using the central A* plotter through the current plan _currentPlan.plotRoute(core.actor, core.actor.currentTrOct, goalNode); } // attempt to follow the path that was either preexisting or was just generated return ProceedAlongPath(_currentPlan); }
/// <summary> /// If the actor is facing the next troct on the path and the path is obstructed and the current actor has action points left, replan /// </summary> /// <param name="_worldState">World state.</param> public override bool Sense(GoapPlan _currentPlan, GoapWorldstate _worldState) { //make a copy of the current path List<GameObject> path = _currentPlan.plannedPath.Value; //if the path is empty or we are at the end of the path, return false as no replanning has to be done as a result of the sensed state if (_currentPlan.plannedPath.Value == null) { return false; } else { if (_currentPlan.plannedPath.Value [0] == core.actor.currentTrOct) { _currentPlan.plannedPath.Value.RemoveAt (0); } } //find the next GO on the currentPath GameObject targetTroct = path[0]; Vector3 towardsTarget = (targetTroct.transform.position - core.actor.currentTrOct.transform.position).normalized; //is this actor facing the troct? if (towardsTarget == core.actor.transform.forward) { //is the target troct occupied? if (targetTroct.GetComponent<TruncOct>().containedActor != null) { //if so, replan return true; } } return false; }
private GoapPlan ExecutePlan(GoapPlan _currentPlan, GoapWorldstate _worldState) { bool actionSuccess = true; int currentPlanAction = 0; //try to carry out the plan until an action attempt fails (or sensors interrupt) while (actor.actionPoints > 0) { //test all actions up to the current int value for retroactive analysis for (int i = 0; i < currentPlanAction; i++) { if (_currentPlan.actionOrder[i].Test(_worldState)) { currentPlanAction = i; break; } } //if the action on the top of the stack needs to be done if (_currentPlan.actionOrder[currentPlanAction].Test (_worldState)) { //run sensors GoapPlan tempPlan = CheckSensors(_currentPlan, _worldState); //if the plans differ if (!ComparePlans(_currentPlan, tempPlan)) { return tempPlan; } //try to carry it out and have it set the result of actionSuccess depending on a success or failure actionSuccess = _currentPlan.actionOrder[currentPlanAction].Action(_currentPlan, _worldState); if (actionSuccess) //if an action was successfully done,check if it will need to be continued (with a new worldstate) { _worldState.generateWorldState (actor); //if the action no longer needs to be done, pop it from the stack if (!_currentPlan.actionOrder[currentPlanAction].Test (_worldState)) { currentPlanAction ++; } tempPlan = CheckSensors (_currentPlan, getworldState ()); //call sensors as a precaution if (!ComparePlans(_currentPlan, tempPlan)) { return tempPlan; } } } else//move to the next operation in the plan the plan, as it doesnt need to be carried out { currentPlanAction++; } } //return the plan now that it has been processed and attempted return _currentPlan; }
calls; //the base function that is used to change the worldstate public abstract bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState);
public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { return false; }
private void Init() { goapPlan = new GoapPlan(); }
public void TakeTurn () { worldState = UpdateWorldstate(); //sort the goal priorities for this turn. GoapGoal tempGoal = SortGoals (worldState); //if the goal has changed, or the sensors demand it, a new plan must be formulated if (tempGoal != currentGoal || currentPlan == null) { currentGoal = tempGoal; currentPlan = FormulatePlan(currentGoal, worldState); } //loop the plan execution until all while (actor.actionPoints > 0) { //process and execute the plan, setting it to be the new plan currentPlan = ExecutePlan (currentPlan, worldState); } return; }
/// <summary> /// Formulates a plan from the given goal and current actor state. /// </summary> /// <returns>The plan.</returns> /// <param name="_goal">Goal.</param> /// <param name="_worldstate">Worldstate.</param> private GoapPlan FormulatePlan (GoapGoal _goal, GoapWorldstate _worldstate) { GoapPlan newPlan = new GoapPlan(); newPlan.actionOrder = new List<GoapAction> (); //according to the goal form an initial prerequisite of what we want to do newPlan.goalBeingFulfilled = _goal; string initPrereq = _goal.initPrerequisite; //add the initial action onto the stack to start constructing the plan foreach (GoapAction _action in actionPool) { if (_action.fulfillment == initPrereq) { newPlan.actionOrder.Insert (0, _action); break; } } List<string> prerequisites = newPlan.actionOrder[0].prerequisites; newPlan.actionOrder = FulfillPrereqs (newPlan.actionOrder, prerequisites, _worldstate); return newPlan; }
/// <summary> /// Compares to see if plans are equal from their planning data (as the reference to the core will always flag them as different otherwise). /// </summary> /// <returns><c>true</c>, if plans are the same <c>false</c> otherwise.</returns> /// <param name="_planA">Plan a.</param> /// <param name="_planB">Plan b.</param> private bool ComparePlans(GoapPlan _planA, GoapPlan _planB) { //if the goals differ if (_planA.goalBeingFulfilled != _planB.goalBeingFulfilled) { //return stating this difference return false; } GoapAction[] tempA = _planA.actionOrder.ToArray(), tempB = _planB.actionOrder.ToArray(); for (int i = 0; i < tempA.Length; i++) { if (tempA[i] != tempB[i]) { return false; } } //else they must be the same return true; }
/// <summary> /// Calls the sensors one at a time in order to see if the plan needs changing in accordance to worldstate changes /// </summary> /// <returns>The altered goal if the sensors call for a replan</returns> /// <param name="">.</param> private GoapPlan CheckSensors (GoapPlan _currentPlan, GoapWorldstate _worldState) { foreach (GoapSensor _sensor in sensors) { //if a replan is needed according to the current sensor if (_sensor.Sense(_currentPlan, _worldState)) { //resort goals, and from this formulate a new plan return FormulatePlan(SortGoals(_worldState), _worldState); } } //if all is fine, return the plan back as it was, it is fine. return _currentPlan; }
/// <summary> /// Carry out the GOAP action, in this case, move to a safer area. /// </summary> /// <param name="_currentPlan">Current plan.</param> /// <param name="_worldState">World state.</param> public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { GameObject goalNode = null; //if the path has not already been made if (_currentPlan.plannedPath.Value == null || _currentPlan.plannedPath.Key != actionName) { KeyValuePair<string, List<GameObject>> tempPath = new KeyValuePair<string, List<GameObject>>(actionName, _currentPlan.plannedPath.Value); _currentPlan.plannedPath = tempPath; List<TruncOct> inLineTrocts = new List<TruncOct>(); //compile a list of trocts from all visible enemies for (int i = 0; i < _worldState.enemyData.Count; i++) { TruncOct enemyTroct = _worldState.enemyData[i].enemyLocation; //List all trocts leading from enemy location //loop through all faces of the troct for (int j = 0; j < enemyTroct.Faces.Count; j++) { //if the current face has no connection, continue to the next face. if (enemyTroct.connections[j] != TruncOct.connectionState.Connected) { continue; } else //else it it connected and should be pushed as far as it can go outwards { //get the next troct TruncOct newTroct = _worldState.topology[enemyTroct.connectionObjects[j]].GetComponent<TruncOct>(); List<TruncOct> direction = new List<TruncOct>(); direction.Add(newTroct); inLineTrocts.AddRange (TroctsInDirection(direction, j, newTroct, _worldState)); } } } //find the closest troct in line that is not in line with the enemy List<TruncOct> inLineSelf = new List<TruncOct>(); TruncOct thisTroct = core.actor.currentTrOct.GetComponent<TruncOct>(); //loop through all faces of the troct for (int i = 0; i < thisTroct.Faces.Count; i++) { //if the current face has no connection, continue to the next face. if (thisTroct.connections[i] != TruncOct.connectionState.Connected) { continue; } else //else it it connected and should be pushed as far as it can go outwards { //get the next troct TruncOct newTroct = _worldState.topology[thisTroct.connectionObjects[i]].GetComponent<TruncOct>(); List<TruncOct> direction = new List<TruncOct>(); direction.Add(newTroct); inLineSelf.AddRange (TroctsInDirection(direction, i, newTroct, _worldState)); } } TruncOct targetTroct = null; //compare to find a troct that is not inline with an enemy for (int i = 0; i < inLineSelf.Count; i++) { if (!inLineTrocts.Contains(inLineSelf[i])) { targetTroct = inLineSelf[i]; break; } } //if a new location still needs to be found if (targetTroct == null) { //else find a close troct that is not in line List<TruncOct> closeTrocts = new List<TruncOct>(); foreach(GameObject _tObject in GameManager.instance.allTrocts) { if (Vector3.Distance(core.actor.transform.position, _tObject.transform.position) <= (core.actor.viewDistance / 1.5f)) { if (!inLineTrocts.Contains(_tObject.GetComponent<TruncOct>())) { targetTroct = _tObject.GetComponent<TruncOct>(); } } } //if a close one cant be found, just generate a random one by force, we must move! while ((!inLineTrocts.Contains(targetTroct) && targetTroct == null) || targetTroct == null) { TruncOct rand = GameManager.instance.allTrocts[Random.Range(0, GameManager.instance.allTrocts.Count)].GetComponent<TruncOct>(); if (!inLineTrocts.Contains(rand)) { targetTroct = rand; break; } } } goalNode = targetTroct.gameObject; //now plot a route to A* pathfind to _currentPlan.plotRoute(core.actor, core.actor.currentTrOct, goalNode); } //try to follow the A* path return ProceedAlongPath(_currentPlan); }
public abstract bool Sense(GoapPlan _currentPlan, GoapWorldstate _worldState);
public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { //try to rotate towards the target enemy return core.actor.TryRotate(core.actor.targetEnemy.transform); }
public override bool Action(GoapPlan _currentPlan, GoapWorldstate _worldState) { //SHOOT FORWARDS return core.actor.Shootforwards(); }
private void Init() { goapPlan = new GoapPlan(); usableGoapActionList = goapGoal.GetActions(); }