diff --git a/Assets/Prefabs/Gladiator.prefab b/Assets/Prefabs/Gladiator.prefab index 5fd83e0..6c83e05 100644 --- a/Assets/Prefabs/Gladiator.prefab +++ b/Assets/Prefabs/Gladiator.prefab @@ -97,13 +97,13 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: k__BackingField: 0 - movementSpeed: 5 - rotSpeed: 3 fov: 0 attackRange: 1.5 attackDmg: 10 attackCooldown: 1 target: {fileID: 0} + stats: {fileID: 11400000, guid: 9d8a9a664d932d0498d5eca7607eeb53, type: 2} + ennemyName: Monster --- !u!58 &3988163462708087662 CircleCollider2D: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Monster.prefab b/Assets/Prefabs/Monster.prefab index e63490d..c04df97 100644 --- a/Assets/Prefabs/Monster.prefab +++ b/Assets/Prefabs/Monster.prefab @@ -104,6 +104,7 @@ MonoBehaviour: attackDmg: 10 attackCooldown: 1 target: {fileID: 0} + stats: {fileID: 11400000, guid: 9d8a9a664d932d0498d5eca7607eeb53, type: 2} --- !u!50 &1427479462206541758 Rigidbody2D: serializedVersion: 4 diff --git a/Assets/Prefabs/Vampire.prefab b/Assets/Prefabs/Vampire.prefab index 70b4266..b5017cb 100644 --- a/Assets/Prefabs/Vampire.prefab +++ b/Assets/Prefabs/Vampire.prefab @@ -65,11 +65,9 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: k__BackingField: 100 - movementSpeed: 0 - rotSpeed: 0 + bloodTokens: 1 fov: 0 attackRange: 0 - attackDmg: 0 attackCooldown: 0 target: {fileID: 0} healthBar: {fileID: 0} @@ -85,7 +83,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 56c3e06ea5db48a40a7f55e72291cb0d, type: 3} m_Name: m_EditorClassIdentifier: - minionPrefabs: [] + minionPrefabs: + - {fileID: 197677485360569561, guid: b25a487d193f24049b6a791adf592b2e, type: 3} aimArrow: {fileID: 5124059627794595469} --- !u!114 &7967951869135974023 MonoBehaviour: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 236943a..85aa05c 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -123,6 +123,17 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!114 &330576709 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 1967503440015794769, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + m_PrefabInstance: {fileID: 1942557562} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 56c3e06ea5db48a40a7f55e72291cb0d, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1001 &647315810 PrefabInstance: m_ObjectHideFlags: 0 @@ -200,9 +211,13 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 4164153230343464235, guid: 581322f036f3ff1448d4d2ec70f295a4, type: 3} + propertyPath: globalCamera + value: + objectReference: {fileID: 1557338110} - target: {fileID: 9196727425507610130, guid: 581322f036f3ff1448d4d2ec70f295a4, type: 3} propertyPath: m_RootOrder - value: 2 + value: 1 objectReference: {fileID: 0} - target: {fileID: 9196727425507610130, guid: 581322f036f3ff1448d4d2ec70f295a4, type: 3} propertyPath: m_LocalPosition.x @@ -282,7 +297,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1878107874060227351, guid: e1dac4f28fe75a547b919b7aa8240fed, type: 3} propertyPath: m_RootOrder - value: 3 + value: 2 objectReference: {fileID: 0} - target: {fileID: 1878107874060227351, guid: e1dac4f28fe75a547b919b7aa8240fed, type: 3} propertyPath: m_AnchorMax.x @@ -377,6 +392,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 81a29b049c6380f4abb3c18ed121efcd, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!1 &1557338110 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 3328484984159178892, guid: f7f5d2b1228d13f4d9015073aced3e81, type: 3} + m_PrefabInstance: {fileID: 647315810} + m_PrefabAsset: {fileID: 0} --- !u!1001 &1942557562 PrefabInstance: m_ObjectHideFlags: 0 @@ -386,7 +406,7 @@ PrefabInstance: m_Modifications: - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.size - value: 14 + value: 15 objectReference: {fileID: 0} - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.data[13].m_ActionId @@ -404,33 +424,57 @@ PrefabInstance: propertyPath: m_ActionEvents.Array.data[13].m_PersistentCalls.m_Calls.Array.data[0].m_Mode value: 0 objectReference: {fileID: 0} + - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + propertyPath: m_ActionEvents.Array.data[14].m_PersistentCalls.m_Calls.Array.data[0].m_Mode + value: 0 + objectReference: {fileID: 0} - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.data[13].m_PersistentCalls.m_Calls.Array.data[0].m_Target value: objectReference: {fileID: 1551362087} + - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + propertyPath: m_ActionEvents.Array.data[14].m_PersistentCalls.m_Calls.Array.data[0].m_Target + value: + objectReference: {fileID: 330576709} - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.data[13].m_PersistentCalls.m_Calls.Array.data[0].m_CallState value: 2 objectReference: {fileID: 0} + - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + propertyPath: m_ActionEvents.Array.data[14].m_PersistentCalls.m_Calls.Array.data[0].m_CallState + value: 2 + objectReference: {fileID: 0} - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.data[13].m_PersistentCalls.m_Calls.Array.data[0].m_MethodName value: ChangeSelectedIcon objectReference: {fileID: 0} + - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + propertyPath: m_ActionEvents.Array.data[14].m_PersistentCalls.m_Calls.Array.data[0].m_MethodName + value: ToggleThrowMode + objectReference: {fileID: 0} - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.data[13].m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName value: MinionBar, Assembly-CSharp objectReference: {fileID: 0} + - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + propertyPath: m_ActionEvents.Array.data[14].m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName + value: MinionThrower, Assembly-CSharp + objectReference: {fileID: 0} - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_ActionEvents.Array.data[13].m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName value: UnityEngine.Object, UnityEngine objectReference: {fileID: 0} + - target: {fileID: 1214567908930553477, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} + propertyPath: m_ActionEvents.Array.data[14].m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName + value: UnityEngine.Object, UnityEngine + objectReference: {fileID: 0} - target: {fileID: 1214567908930553593, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_Name value: Vampire objectReference: {fileID: 0} - target: {fileID: 1214567908930553594, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_RootOrder - value: 1 + value: 3 objectReference: {fileID: 0} - target: {fileID: 1214567908930553594, guid: 3e0aae8cda56aef44af9598dc5471020, type: 3} propertyPath: m_LocalPosition.x diff --git a/Assets/Scripts/AI Stats.asset b/Assets/Scripts/AI Stats.asset new file mode 100644 index 0000000..fc57117 --- /dev/null +++ b/Assets/Scripts/AI Stats.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4cd7eb51def0c7747bd646073babaf4f, type: 3} + m_Name: AI Stats + m_EditorClassIdentifier: + closeEnough: 2 diff --git a/Assets/Scripts/AI Stats.asset.meta b/Assets/Scripts/AI Stats.asset.meta new file mode 100644 index 0000000..c420059 --- /dev/null +++ b/Assets/Scripts/AI Stats.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d8a9a664d932d0498d5eca7607eeb53 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/AIEntity.cs b/Assets/Scripts/AIEntity.cs new file mode 100644 index 0000000..81e0ab6 --- /dev/null +++ b/Assets/Scripts/AIEntity.cs @@ -0,0 +1,103 @@ +#nullable enable +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class AIEntity : Entity +{ + [SerializeField] AIStats stats = null!; + public string ennemyName {get; protected set; } + + abstract class BaseStateAI : BaseState{ + protected AIEntity entity; + public BaseStateAI(AIEntity entity){ + this.entity = entity; + } + } + + class SeekState : BaseStateAI{ + public SeekState(AIEntity entity) : base(entity){ + + } + + public override BaseState? UpdateState(){ + Entity targetEntity = entity.GetTarget().GetComponent(); + if(targetEntity != null){ + if(targetEntity.IsAlive()){//target is alive, keep chasing it + return null; + }else{//target is dead, go to findTargetState + return new FindTargetState(entity);; + } + } + return null; + } + + public override BaseState? FixedUpdateState(){ + Transform target = entity.GetTarget(); + entity.direction = Vector3.RotateTowards(entity.direction, (target.position - entity.transform.position), entity.rotSpeed*Time.fixedDeltaTime, 0.0f); + if(!entity.IsInAttackRange()){ + entity.rb.MovePosition(entity.transform.position + entity.direction * entity.movementSpeed * Time.fixedDeltaTime); + }else{ + return new AttackState(entity); + } + return null; + } + } + + class FindTargetState : BaseStateAI{ + float closeEnough; + public FindTargetState(AIEntity entity) : base(entity){ + } + + public override BaseState? UpdateState(){ + Entity[] entities = FindObjectsOfType(); + float lastDist = -1; + Entity chosenEntity = null!; + foreach (Entity other in entities){// Find the closest entity + if(other.name == entity.ennemyName){ + float distance = Vector2.Distance(other.transform.position, entity.transform.position); + if(distance < lastDist){ + lastDist = distance; + chosenEntity = other; + if(lastDist <= entity.stats.closeEnough)break; + } + } + } + if(chosenEntity != null){ + entity.SetTarget(chosenEntity.transform); + } + return new SeekState(entity); + } + + } + + class AttackState : BaseStateAI{ + public AttackState(AIEntity entity) : base(entity){ + } + + public override BaseState? UpdateState(){ + if(entity.IsInAttackRange()){ + if(entity.attackTimer >= entity.attackCooldown){ + entity.attackTimer = 0; + return Attack(); + }else{ + entity.attackTimer += Time.deltaTime; + } + + } + return null; + } + + private BaseState? Attack(){ + Entity targetEntity = entity.GetTarget().GetComponent(); + if(targetEntity != null){ + targetEntity.TakeDamage(entity.attackDmg); + bool isTargetAlive = targetEntity.IsAlive(); + if(!isTargetAlive){ + return new FindTargetState(entity); + } + } + return null; + } + } +} diff --git a/Assets/Scripts/AIEntity.cs.meta b/Assets/Scripts/AIEntity.cs.meta new file mode 100644 index 0000000..75d2700 --- /dev/null +++ b/Assets/Scripts/AIEntity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9081d4ec2499ba4ab3e13006869bfaf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/AIStats.cs b/Assets/Scripts/AIStats.cs new file mode 100644 index 0000000..e1d503a --- /dev/null +++ b/Assets/Scripts/AIStats.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +[CreateAssetMenu] +public class AIStats : ScriptableObject { + public float closeEnough = 1f; +} \ No newline at end of file diff --git a/Assets/Scripts/AIStats.cs.meta b/Assets/Scripts/AIStats.cs.meta new file mode 100644 index 0000000..6fe625f --- /dev/null +++ b/Assets/Scripts/AIStats.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4cd7eb51def0c7747bd646073babaf4f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/BloodSucker.cs b/Assets/Scripts/BloodSucker.cs index 81e6187..064ee24 100644 --- a/Assets/Scripts/BloodSucker.cs +++ b/Assets/Scripts/BloodSucker.cs @@ -50,8 +50,9 @@ public class BloodSucker : MonoBehaviour { foreach (Collider2D coll in Physics2D.OverlapCircleAll(transform.position, suckRange)) { Entity entity = coll.GetComponent(); if (entity != null && entity.gameObject != gameObject) { - // TODO : check if target is dead - SetTarget(entity); + if (!entity.IsAlive()) { + SetTarget(entity); + } } } } @@ -74,7 +75,7 @@ public class BloodSucker : MonoBehaviour { if (currentSuckTimer < 0f) { currentTarget.bloodTokens -= 1; // print("One token sucked"); - if(currentTarget.bloodTokens == 0) { + if (currentTarget.bloodTokens == 0) { SetTarget(null); isSucking = false; } diff --git a/Assets/Scripts/Entity.cs b/Assets/Scripts/Entity.cs index fecedb5..617a054 100644 --- a/Assets/Scripts/Entity.cs +++ b/Assets/Scripts/Entity.cs @@ -5,20 +5,21 @@ using UnityEngine; [RequireComponent(typeof(Rigidbody2D))] public class Entity : MonoBehaviour { - [field: SerializeField]public float Health { get; private set; } + [field: SerializeField]public float Health {get; private set; } public int bloodTokens = 1; - [SerializeField]private float movementSpeed; - [SerializeField]private float rotSpeed; + bool isAlive = true; + [SerializeField]public float movementSpeed{get; private set; } + [SerializeField]public float rotSpeed {get; private set; } [SerializeField]private float fov; [SerializeField]private float attackRange; - [SerializeField]private float attackDmg; + [SerializeField]public float attackDmg {get; private set; } [SerializeField]protected float attackCooldown; protected float attackTimer; [SerializeField]private Transform target; - private new string name; + public string entityName {get; protected set; } private Collider atkCollider; - private Vector3 direction; - Rigidbody2D rb; + public Vector3 direction {get; set; } + public Rigidbody2D rb {get; private set;} void Awake() => rb = GetComponent(); @@ -28,11 +29,6 @@ public class Entity : MonoBehaviour } protected virtual void Attack(){ - // jason: TODO Either have target be Entity instead of transform, or skip Attack when GetComponent() is null - Entity targetEntity = target.GetComponent(); - if(targetEntity != null){ - bool isTargetAlive = targetEntity.TakeDamage(attackDmg); - } } @@ -61,19 +57,12 @@ public class Entity : MonoBehaviour public virtual bool TakeDamage(float amount){ Health -= amount; if(Health <= 0){ + isAlive = false; return false; } return true; } - public void SetName(string name){ - this.name = name; - } - - protected string GetName(){ - return this.name; - } - protected bool IsInAttackRange(){ return Vector2.Distance(transform.position, target.position) <= attackRange; } @@ -82,4 +71,8 @@ public class Entity : MonoBehaviour float angle = Vector2.SignedAngle(direction, (target.position - transform.position)); return angle >= -fov && angle <= fov; } + + public bool IsAlive(){ + return isAlive; + } } diff --git a/Assets/Scripts/Gladiator.cs b/Assets/Scripts/Gladiator.cs index 81da14e..628a1d7 100644 --- a/Assets/Scripts/Gladiator.cs +++ b/Assets/Scripts/Gladiator.cs @@ -2,13 +2,14 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public class Gladiator : Entity +public class Gladiator : AIEntity { // Start is called before the first frame update override protected void Start() { base.Start(); - base.SetName("Gladiator"); + base.entityName = "Gladiator"; + base.ennemyName = "Monster"; } // Update is called once per frame diff --git a/Assets/Scripts/Monster.cs b/Assets/Scripts/Monster.cs index 77bd059..91d3042 100644 --- a/Assets/Scripts/Monster.cs +++ b/Assets/Scripts/Monster.cs @@ -2,13 +2,14 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public class Monster : Entity +public class Monster : AIEntity { // Start is called before the first frame update override protected void Start() { base.Start(); - base.SetName("Monster"); + base.entityName = "Monster"; + base.ennemyName = "Gladiator"; } void FixedUpdate() => MoveToTarget(Time.fixedDeltaTime); diff --git a/Assets/Scripts/VampireEntity.cs b/Assets/Scripts/VampireEntity.cs index 51561e8..a5bc04d 100644 --- a/Assets/Scripts/VampireEntity.cs +++ b/Assets/Scripts/VampireEntity.cs @@ -8,7 +8,7 @@ public class VampireEntity : Entity { protected override void Start() { base.Start(); - SetName("Vampire"); + base.entityName = "Vampire"; initialHealth = Health; }