Add most of research

This commit is contained in:
Bram verhulst
2025-05-31 15:54:23 +02:00
commit 70f128f092
270 changed files with 80847 additions and 0 deletions

View 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();
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e9e7c04605c1fa4438b738c124267f4c

View 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;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c48e5729f78aac64c8dbc08eb09aa525

View 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; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 06be48fd5f3a4298a422a72827aa61f0
timeCreated: 1748549167

View 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;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 105223c6dcaa56146870d3dd0b4f3a13

View 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;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2c9831f822b94a8dbdae2de4a63ab6e7

View 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;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 121b61efa26f4a91a871ce8e3b0049ac
timeCreated: 1748548853