Add most of research
This commit is contained in:
34
GOAP/Assets/Scrips/AI_Area.cs
Normal file
34
GOAP/Assets/Scrips/AI_Area.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class AI_Area : MonoBehaviour
|
||||
{
|
||||
[Header("Area Settings")]
|
||||
public Vector2 size = new Vector2(10f, 10f); // Width x Depth
|
||||
public Color gizmoColor = new Color(0f, 1f, 0f, 0.25f);
|
||||
|
||||
public Vector3 GetRandomPointInArea()
|
||||
{
|
||||
float halfX = size.x / 2f;
|
||||
float halfZ = size.y / 2f;
|
||||
|
||||
float randomX = Random.Range(-halfX, halfX);
|
||||
float randomZ = Random.Range(-halfZ, halfZ);
|
||||
|
||||
Vector3 localOffset = new Vector3(randomX, 0f, randomZ);
|
||||
return transform.position + transform.rotation * localOffset;
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = gizmoColor;
|
||||
|
||||
Matrix4x4 oldMatrix = Gizmos.matrix;
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
Gizmos.DrawCube(Vector3.zero, new Vector3(size.x, 0.01f, size.y));
|
||||
Gizmos.matrix = oldMatrix;
|
||||
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireCube(transform.position, new Vector3(size.x, 0.01f, size.y));
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/AI_Area.cs.meta
Normal file
2
GOAP/Assets/Scrips/AI_Area.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22f280aea26c8374aa78095f232b885f
|
||||
3
GOAP/Assets/Scrips/Actions.meta
Normal file
3
GOAP/Assets/Scrips/Actions.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d301a715802c4bd3bc42de723b5e93e2
|
||||
timeCreated: 1748549866
|
||||
29
GOAP/Assets/Scrips/Actions/Charge.cs
Normal file
29
GOAP/Assets/Scrips/Actions/Charge.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class Charge : AI_Action
|
||||
{
|
||||
public GameObject m_Resource;
|
||||
public override bool PrePerform()
|
||||
{
|
||||
m_Resource = AI_World.Instance.RemoveCharger();
|
||||
if (m_Resource == null)
|
||||
{
|
||||
return false; // No charger available
|
||||
}
|
||||
|
||||
inventory.AddItem(m_Resource);
|
||||
target = m_Resource;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
agentWorldStates.RemoveState("Depleted");
|
||||
AI_World.Instance.AddCharger(m_Resource);
|
||||
m_Resource = null; // Clear the resource after use
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/Charge.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/Charge.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d65acb659c17edb43b07f1984ce199a1
|
||||
14
GOAP/Assets/Scrips/Actions/CheckIn.cs
Normal file
14
GOAP/Assets/Scrips/Actions/CheckIn.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class CheckIn : AI_Action
|
||||
{
|
||||
public override bool PrePerform()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/CheckIn.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/CheckIn.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da447a39bb3a3c144a8a1245dac6953d
|
||||
36
GOAP/Assets/Scrips/Actions/GetPatient.cs
Normal file
36
GOAP/Assets/Scrips/Actions/GetPatient.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GetPatient : AI_Action
|
||||
{
|
||||
GameObject m_Resource;
|
||||
public override bool PrePerform()
|
||||
{
|
||||
target = AI_World.Instance.RemovePatient();
|
||||
if(target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Resource = AI_World.Instance.RemoveTreatmentBed();
|
||||
if (m_Resource != null)
|
||||
{
|
||||
inventory.AddItem(m_Resource);
|
||||
} else {
|
||||
AI_World.Instance.AddPatient(target);
|
||||
target = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
AI_World.Instance.GetWorld().ModifyState("Waiting", -1);
|
||||
if (target)
|
||||
{
|
||||
target.GetComponent<AI_Agent>().inventory.AddItem(m_Resource);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/GetPatient.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/GetPatient.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a3594ff153540945b38f6c6e7969913
|
||||
23
GOAP/Assets/Scrips/Actions/GetTreated.cs
Normal file
23
GOAP/Assets/Scrips/Actions/GetTreated.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
public class GetTreated : AI_Action
|
||||
{
|
||||
public override bool PrePerform()
|
||||
{
|
||||
target = inventory.FindItemWithTag("Bed");
|
||||
if(target == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
AI_World.Instance.GetWorld().ModifyState("Treated", 1);
|
||||
agentWorldStates.ModifyState("IsCured", 1);
|
||||
inventory.RemoveItem(target);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/GetTreated.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/GetTreated.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b134cecb1ecf86140a6bef65725746b3
|
||||
17
GOAP/Assets/Scrips/Actions/GoHome.cs
Normal file
17
GOAP/Assets/Scrips/Actions/GoHome.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
public class GoHome : AI_Action
|
||||
{
|
||||
public override bool PrePerform()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
AI_World.Instance.GetWorld().ModifyState("Home", 1);
|
||||
Destroy(this.gameObject);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/GoHome.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/GoHome.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee0072bcc9d306949b2510eb33147033
|
||||
24
GOAP/Assets/Scrips/Actions/GoToBed.cs
Normal file
24
GOAP/Assets/Scrips/Actions/GoToBed.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GoToBed : AI_Action
|
||||
{
|
||||
public override bool PrePerform()
|
||||
{
|
||||
target = inventory.FindItemWithTag("Bed");
|
||||
if(target == null)
|
||||
return false;
|
||||
|
||||
AI_World.Instance.GetWorld().ModifyState("TreatingPatient", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
|
||||
AI_World.Instance.GetWorld().ModifyState("TreatingPatient", -1);
|
||||
AI_World.Instance.AddTreatmentBed(target);
|
||||
inventory.RemoveItem(target);
|
||||
// AI_World.Instance.GetWorld().ModifyState("FreeBeds", 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/GoToBed.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/GoToBed.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9744404dabc38e24390e5f04a158b73d
|
||||
14
GOAP/Assets/Scrips/Actions/GoToHospital.cs
Normal file
14
GOAP/Assets/Scrips/Actions/GoToHospital.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GoToHospital : AI_Action
|
||||
{
|
||||
public override bool PrePerform()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/GoToHospital.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/GoToHospital.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df82dab2aef220d4eaf8d1953b5668d3
|
||||
17
GOAP/Assets/Scrips/Actions/GoToWaitingRoom.cs
Normal file
17
GOAP/Assets/Scrips/Actions/GoToWaitingRoom.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GoToWaitingRoom : AI_Action
|
||||
{
|
||||
public override bool PrePerform()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool PostPerform()
|
||||
{
|
||||
AI_World.Instance.GetWorld().ModifyState("Waiting", 1);
|
||||
AI_World.Instance.AddPatient(this.gameObject);
|
||||
agentWorldStates.ModifyState("InWaitingRoom", 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Actions/GoToWaitingRoom.cs.meta
Normal file
2
GOAP/Assets/Scrips/Actions/GoToWaitingRoom.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e80a344ad86244145a0a6408b77f4a9d
|
||||
8
GOAP/Assets/Scrips/GOAP.meta
Normal file
8
GOAP/Assets/Scrips/GOAP.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecdfd6b0e8c2f3442b5ea0b58b60b592
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
71
GOAP/Assets/Scrips/GOAP/AI_Action.cs
Normal file
71
GOAP/Assets/Scrips/GOAP/AI_Action.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
public abstract class AI_Action : MonoBehaviour
|
||||
{
|
||||
public string actionName = "Undefined Action";
|
||||
public float cost = 1.0f;
|
||||
public GameObject target;
|
||||
public string targetTag;
|
||||
public float duration = 0;
|
||||
public AIState[] preConditions;
|
||||
public AIState[] afterEffects;
|
||||
public NavMeshAgent agent;
|
||||
|
||||
public Dictionary<string, int> preConditionsDict;
|
||||
public Dictionary<string, int> effectsDict;
|
||||
|
||||
public AI_Inventory inventory;
|
||||
public AIStates agentWorldStates;
|
||||
|
||||
public bool isRunning = false;
|
||||
|
||||
public AI_Action()
|
||||
{
|
||||
preConditionsDict = new Dictionary<string, int>();
|
||||
effectsDict = new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
agent = GetComponent<NavMeshAgent>();
|
||||
|
||||
if(preConditions != null)
|
||||
{
|
||||
foreach (AIState w in preConditions)
|
||||
{
|
||||
preConditionsDict.Add(w.key, w.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (afterEffects != null)
|
||||
{
|
||||
foreach (AIState w in afterEffects)
|
||||
{
|
||||
effectsDict.Add(w.key, w.value);
|
||||
}
|
||||
}
|
||||
|
||||
inventory = GetComponent<AI_Agent>().inventory;
|
||||
agentWorldStates = GetComponent<AI_Agent>().agentWorldStates;
|
||||
}
|
||||
|
||||
public bool IsAchievable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsAchievableGiven(Dictionary<string, int> conditions)
|
||||
{
|
||||
foreach(KeyValuePair<string, int> p in preConditionsDict)
|
||||
{
|
||||
if (!conditions.ContainsKey(p.Key))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract bool PrePerform();
|
||||
public abstract bool PostPerform();
|
||||
}
|
||||
2
GOAP/Assets/Scrips/GOAP/AI_Action.cs.meta
Normal file
2
GOAP/Assets/Scrips/GOAP/AI_Action.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9e7c04605c1fa4438b738c124267f4c
|
||||
135
GOAP/Assets/Scrips/GOAP/AI_Agent.cs
Normal file
135
GOAP/Assets/Scrips/GOAP/AI_Agent.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class SubGoal
|
||||
{
|
||||
public Dictionary<string, int> goals;
|
||||
public bool shouldRemove;
|
||||
|
||||
public SubGoal(string goalName, int value, bool shouldRemove)
|
||||
{
|
||||
goals = new Dictionary<string, int>
|
||||
{
|
||||
{ goalName, value }
|
||||
};
|
||||
this.shouldRemove = shouldRemove;
|
||||
}
|
||||
}
|
||||
|
||||
public class AI_Agent : MonoBehaviour
|
||||
{
|
||||
public List<AI_Action> actions = new List<AI_Action>();
|
||||
public Dictionary<SubGoal, int> goals = new Dictionary<SubGoal, int>();
|
||||
public AI_Inventory inventory = new AI_Inventory();
|
||||
public AIStates agentWorldStates = new AIStates();
|
||||
|
||||
public float taskRange = 2.5f;
|
||||
|
||||
protected AI_Planner planner;
|
||||
protected Queue<AI_Action> actionQueue;
|
||||
protected AI_Action currentAction;
|
||||
protected SubGoal currentGoal;
|
||||
protected bool actionInvoked;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
AI_Action[] actionsArray = GetComponents<AI_Action>();
|
||||
foreach (AI_Action action in actionsArray)
|
||||
{
|
||||
actions.Add(action);
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteAction()
|
||||
{
|
||||
currentAction.isRunning = false;
|
||||
currentAction.PostPerform();
|
||||
actionInvoked = false;
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(transform.position, taskRange);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if(currentAction != null && currentAction.isRunning)
|
||||
{
|
||||
float distanceToTarget = Vector3.Distance(currentAction.target.transform.position, transform.position);
|
||||
if(currentAction.agent.hasPath && distanceToTarget < taskRange)
|
||||
{
|
||||
if(!actionInvoked)
|
||||
{
|
||||
Invoke(nameof(CompleteAction), currentAction.duration);
|
||||
actionInvoked = true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(planner == null || actionQueue == null)
|
||||
{
|
||||
planner = new AI_Planner();
|
||||
|
||||
var sortedGoals = from entry in goals orderby entry.Value descending select entry;
|
||||
|
||||
foreach(KeyValuePair<SubGoal, int> subGoal in sortedGoals)
|
||||
{
|
||||
actionQueue = planner.Plan(actions, subGoal.Key.goals, agentWorldStates);
|
||||
if (actionQueue != null)
|
||||
{
|
||||
currentGoal = subGoal.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(actionQueue != null && actionQueue.Count == 0)
|
||||
{
|
||||
if(currentGoal.shouldRemove)
|
||||
{
|
||||
goals.Remove(currentGoal);
|
||||
}
|
||||
planner = null;
|
||||
}
|
||||
|
||||
if (actionQueue != null && actionQueue.Count > 0)
|
||||
{
|
||||
currentAction = actionQueue.Dequeue();
|
||||
if (currentAction.PrePerform())
|
||||
{
|
||||
if (currentAction.target == null && !string.IsNullOrEmpty(currentAction.targetTag))
|
||||
{
|
||||
currentAction.target = GameObject.FindWithTag(currentAction.targetTag);
|
||||
}
|
||||
|
||||
if (currentAction.target != null)
|
||||
{
|
||||
currentAction.isRunning = true;
|
||||
|
||||
// Check for AI_Area component
|
||||
AI_Area area = currentAction.target.GetComponent<AI_Area>();
|
||||
Vector3 destination;
|
||||
|
||||
if (area != null)
|
||||
{
|
||||
destination = area.GetRandomPointInArea();
|
||||
}
|
||||
else
|
||||
{
|
||||
destination = currentAction.target.transform.position;
|
||||
}
|
||||
|
||||
currentAction.agent.SetDestination(destination);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actionQueue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/GOAP/AI_Agent.cs.meta
Normal file
2
GOAP/Assets/Scrips/GOAP/AI_Agent.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c48e5729f78aac64c8dbc08eb09aa525
|
||||
49
GOAP/Assets/Scrips/GOAP/AI_Inventory.cs
Normal file
49
GOAP/Assets/Scrips/GOAP/AI_Inventory.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class AI_Inventory
|
||||
{
|
||||
private List<GameObject> items = new List<GameObject>();
|
||||
|
||||
public void AddItem(GameObject item)
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
public GameObject FindItemWithTag(string tag)
|
||||
{
|
||||
foreach(GameObject item in items)
|
||||
{
|
||||
if(item.CompareTag(tag))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RemoveItem(GameObject item)
|
||||
{
|
||||
int indexToRemove = items.IndexOf(item);
|
||||
if(indexToRemove >= 0)
|
||||
{
|
||||
items.RemoveAt(indexToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
// Additional helper methods
|
||||
public bool ContainsItem(GameObject item)
|
||||
{
|
||||
return items.Contains(item);
|
||||
}
|
||||
|
||||
public void ClearInventory()
|
||||
{
|
||||
items.Clear();
|
||||
}
|
||||
|
||||
public int ItemCount
|
||||
{
|
||||
get { return items.Count; }
|
||||
}
|
||||
}
|
||||
3
GOAP/Assets/Scrips/GOAP/AI_Inventory.cs.meta
Normal file
3
GOAP/Assets/Scrips/GOAP/AI_Inventory.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06be48fd5f3a4298a422a72827aa61f0
|
||||
timeCreated: 1748549167
|
||||
154
GOAP/Assets/Scrips/GOAP/AI_Planner.cs
Normal file
154
GOAP/Assets/Scrips/GOAP/AI_Planner.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class PlanNode
|
||||
{
|
||||
public PlanNode parent;
|
||||
public float cost;
|
||||
public Dictionary<string, int> states;
|
||||
public AI_Action action;
|
||||
|
||||
public PlanNode(PlanNode parent, float cost, Dictionary<string, int> allStates, AI_Action action)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.cost = cost;
|
||||
states = new Dictionary<string, int>(allStates);
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public PlanNode(PlanNode parent, float cost, Dictionary<string, int> allStates,
|
||||
Dictionary<string, int> agentStates, AI_Action action)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.cost = cost;
|
||||
states = new Dictionary<string, int>(allStates);
|
||||
|
||||
foreach(KeyValuePair<string, int> state in agentStates)
|
||||
if(!states.ContainsKey(state.Key))
|
||||
states.Add(state.Key, state.Value);
|
||||
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
public class AI_Planner
|
||||
{
|
||||
private string planDescription;
|
||||
|
||||
public Queue<AI_Action> Plan(List<AI_Action> actions, Dictionary<string, int> goal, AIStates agentStates)
|
||||
{
|
||||
List<AI_Action> usableActions = new List<AI_Action>();
|
||||
foreach (AI_Action action in actions)
|
||||
{
|
||||
if(action.IsAchievable())
|
||||
usableActions.Add(action);
|
||||
}
|
||||
|
||||
List<PlanNode> leaves = new List<PlanNode>();
|
||||
PlanNode start = new PlanNode(null, 0, AI_World.Instance.GetWorld().GetStates(),
|
||||
agentStates.GetStates(), null);
|
||||
|
||||
bool success = BuildGraph(start, leaves, usableActions, goal);
|
||||
|
||||
if(!success)
|
||||
{
|
||||
Debug.Log("No plan could be constructed");
|
||||
return null;
|
||||
}
|
||||
|
||||
PlanNode cheapest = null;
|
||||
foreach (PlanNode leaf in leaves)
|
||||
{
|
||||
if (cheapest == null)
|
||||
cheapest = leaf;
|
||||
else if (leaf.cost < cheapest.cost)
|
||||
cheapest = leaf;
|
||||
}
|
||||
|
||||
List<AI_Action> result = new List<AI_Action>();
|
||||
PlanNode n = cheapest;
|
||||
while (n != null)
|
||||
{
|
||||
if(n.action != null)
|
||||
{
|
||||
result.Insert(0, n.action);
|
||||
}
|
||||
n = n.parent;
|
||||
}
|
||||
|
||||
Queue<AI_Action> queue = new Queue<AI_Action>();
|
||||
foreach(AI_Action action in result)
|
||||
{
|
||||
queue.Enqueue(action);
|
||||
}
|
||||
|
||||
planDescription = "";
|
||||
int index = 0;
|
||||
foreach(AI_Action action in queue)
|
||||
{
|
||||
planDescription += index + ": " + action.actionName + "\n";
|
||||
index++;
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
private bool BuildGraph(PlanNode parent, List<PlanNode> leaves, List<AI_Action> usableActions,
|
||||
Dictionary<string, int> goal)
|
||||
{
|
||||
bool foundPath = false;
|
||||
foreach(AI_Action action in usableActions)
|
||||
{
|
||||
if(action.IsAchievableGiven(parent.states))
|
||||
{
|
||||
Dictionary<string, int> currentState = new Dictionary<string, int>(parent.states);
|
||||
foreach(KeyValuePair<string, int> effect in action.effectsDict)
|
||||
if(!currentState.ContainsKey(effect.Key))
|
||||
currentState.Add(effect.Key, effect.Value);
|
||||
|
||||
PlanNode node = new PlanNode(parent, parent.cost + action.cost, currentState, action);
|
||||
|
||||
if(GoalAchieved(goal, currentState))
|
||||
{
|
||||
leaves.Add(node);
|
||||
foundPath = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<AI_Action> subset = ActionSubset(usableActions, action);
|
||||
bool found = BuildGraph(node, leaves, subset, goal);
|
||||
if(found)
|
||||
foundPath = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundPath;
|
||||
}
|
||||
|
||||
private bool GoalAchieved(Dictionary<string, int> goals, Dictionary<string, int> state)
|
||||
{
|
||||
foreach(KeyValuePair<string, int> goal in goals)
|
||||
{
|
||||
if (!state.ContainsKey(goal.Key))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<AI_Action> ActionSubset(List<AI_Action> actions, AI_Action removeAction)
|
||||
{
|
||||
List<AI_Action> subset = new List<AI_Action>();
|
||||
foreach(AI_Action action in actions)
|
||||
{
|
||||
if(!action.Equals(removeAction))
|
||||
subset.Add(action);
|
||||
}
|
||||
return subset;
|
||||
}
|
||||
|
||||
public string GetPlanDescription()
|
||||
{
|
||||
return planDescription;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/GOAP/AI_Planner.cs.meta
Normal file
2
GOAP/Assets/Scrips/GOAP/AI_Planner.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 105223c6dcaa56146870d3dd0b4f3a13
|
||||
93
GOAP/Assets/Scrips/GOAP/AI_World.cs
Normal file
93
GOAP/Assets/Scrips/GOAP/AI_World.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public sealed class AI_World
|
||||
{
|
||||
private static readonly AI_World instance = new AI_World();
|
||||
private static AIStates worldStates;
|
||||
private static Queue<GameObject> patients;
|
||||
private static Queue<GameObject> chargers;
|
||||
private static Queue<GameObject> treatmentBeds;
|
||||
|
||||
static AI_World()
|
||||
{
|
||||
worldStates = new AIStates();
|
||||
patients = new Queue<GameObject>();
|
||||
chargers = new Queue<GameObject>();
|
||||
treatmentBeds = new Queue<GameObject>();
|
||||
|
||||
GameObject[] cubicleArray = GameObject.FindGameObjectsWithTag("Charger");
|
||||
foreach(GameObject cubicle in cubicleArray)
|
||||
{
|
||||
chargers.Enqueue(cubicle);
|
||||
}
|
||||
|
||||
if (cubicleArray.Length > 0)
|
||||
{
|
||||
worldStates.SetState("FreeCharger", cubicleArray.Length);
|
||||
}
|
||||
|
||||
GameObject[] bedArray = GameObject.FindGameObjectsWithTag("Bed");
|
||||
|
||||
foreach(GameObject bed in bedArray)
|
||||
{
|
||||
treatmentBeds.Enqueue(bed);
|
||||
}
|
||||
|
||||
if (bedArray.Length > 0)
|
||||
{
|
||||
worldStates.SetState("FreeBeds", bedArray.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private AI_World() { }
|
||||
|
||||
public void AddPatient(GameObject patient)
|
||||
{
|
||||
patients.Enqueue(patient);
|
||||
worldStates.ModifyState("Patients", 1);
|
||||
}
|
||||
|
||||
public GameObject RemovePatient()
|
||||
{
|
||||
if (patients.Count == 0) return null;
|
||||
worldStates.ModifyState("Patients", -1);
|
||||
return patients.Dequeue();
|
||||
}
|
||||
|
||||
public void AddCharger(GameObject charger)
|
||||
{
|
||||
worldStates.ModifyState("FreeCharger", 1);
|
||||
chargers.Enqueue(charger);
|
||||
}
|
||||
|
||||
public GameObject RemoveCharger()
|
||||
{
|
||||
if (chargers.Count == 0) return null;
|
||||
worldStates.ModifyState("FreeCharger", -1);
|
||||
return chargers.Dequeue();
|
||||
}
|
||||
|
||||
public void AddTreatmentBed(GameObject bed)
|
||||
{
|
||||
treatmentBeds.Enqueue(bed);
|
||||
worldStates.ModifyState("FreeBeds", 1);
|
||||
}
|
||||
|
||||
public GameObject RemoveTreatmentBed()
|
||||
{
|
||||
if (treatmentBeds.Count == 0) return null;
|
||||
worldStates.ModifyState("FreeBeds", -1);
|
||||
return treatmentBeds.Dequeue();
|
||||
}
|
||||
|
||||
public static AI_World Instance
|
||||
{
|
||||
get { return instance; }
|
||||
}
|
||||
|
||||
public AIStates GetWorld()
|
||||
{
|
||||
return worldStates;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/GOAP/AI_World.cs.meta
Normal file
2
GOAP/Assets/Scrips/GOAP/AI_World.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c9831f822b94a8dbdae2de4a63ab6e7
|
||||
70
GOAP/Assets/Scrips/GOAP/Statemachine.cs
Normal file
70
GOAP/Assets/Scrips/GOAP/Statemachine.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class AIState
|
||||
{
|
||||
public string key;
|
||||
public int value;
|
||||
}
|
||||
public class AIStates
|
||||
{
|
||||
public Dictionary<string, int> states;
|
||||
|
||||
public AIStates()
|
||||
{
|
||||
states = new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
public bool HasState(string key)
|
||||
{
|
||||
return states.ContainsKey(key);
|
||||
}
|
||||
|
||||
void AddState(string key, int value)
|
||||
{
|
||||
states.Add(key, value);
|
||||
}
|
||||
|
||||
public void ModifyState(string key, int value)
|
||||
{
|
||||
if (states.ContainsKey(key))
|
||||
{
|
||||
states[key] += value;
|
||||
if (states[key] <= 0)
|
||||
{
|
||||
RemoveState(key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddState(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveState(string key)
|
||||
{
|
||||
if (states.ContainsKey(key))
|
||||
{
|
||||
states.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetState(string key, int value)
|
||||
{
|
||||
if (states.ContainsKey(key))
|
||||
{
|
||||
states[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddState(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, int> GetStates()
|
||||
{
|
||||
return states;
|
||||
}
|
||||
}
|
||||
3
GOAP/Assets/Scrips/GOAP/Statemachine.cs.meta
Normal file
3
GOAP/Assets/Scrips/GOAP/Statemachine.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 121b61efa26f4a91a871ce8e3b0049ac
|
||||
timeCreated: 1748548853
|
||||
41
GOAP/Assets/Scrips/Human.cs
Normal file
41
GOAP/Assets/Scrips/Human.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Scrips
|
||||
{
|
||||
public class Patient : AI_Agent
|
||||
{
|
||||
[SerializeField] TextMeshProUGUI _currentStatePrint;
|
||||
[SerializeField] private Material m_Healthy;
|
||||
[SerializeField] private Material m_Sick;
|
||||
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
var s1 = new SubGoal("IsWaiting", 1, true);
|
||||
goals.Add(s1, 1);
|
||||
|
||||
var s2 = new SubGoal("IsTreated", 1, true);
|
||||
goals.Add(s2, 3);
|
||||
|
||||
var s3 = new SubGoal("IsHome", 1, true);
|
||||
goals.Add(s3, 5);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_currentStatePrint != null && planner != null)
|
||||
{
|
||||
// _currentStatePrint.text = "Nurse 1 Action: " + currentAction.actionName + "\n" + planner.GetPlanString();
|
||||
_currentStatePrint.text = "Patient 1 Action: " + currentAction.actionName + "\n";
|
||||
}
|
||||
|
||||
if( agentWorldStates.GetStates().ContainsKey("IsHealthy") &&
|
||||
agentWorldStates.GetStates()["IsHealthy"] > 0)
|
||||
{
|
||||
GetComponent<Renderer>().material = m_Healthy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
GOAP/Assets/Scrips/Human.cs.meta
Normal file
3
GOAP/Assets/Scrips/Human.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bc6d86f29a648b39e86210d37733785
|
||||
timeCreated: 1748552892
|
||||
38
GOAP/Assets/Scrips/Robot.cs
Normal file
38
GOAP/Assets/Scrips/Robot.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Robot : AI_Agent {
|
||||
|
||||
[SerializeField] TextMeshProUGUI _currentStatePrint;
|
||||
|
||||
// Start is called before the first frame update
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
SubGoal s1 = new SubGoal("TreatPatient", 1, false);
|
||||
goals.Add(s1, 3);
|
||||
|
||||
var s2 = new SubGoal("Charged", 1, false);
|
||||
goals.Add(s2, 5);
|
||||
|
||||
Invoke(nameof(GetDepleted), Random.Range(10, 20));
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_currentStatePrint != null && planner != null && currentAction != null)
|
||||
{
|
||||
// _currentStatePrint.text = "Nurse 1 Action: " + currentAction.actionName + "\n" + planner.GetPlanString();
|
||||
_currentStatePrint.text =
|
||||
"Nurse 1 Action: " + currentAction.actionName + "\n" + planner.GetPlanDescription();
|
||||
}
|
||||
}
|
||||
|
||||
void GetDepleted()
|
||||
{
|
||||
agentWorldStates.ModifyState("Depleted", 0);
|
||||
Invoke(nameof(GetDepleted), Random.Range(10, 20));
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Robot.cs.meta
Normal file
2
GOAP/Assets/Scrips/Robot.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94220d7855458a249b83ebdc1f084bbe
|
||||
42
GOAP/Assets/Scrips/Spawner.cs
Normal file
42
GOAP/Assets/Scrips/Spawner.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
public class Spawner : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameObject _spawnTemplate = null;
|
||||
[SerializeField] private int _spawnCount = 1;
|
||||
[SerializeField] private float _spawnInterval = 1.0f;
|
||||
|
||||
private float _nextSpawnTime = 0.0f;
|
||||
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
_nextSpawnTime = Time.time + _spawnInterval;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Time.time >= _nextSpawnTime)
|
||||
{
|
||||
for (int i = 0; i < _spawnCount; i++)
|
||||
{
|
||||
Spawn();
|
||||
}
|
||||
_nextSpawnTime = Time.time + _spawnInterval;
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject Spawn()
|
||||
{
|
||||
if (_spawnTemplate == null)
|
||||
{
|
||||
Debug.LogError("Spawn template is not assigned in the Spawner component.");
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject spawnedObject = Instantiate(_spawnTemplate, transform.position, transform.rotation);
|
||||
spawnedObject.transform.SetParent(transform); // Optional: Set parent to keep hierarchy organized
|
||||
return spawnedObject;
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/Spawner.cs.meta
Normal file
2
GOAP/Assets/Scrips/Spawner.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ea4287f49c95674daed326c6191fe7e
|
||||
19
GOAP/Assets/Scrips/WorldVisualizor.cs
Normal file
19
GOAP/Assets/Scrips/WorldVisualizor.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class WorldVisualizor : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public TextMeshProUGUI states;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
Dictionary<string, int> worldStates = AI_World.Instance.GetWorld().GetStates();
|
||||
states.text = "";
|
||||
foreach (KeyValuePair<string, int> pair in worldStates)
|
||||
{
|
||||
states.text += pair.Key + ", " + pair.Value + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
2
GOAP/Assets/Scrips/WorldVisualizor.cs.meta
Normal file
2
GOAP/Assets/Scrips/WorldVisualizor.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef85eecb98eba9a41bfb33950b4751e0
|
||||
Reference in New Issue
Block a user