diff --git a/Assets/Prefabs/projectile.meta b/Assets/Prefabs/projectile.meta new file mode 100644 index 00000000..75c8c807 --- /dev/null +++ b/Assets/Prefabs/projectile.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 260c19d2a0b76c34c956581dfa0d973e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/projectile/_LazerPrọectile.prefab b/Assets/Prefabs/projectile/_LazerPrọectile.prefab new file mode 100644 index 00000000..78737243 --- /dev/null +++ b/Assets/Prefabs/projectile/_LazerPrọectile.prefab @@ -0,0 +1,249 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3965388737199864462 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3931626442576998839} + - component: {fileID: 3709300698874473534} + - component: {fileID: 8126964110933236075} + - component: {fileID: 411349647056113735} + - component: {fileID: 2417107839128453854} + - component: {fileID: 6433774282585127385} + m_Layer: 0 + m_Name: "_LazerPr\u1ECDectile" + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3931626442576998839 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3965388737199864462} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.69, z: 0.267} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3709300698874473534 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3965388737199864462} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8126964110933236075 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3965388737199864462} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9193f4635bbf98d46be9a6357461aa10, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!135 &411349647056113735 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3965388737199864462} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!96 &2417107839128453854 +TrailRenderer: + serializedVersion: 4 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3965388737199864462} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10308, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_Time: 0.5 + m_PreviewTimeScale: 1 + m_Parameters: + serializedVersion: 3 + widthMultiplier: 0.1 + widthCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0.9218468 + outSlope: 0.9218468 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.1878327 + - serializedVersion: 3 + time: 0.9828102 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + colorGradient: + serializedVersion: 2 + key0: {r: 1, g: 0, b: 0, a: 1} + key1: {r: 1, g: 0, b: 0, a: 1} + key2: {r: 1, g: 1, b: 1, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 36006 + ctime2: 65535 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: 0 + m_NumColorKeys: 3 + m_NumAlphaKeys: 2 + numCornerVertices: 0 + numCapVertices: 0 + alignment: 0 + textureMode: 0 + textureScale: {x: 1, y: 1} + shadowBias: 0.5 + generateLightingData: 0 + m_MinVertexDistance: 0.1 + m_Autodestruct: 0 + m_Emitting: 1 + m_ApplyActiveColorSpace: 1 +--- !u!114 &6433774282585127385 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3965388737199864462} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e4f602386d4d484ea7a2a3b0c19ac21, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::LaserProjectile + speed: 5 + lifeTime: 5 diff --git a/Assets/Prefabs/projectile/_LazerPrọectile.prefab.meta b/Assets/Prefabs/projectile/_LazerPrọectile.prefab.meta new file mode 100644 index 00000000..408b2ca5 --- /dev/null +++ b/Assets/Prefabs/projectile/_LazerPrọectile.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fbec2b501d70daa4c9cb481ba53fc0b8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/AI NPC/EnemyAI.cs b/Assets/Scripts/AI NPC/EnemyAI.cs index 38fa44ca..41210a9f 100644 --- a/Assets/Scripts/AI NPC/EnemyAI.cs +++ b/Assets/Scripts/AI NPC/EnemyAI.cs @@ -3,71 +3,171 @@ using UnityEngine; public class EnemyAI : MonoBehaviour { + [Header("References")] public Transform player; + + [Header("Detection")] public float detectRange = 10f; public float moveSpeed = 3f; public float rotateSpeed = 50f; - public bool isAttackReady; + + [Header("Artifact")] + public bool playerHasArtifact; + + [Header("Laser")] + public GameObject laserPrefab; + public Transform firePoint; + public float minShootDelay = 1f; + public float maxShootDelay = 3f; + + private float nextShootTime; public Node behaviorTreeRoot; - // Start is called once before the first execution of Update after the MonoBehaviour is created - void Start() + private void Start() { + nextShootTime = Time.time + Random.Range(minShootDelay, maxShootDelay); InitBehaviorTree(); } - // Update is called once per frame - void Update() + private void Update() { - if (behaviorTreeRoot != null) - { - behaviorTreeRoot.Evaluate(); - } + behaviorTreeRoot?.Evaluate(); } - void InitBehaviorTree() + private void InitBehaviorTree() { + // Player có artifact -> focus + shoot + var laserSequence = new Sequence(new List + { + new TaskNode(CheckHasArtifact), + new TaskNode(ActionFocusAndShoot) + }); + + // Thấy player -> chạy tới var chaseSequence = new Sequence(new List { new TaskNode(CheckCanSeePlayer), new TaskNode(ActionMoveToPlayer) }); - var rotationScanNode = new TaskNode(ActionRotationScan); + + // Không thấy ai -> scan + var scanNode = new TaskNode(ActionRotationScan); + behaviorTreeRoot = new Selector(new List { + laserSequence, chaseSequence, - rotationScanNode + scanNode }); } - private NodeState ActionRotationScan() - { - Debug.Log("ActionRotationScan"); - transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime); - return NodeState.Running; - } + #region CONDITIONS - private NodeState ActionMoveToPlayer() + private NodeState CheckHasArtifact() { - Debug.Log($"Moving to Player"); - Vector3 dir = (player.position - transform.position).normalized; - transform.position += dir * moveSpeed * Time.deltaTime; - return NodeState.Running; + return playerHasArtifact + ? NodeState.Success + : NodeState.Failure; } private NodeState CheckCanSeePlayer() { if (player == null) - { return NodeState.Failure; - } - float distance = Vector3.Distance(transform.position,player.position); - if (distance < detectRange) + + float distance = + Vector3.Distance(transform.position, player.position); + + if (distance <= detectRange) { - Debug.Log($"Player detected!"); return NodeState.Success; } + return NodeState.Failure; } + + #endregion + + #region ACTIONS + + private NodeState ActionRotationScan() + { + Debug.Log("Scanning..."); + + transform.Rotate( + Vector3.up, + rotateSpeed * Time.deltaTime); + + return NodeState.Running; + } + + private NodeState ActionMoveToPlayer() + { + if (player == null) + return NodeState.Failure; + + Debug.Log("Chasing Player"); + + Vector3 dir = + (player.position - transform.position).normalized; + + transform.position += + dir * + moveSpeed * + Time.deltaTime; + + return NodeState.Running; + } + + private NodeState ActionFocusAndShoot() + { + if (player == null) + return NodeState.Failure; + + // Focus player + Vector3 dir = + player.position - transform.position; + + dir.y = 0f; + + if (dir != Vector3.zero) + { + Quaternion targetRotation = + Quaternion.LookRotation(dir); + + transform.rotation = + Quaternion.Slerp( + transform.rotation, + targetRotation, + 5f * Time.deltaTime); + } + + // Shoot with random delay + if (Time.time >= nextShootTime) + { + ShootLaser(); + + nextShootTime = + Time.time + + Random.Range(minShootDelay, maxShootDelay); + } + + return NodeState.Running; + } + + private void ShootLaser() + { + if (laserPrefab == null || firePoint == null) + return; + + Instantiate( + laserPrefab, + firePoint.position, + firePoint.rotation); + + Debug.Log("Laser Shot!"); + } + + #endregion } \ No newline at end of file diff --git a/Assets/Scripts/AI NPC/LaserProjectile.cs b/Assets/Scripts/AI NPC/LaserProjectile.cs new file mode 100644 index 00000000..01bffd8e --- /dev/null +++ b/Assets/Scripts/AI NPC/LaserProjectile.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +public class LaserProjectile : MonoBehaviour +{ + public float speed = 5f; + public float lifeTime = 5f; + + private void Start() + { + Destroy(gameObject, lifeTime); + } + + private void Update() + { + transform.position += + transform.forward * + speed * + Time.deltaTime; + } + + private void OnTriggerEnter(Collider other) + { + if (other.CompareTag("Player")) + { + Debug.Log("Player Hit"); + + Destroy(gameObject); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/AI NPC/LaserProjectile.cs.meta b/Assets/Scripts/AI NPC/LaserProjectile.cs.meta new file mode 100644 index 00000000..54bf4034 --- /dev/null +++ b/Assets/Scripts/AI NPC/LaserProjectile.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4e4f602386d4d484ea7a2a3b0c19ac21 \ No newline at end of file diff --git a/Assets/Scripts/AI NPC/RagNPC.cs b/Assets/Scripts/AI NPC/RagNPC.cs new file mode 100644 index 00000000..d4dec279 --- /dev/null +++ b/Assets/Scripts/AI NPC/RagNPC.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +public class RagNPC : MonoBehaviour +{ + // Start is called once before the first execution of Update after the MonoBehaviour is created + void Start() + { + + } + + // Update is called once per frame + void Update() + { + + } +} diff --git a/Assets/Scripts/AI NPC/RagNPC.cs.meta b/Assets/Scripts/AI NPC/RagNPC.cs.meta new file mode 100644 index 00000000..04e171a8 --- /dev/null +++ b/Assets/Scripts/AI NPC/RagNPC.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 30cdc86fe97fa95428a4b31052cfb22f \ No newline at end of file