diff --git a/Scripts/Characters/AI/Simple/Activity.cs b/Scripts/Characters/AI/Simple/Activity.cs index d27e5d1..c5105ce 100644 --- a/Scripts/Characters/AI/Simple/Activity.cs +++ b/Scripts/Characters/AI/Simple/Activity.cs @@ -6,7 +6,8 @@ namespace CharacterModel { - public class Activity : MonoBehaviour { + [System.Serializable] + public class Activity { public ENeeds need; public float satisfaction; diff --git a/Scripts/Characters/AI/Simple/ActivityChoice.cs b/Scripts/Characters/AI/Simple/ActivityChoice.cs new file mode 100644 index 0000000..05c624b --- /dev/null +++ b/Scripts/Characters/AI/Simple/ActivityChoice.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.AI; + +namespace CharacterModel { + + + [System.Serializable] + public class ActivityChoice : IComparer, System.IComparable { + [SerializeField] public Activity activity; + //[SerializeField] public AbstractNeedEvaluator evaluator; + public float desirability = 0; // This is to be calculated during decision making, not preset as data + + // Getting and setting desirability + public float GetDesirability(CoreNeeds needs, float situation) + => needs.GetNeed(activity.need).Evaluator.GetDesirability(this, needs.GetNeed(activity.need), situation); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetDesirability(CoreNeeds needs, float situation) { + needs.GetNeed(activity.need).Evaluator.SetDesirability(this, needs.GetNeed(activity.need), situation); + } + + // Comparisons -- desirability is the basis, since the more desirable choices willl be preferred + // Compare() and CompareTo() are set up so that sort functions will place higher desirability on top + public static bool operator >(ActivityChoice a, ActivityChoice b) => a.desirability > b.desirability; + public static bool operator <(ActivityChoice a, ActivityChoice b) => a.desirability < b.desirability; + public static bool operator >=(ActivityChoice a, ActivityChoice b) => a.desirability >= b.desirability; + public static bool operator <=(ActivityChoice a, ActivityChoice b) => a.desirability <= b.desirability; + public int Compare(ActivityChoice a, ActivityChoice b) { + return -a.desirability.CompareTo(b.desirability); // Should I do this, or use arithmetic? + } + public int CompareTo(ActivityChoice other) { + return -desirability.CompareTo(other.desirability); // Should I do this, or use arithmetic? + } + } + +} \ No newline at end of file diff --git a/Scripts/Characters/AI/Simple/ActivityChoice.cs.meta b/Scripts/Characters/AI/Simple/ActivityChoice.cs.meta new file mode 100644 index 0000000..79153bb --- /dev/null +++ b/Scripts/Characters/AI/Simple/ActivityChoice.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 60c143f28acd8f4c780a66d374e21453 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Characters/AI/Simple/ActivityChooser.cs b/Scripts/Characters/AI/Simple/ActivityChooser.cs index 4d1f57b..91d3f91 100644 --- a/Scripts/Characters/AI/Simple/ActivityChooser.cs +++ b/Scripts/Characters/AI/Simple/ActivityChooser.cs @@ -8,37 +8,13 @@ namespace CharacterModel { public class ActivityChooser : MonoBehaviour { - - [System.Serializable] - public class ActivityChoice : IComparer, System.IComparable { - [SerializeField] public Activity activity; - //[SerializeField] public AbstractNeedEvaluator evaluator; - public float desirability = 0; - public float GetDesirability(CoreNeeds needs, float situation) - => needs.GetNeed(activity.need).Evaluator.GetDesirability(this, needs.GetNeed(activity.need), situation); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetDesirability(CoreNeeds needs, float situation) { - needs.GetNeed(activity.need).Evaluator.SetDesirability(this, needs.GetNeed(activity.need), situation); - } - public static bool operator >(ActivityChoice a, ActivityChoice b) => a.desirability > b.desirability; - public static bool operator <(ActivityChoice a, ActivityChoice b) => a.desirability < b.desirability; - public static bool operator >=(ActivityChoice a, ActivityChoice b) => a.desirability >= b.desirability; - public static bool operator <=(ActivityChoice a, ActivityChoice b) => a.desirability <= b.desirability; - public int Compare(ActivityChoice a, ActivityChoice b) { - return -a.desirability.CompareTo(b.desirability); // Should I do this, or use arithmetic? - } - public int CompareTo(ActivityChoice other) { - return -desirability.CompareTo(other.desirability); // Should I do this, or use arithmetic? - } - } - - [SerializeField] List choices = new List(); [SerializeField] Character character; [SerializeField] CoreNeeds needs; private float activityTimer = 0; private bool atLoction = false; + private bool ready = false; //Testing Stuff [SerializeField] GameObject testingPlaceShower; @@ -57,6 +33,7 @@ void Start() // FIXME/TODO: This ultimately needs to be removed, but first it must be replaced with a call from outside void Update() { + if(!ready) return; if(activityTimer <= 0) { currentChoice = Choose(); testingPlaceShower.transform.position = currentChoice.actorLocation.position; @@ -66,13 +43,13 @@ void Update() else needs.Situation = 0.2f; navAgent.SetDestination(currentChoice.actorLocation.position); atLoction = false; - testingPlaceShower.SetActive(false); } else { //FIXME: Remember, in the real game anything similar must use worled (simulation) time, not engine game time! if(atLoction) { + transform.rotation = currentChoice.actorLocation.rotation; activityTimer -= Time.deltaTime; needs.GetNeed(currentChoice.need).AddSafe((currentChoice.satisfaction / currentChoice.timeToDo) - * Time.deltaTime); + * Time.deltaTime); } else { atLoction = navAgent.remainingDistance < 0.1f; testingPlaceShower.SetActive(atLoction); @@ -126,6 +103,13 @@ public Activity Choose() { } + public void AssignChoices(List availableChoices) { + choices.Clear(); + foreach(ActivityChoice choice in availableChoices) choices.Add(choice); + ready = true; + } + + } diff --git a/Scripts/Characters/AI/Simple/ActivityHolder.cs b/Scripts/Characters/AI/Simple/ActivityHolder.cs new file mode 100644 index 0000000..7b4f77c --- /dev/null +++ b/Scripts/Characters/AI/Simple/ActivityHolder.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.AI; + +namespace CharacterModel { + + + [System.Serializable] + public class ActivityHolder : MonoBehaviour { + + [SerializeField] ActivityChoice[] activities; + + public ActivityChoice[] Activities => activities; + public ActivityChoice GetActivityChoice(int n) => activities[n]; + public Activity GetActivity(int n) => activities[n].activity; + + + public void AddActivities(ref List mainList) { + foreach(ActivityChoice activity in Activities) { + mainList.Add(activity); + } + } + + + // TODO: It seems I need more, but not sure what yet + + } + + + +} \ No newline at end of file diff --git a/Scripts/Characters/AI/Simple/ActivityHolder.cs.meta b/Scripts/Characters/AI/Simple/ActivityHolder.cs.meta new file mode 100644 index 0000000..acd9d13 --- /dev/null +++ b/Scripts/Characters/AI/Simple/ActivityHolder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5c0da1ab2b64508bdada960b13e966c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Characters/Character.cs b/Scripts/Characters/Character.cs index 6a1da07..a5b199b 100644 --- a/Scripts/Characters/Character.cs +++ b/Scripts/Characters/Character.cs @@ -23,6 +23,8 @@ public class Character : MonoBehaviour { [SerializeField] EmotionalState emotions; [SerializeField] Preferences preferences; + [SerializeField] ActivityChooser ai; + public static ulong IDCount => idCounter; public Personality Persona => personality; @@ -30,6 +32,8 @@ public class Character : MonoBehaviour { public EmotionalState Emotions => emotions; public Preferences prefs => preferences; + public ActivityChooser AI => ai; // FIXME? TODO? Should it really be part of a bigger AI module? + /// /// Set the ID of a new character; this should be done when character is created and should never change diff --git a/Scripts/Characters/State/AbstractNeedEvaluator.cs b/Scripts/Characters/State/AbstractNeedEvaluator.cs index d85c7a0..aa003e2 100644 --- a/Scripts/Characters/State/AbstractNeedEvaluator.cs +++ b/Scripts/Characters/State/AbstractNeedEvaluator.cs @@ -6,9 +6,9 @@ namespace CharacterModel { public abstract class AbstractNeedEvaluator : ScriptableObject { - public abstract float GetDesirability(ActivityChooser.ActivityChoice choice, Need need, float extraData = 0f); + public abstract float GetDesirability(ActivityChoice choice, Need need, float extraData = 0f); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public abstract void SetDesirability(ActivityChooser.ActivityChoice choice, Need need, float extraData = 0f); + public abstract void SetDesirability(ActivityChoice choice, Need need, float extraData = 0f); } } \ No newline at end of file diff --git a/Scripts/Characters/State/DepletingNeedEvaluator.cs b/Scripts/Characters/State/DepletingNeedEvaluator.cs index df4c85f..1977205 100644 --- a/Scripts/Characters/State/DepletingNeedEvaluator.cs +++ b/Scripts/Characters/State/DepletingNeedEvaluator.cs @@ -9,12 +9,12 @@ namespace CharacterModel { [CreateAssetMenu(menuName = "Character Engine/AI/Depleting Need Evaluator", order = 1001, fileName = "DepletingEvaluator")] public class DepletingNeedEvaluator : AbstractNeedEvaluator { - public override float GetDesirability(ActivityChooser.ActivityChoice choice, Need need, float unused = 0f) { + public override float GetDesirability(ActivityChoice choice, Need need, float unused = 0f) { SetDesirability(choice, need); return choice.desirability; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override void SetDesirability(ActivityChooser.ActivityChoice choice, Need need, float unused = 0f) { + public override void SetDesirability(ActivityChoice choice, Need need, float unused = 0f) { choice.desirability = (choice.activity.satisfaction + (choice.activity.satisfaction / (choice.activity.timeToDo + 5))) * need.GetDrive() * Need.TIME_SCALE; diff --git a/Scripts/Characters/State/SituationalNeedTracker.cs b/Scripts/Characters/State/SituationalNeedTracker.cs index c3b4b49..7a0976a 100644 --- a/Scripts/Characters/State/SituationalNeedTracker.cs +++ b/Scripts/Characters/State/SituationalNeedTracker.cs @@ -9,12 +9,12 @@ namespace CharacterModel { [CreateAssetMenu(menuName = "Character Engine/AI/Situational Need Evaluator", order = 1002, fileName = "SituationalEvaluator")] public class SituationalNeedTracker : AbstractNeedEvaluator { - public override float GetDesirability(ActivityChooser.ActivityChoice choice, Need need, float situation) { + public override float GetDesirability(ActivityChoice choice, Need need, float situation) { SetDesirability(choice, need, situation); return choice.desirability; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override void SetDesirability(ActivityChooser.ActivityChoice choice, Need need, float situation) { + public override void SetDesirability(ActivityChoice choice, Need need, float situation) { choice.desirability = (choice.activity.satisfaction - situation) * need.GetDrive() * Need.TIME_SCALE; } diff --git a/Scripts/Characters/State/VitalNeedTracker.cs b/Scripts/Characters/State/VitalNeedTracker.cs index 03f5456..02f4adb 100644 --- a/Scripts/Characters/State/VitalNeedTracker.cs +++ b/Scripts/Characters/State/VitalNeedTracker.cs @@ -9,18 +9,20 @@ namespace CharacterModel { [CreateAssetMenu(menuName = "Character Engine/AI/Vital Need Evaluator", order = 1003, fileName = "VitalEvaluator")] public class VitalNeedTracker : AbstractNeedEvaluator { - public override float GetDesirability(ActivityChooser.ActivityChoice choice, Need need, float situation) { + public override float GetDesirability(ActivityChoice choice, Need need, float situation) { SetDesirability(choice, need, situation); return choice.desirability; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override void SetDesirability(ActivityChooser.ActivityChoice choice, Need need, float situation) { + public override void SetDesirability(ActivityChoice choice, Need need, float situation) { choice.desirability = (choice.activity.satisfaction - situation) * need.GetDrive() * Need.TIME_SCALE; choice.desirability *= choice.desirability; } - public float GetDrive(ActivityChooser.ActivityChoice choice, Need need) { + public float GetDrive(ActivityChoice choice, Need need) { return (Mathf.Max((need.DriveOrigin - need.Value), 0f) / Mathf.Clamp(need.Value - 0.2f, 0.01f, 0.4f) * need.Importance); } diff --git a/Scripts/Characters/Trait/Skills.cs b/Scripts/Characters/Trait/Skills.cs new file mode 100644 index 0000000..df6f9cf --- /dev/null +++ b/Scripts/Characters/Trait/Skills.cs @@ -0,0 +1,72 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using CharacterEngine; + + +namespace CharacterModel { + + [System.Serializable] + public class Skills { + [SerializeField] Skill[] coreSkills = new Skill[17]; + + + + + + } + + + + #region SkillEnums + public enum ECoreSkills { + //Physical + Athletics = 0, + Dancing = 1, + Driving = 2, + MartialArts = 3, + + //Creative + Art = 4, + Music = 5, + Writing = 6, + + //Intellectual + Science = 7, + Mechanical = 8, + Computers = 9, + Gaming = 10, + + //Social + Charm = 11, + Performance = 12, + Persuasion = 13, + + //Practical + Business = 14, + Cooking = 15, + Housekeeping = 16, + Naturalist = 17 + } + + + public enum EChildSkills { + Physical = 0, + Creative = 1, + Intellectual = 2, + Social = 3, + Practical = 4 + } + + + public enum EHiddenSkills { + Physical = 0, + Creative = 1, + Intellectual = 2, + Social = 3, + Practical = 4 + } + #endregion + + +} \ No newline at end of file diff --git a/Scripts/Characters/Trait/Skills.cs.meta b/Scripts/Characters/Trait/Skills.cs.meta new file mode 100644 index 0000000..783d88e --- /dev/null +++ b/Scripts/Characters/Trait/Skills.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0dde3ee085aeaf61988971b716234325 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Characters/World/LotManager.cs b/Scripts/Characters/World/LotManager.cs new file mode 100644 index 0000000..06645c3 --- /dev/null +++ b/Scripts/Characters/World/LotManager.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.AI; + +namespace CharacterModel { + + + [System.Serializable] + public class LotManager : MonoBehaviour { + [SerializeField] List usableObjects; + [SerializeField] List characters; + + private List choices; + + // Start is called before the first frame update + void Start() { + choices = new List(); + foreach(ActivityHolder usableObject in usableObjects) { + usableObject.AddActivities(ref choices); + } + foreach(Character character in characters) { + character.AI.AssignChoices(choices); + } + } + + /*// Update is called once per frame + void Update() { + + }*/ + } + +} \ No newline at end of file diff --git a/Scripts/Characters/World/LotManager.cs.meta b/Scripts/Characters/World/LotManager.cs.meta new file mode 100644 index 0000000..8204a33 --- /dev/null +++ b/Scripts/Characters/World/LotManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 808dcc263abb58f9ea774437c87119ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: