From fa810bf97056aa9d0236ef983354818b7e4f89db Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 10 Nov 2025 16:06:21 -0500 Subject: [PATCH] added: enemy target acquisition, better pathfinding, moved combat reference to unit --- .../Enemies/Common/Graphs/BasicEnemyFSM.asset | 21 ++- .../TestEnemy/Graphs/TestEnemyCombatFSM.asset | 24 +++ .../Graphs/TestEnemyCombatFSM.asset.meta | 8 + .../TestMonsterModelAnimController.controller | 164 ++++++++++++++++++ .../TestEnemy/Objects/TestMonster.prefab | 39 +++-- Assets/Scripts/Units/Enemy/EnemyCombat.cs | 9 +- Assets/Scripts/Units/Enemy/EnemySpawn.cs | 35 +++- .../Units/Graph Tasks/CheckIfSpawnmate.cs | 35 ++++ .../Graph Tasks/CheckIfSpawnmate.cs.meta | 2 + .../Units/Graph Tasks/SetWanderingPath.cs | 64 +++++++ .../Graph Tasks/SetWanderingPath.cs.meta | 2 + Assets/Scripts/Units/Unit.cs | 8 + ...EnemyPathfinding.cs => UnitPathfinding.cs} | 48 +---- Assets/Scripts/Units/UnitPathfinding.cs.meta | 2 + 14 files changed, 398 insertions(+), 63 deletions(-) create mode 100644 Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset create mode 100644 Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset.meta create mode 100644 Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs create mode 100644 Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs.meta create mode 100644 Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs create mode 100644 Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs.meta rename Assets/Scripts/Units/{Enemy/EnemyPathfinding.cs => UnitPathfinding.cs} (71%) create mode 100644 Assets/Scripts/Units/UnitPathfinding.cs.meta diff --git a/Assets/Enemies/Common/Graphs/BasicEnemyFSM.asset b/Assets/Enemies/Common/Graphs/BasicEnemyFSM.asset index 3f83e8e..a7f8620 100644 --- a/Assets/Enemies/Common/Graphs/BasicEnemyFSM.asset +++ b/Assets/Enemies/Common/Graphs/BasicEnemyFSM.asset @@ -12,13 +12,28 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f945e777233a59f4aba40aeca29093a6, type: 3} m_Name: BasicEnemyFSM m_EditorClassIdentifier: NodeCanvas::NodeCanvas.StateMachines.FSM - _serializedGraph: '{"type":"NodeCanvas.StateMachines.FSM","nodes":[{"_onEnterList":{"executionMode":1,"actions":[]},"_onUpdateList":{"executionMode":1,"actions":[]},"_onExitList":{"executionMode":1,"actions":[]},"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_name":"Standby","_position":{"x":570.0,"y":447.0},"$type":"NodeCanvas.StateMachines.SuperActionState"}],"connections":[],"canvasGroups":[],"localBlackboard":{"_variables":{}}}' - _objectReferences: [] + _serializedGraph: '{"type":"NodeCanvas.StateMachines.FSM","nodes":[{"_actionList":{"executionMode":1,"actions":[]},"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_position":{"x":522.1997,"y":608.5296},"$type":"NodeCanvas.StateMachines.ActionState","$id":"0"},{"_onEnterList":{"executionMode":1,"actions":[{"minValue":{"_value":2.0},"maxValue":{"_value":8.0},"floatVariable":{"_name":"_wanderTimer"},"$type":"NodeCanvas.Tasks.Actions.SetFloatRandom"}]},"_onUpdateList":{"executionMode":1,"actions":[]},"_onExitList":{"executionMode":1,"actions":[]},"foldEnter":true,"foldUpdate":true,"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_name":"Wander + Stand-by","_position":{"x":83.0,"y":289.0},"$type":"NodeCanvas.StateMachines.SuperActionState","$id":"1"},{"_onEnterList":{"executionMode":1,"actions":[{"moveSpeed":{"label":"Move + Speed","changeValue":{"_value":1},"value":{},"_changeSmoothing":{},"_smoothing":{},"_changeEasing":{},"_easing":{}},"acceleration":{"label":"Acceleration","changeValue":{},"value":{},"_changeSmoothing":{},"_smoothing":{},"_changeEasing":{},"_easing":{}},"deacceleration":{"label":"Deacceleration","changeValue":{},"value":{},"_changeSmoothing":{},"_smoothing":{},"_changeEasing":{},"_easing":{}},"$type":"Reset.Units.ChangeMoveSpeedSettings"},{"log":{"_value":"Detected + Player"},"$type":"NodeCanvas.Tasks.Actions.DebugLogText"},{"newSpeed":{},"absolute":{},"relativity":{},"$type":"Reset.Units.SetNewSpeed"}]},"_onUpdateList":{"executionMode":1,"actions":[]},"_onExitList":{"executionMode":1,"actions":[]},"foldEnter":true,"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_name":"Detect","_position":{"x":486.012,"y":-14.01074},"$type":"NodeCanvas.StateMachines.SuperActionState","$id":"2"},{"_actionList":{"executionMode":1,"actions":[{"saveAs":{"_name":"_self"},"$type":"NodeCanvas.Tasks.Actions.GetSelf"},{"eventName":{"_value":"Start + Combat"},"eventValue":{"_name":"_self"},"delay":{},"$type":"NodeCanvas.Tasks.Actions.SendEvent`1[[UnityEngine.GameObject, + UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"}]},"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_name":"Signal + Spawnmates","_position":{"x":673.0,"y":-182.0},"$type":"NodeCanvas.StateMachines.ActionState","$id":"3"},{"_actionList":{"executionMode":1,"actions":[]},"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_name":"Enter + Combat","_position":{"x":1049.0,"y":32.0},"$type":"NodeCanvas.StateMachines.ActionState","$id":"4"},{"_nestedFSM":{"_value":1},"_position":{"x":1167.398,"y":424.1194},"$type":"NodeCanvas.StateMachines.NestedFSMState","$id":"5"},{"_name":"Check + for same spawner","_position":{"x":711.0,"y":193.0},"$type":"NodeCanvas.StateMachines.EmptyState","$id":"6"},{"_actionList":{"executionMode":1,"actions":[{"$type":"Reset.Units.SetWanderingPath"},{"minValue":{"_value":2.0},"maxValue":{"_value":7.0},"floatVariable":{"_name":"_newSpeed"},"$type":"NodeCanvas.Tasks.Actions.SetFloatRandom"},{"moveSpeed":{"label":"Move + Speed","changeValue":{"_value":1},"value":{"_name":"_newSpeed"},"_changeSmoothing":{},"_smoothing":{},"_changeEasing":{},"_easing":{}},"acceleration":{"label":"Acceleration","changeValue":{},"value":{},"_changeSmoothing":{},"_smoothing":{},"_changeEasing":{},"_easing":{}},"deacceleration":{"label":"Deacceleration","changeValue":{},"value":{},"_changeSmoothing":{},"_smoothing":{},"_changeEasing":{},"_easing":{}},"$type":"Reset.Units.ChangeMoveSpeedSettings"},{"newSpeed":{"_name":"_newSpeed"},"absolute":{},"relativity":{},"$type":"Reset.Units.SetNewSpeed"}]},"_color":{"r":1.0,"g":0.42,"b":0.32,"a":1.0},"_name":"Get + New Wandering Path","_position":{"x":-134.0,"y":112.0},"$type":"NodeCanvas.StateMachines.ActionState","$id":"7"}],"connections":[{"_sourceNode":{"$ref":"0"},"_targetNode":{"$ref":"1"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_condition":{"eventName":{"_value":"New + Target Set"},"$type":"NodeCanvas.Tasks.Conditions.CheckEvent"},"_sourceNode":{"$ref":"1"},"_targetNode":{"$ref":"2"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_condition":{"timeout":{"_name":"_wanderTimer"},"$type":"NodeCanvas.Tasks.Conditions.Timeout"},"_sourceNode":{"$ref":"1"},"_targetNode":{"$ref":"7"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_condition":{"timeout":{"_value":6.0},"$type":"NodeCanvas.Tasks.Conditions.Timeout"},"_sourceNode":{"$ref":"2"},"_targetNode":{"$ref":"3"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_condition":{"eventName":{"_value":"Start + Combat"},"saveEventValue":{"_name":"_calledBy"},"$type":"NodeCanvas.Tasks.Conditions.CheckEvent`1[[UnityEngine.GameObject, + UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]"},"_sourceNode":{"$ref":"2"},"_targetNode":{"$ref":"6"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_sourceNode":{"$ref":"3"},"_targetNode":{"$ref":"4"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_sourceNode":{"$ref":"4"},"_targetNode":{"$ref":"5"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_condition":{"target":{"_name":"_calledBy"},"$type":"Reset.Units.CheckIfSpawnmate"},"_sourceNode":{"$ref":"6"},"_targetNode":{"$ref":"4"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_sourceNode":{"$ref":"6"},"_targetNode":{"$ref":"2"},"$type":"NodeCanvas.StateMachines.FSMConnection"},{"_sourceNode":{"$ref":"7"},"_targetNode":{"$ref":"1"},"$type":"NodeCanvas.StateMachines.FSMConnection"}],"canvasGroups":[],"localBlackboard":{"_variables":{}}}' + _objectReferences: + - {fileID: 0} + - {fileID: 11400000, guid: 66d780be76d914c40afd1b3f00df719f, type: 2} _graphSource: _version: 3.31 _category: _comments: - _translation: {x: 135, y: 18} + _translation: {x: 112, y: 401} _zoomFactor: 1 _haltSerialization: 0 _externalSerializationFile: {fileID: 0} diff --git a/Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset b/Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset new file mode 100644 index 0000000..72f44fb --- /dev/null +++ b/Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset @@ -0,0 +1,24 @@ +%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: f945e777233a59f4aba40aeca29093a6, type: 3} + m_Name: TestEnemyCombatFSM + m_EditorClassIdentifier: NodeCanvas::NodeCanvas.StateMachines.FSM + _serializedGraph: '{"type":"NodeCanvas.StateMachines.FSM","nodes":[],"connections":[],"canvasGroups":[],"localBlackboard":{"_variables":{}}}' + _objectReferences: [] + _graphSource: + _version: 3.31 + _category: + _comments: + _translation: {x: 0, y: 0} + _zoomFactor: 1 + _haltSerialization: 0 + _externalSerializationFile: {fileID: 0} diff --git a/Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset.meta b/Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset.meta new file mode 100644 index 0000000..6f54272 --- /dev/null +++ b/Assets/Enemies/TestEnemy/Graphs/TestEnemyCombatFSM.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66d780be76d914c40afd1b3f00df719f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Enemies/TestEnemy/Models/TestMonster/TestMonsterModelAnimController.controller b/Assets/Enemies/TestEnemy/Models/TestMonster/TestMonsterModelAnimController.controller index 3dd3b90..2aa9f20 100644 --- a/Assets/Enemies/TestEnemy/Models/TestMonster/TestMonsterModelAnimController.controller +++ b/Assets/Enemies/TestEnemy/Models/TestMonster/TestMonsterModelAnimController.controller @@ -127,6 +127,9 @@ AnimatorStateMachine: - serializedVersion: 1 m_State: {fileID: -6278834590196608118} m_Position: {x: 230, y: 260, z: 0} + - serializedVersion: 1 + m_State: {fileID: 6332575986919065934} + m_Position: {x: -68.95941, y: 277.56348, z: 0} m_ChildStateMachines: [] m_AnyStateTransitions: - {fileID: 6050553813420038917} @@ -417,6 +420,28 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: +--- !u!1101 &-483324057439386864 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: [] + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 1413696981156420822} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.2500002 + m_TransitionOffset: 0 + m_ExitTime: 0.0007289399 + m_HasExitTime: 1 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 --- !u!91 &9100000 AnimatorController: m_ObjectHideFlags: 0 @@ -457,6 +482,18 @@ AnimatorController: m_IKPass: 0 m_SyncedLayerAffectsTiming: 0 m_Controller: {fileID: 9100000} + - serializedVersion: 5 + m_Name: New Layer + m_StateMachine: {fileID: 6830853216154444894} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 1 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 1 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} --- !u!1102 &216270272570043207 AnimatorState: serializedVersion: 6 @@ -484,6 +521,55 @@ AnimatorState: m_MirrorParameter: m_CycleOffsetParameter: m_TimeParameter: +--- !u!1102 &1413696981156420822 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: New State + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: 1595209839139272091} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 0} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1101 &1595209839139272091 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: [] + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: 8637122628281323528} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.75 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 --- !u!1101 &1884416669882918329 AnimatorStateTransition: m_ObjectHideFlags: 1 @@ -703,3 +789,81 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 +--- !u!1102 &6332575986919065934 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: New State + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 0} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &6830853216154444894 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: New Layer + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 8637122628281323528} + m_Position: {x: 500, y: 90, z: 0} + - serializedVersion: 1 + m_State: {fileID: 1413696981156420822} + m_Position: {x: 376.62445, y: 237.36044, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: 1413696981156420822} +--- !u!1102 &8637122628281323528 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Attack2Telegraph-60 + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: + - {fileID: -483324057439386864} + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: -2778899801529699949, guid: 64c95eab532c57d4eb98569c66e7455a, type: 3} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: diff --git a/Assets/Enemies/TestEnemy/Objects/TestMonster.prefab b/Assets/Enemies/TestEnemy/Objects/TestMonster.prefab index 5ee0275..2f140a6 100644 --- a/Assets/Enemies/TestEnemy/Objects/TestMonster.prefab +++ b/Assets/Enemies/TestEnemy/Objects/TestMonster.prefab @@ -16,9 +16,9 @@ GameObject: - component: {fileID: 3375213058463339329} - component: {fileID: 6881462958115636691} - component: {fileID: 5075083518210584453} - - component: {fileID: 1077794308846883818} - component: {fileID: 6620953456884791151} - component: {fileID: 6778397863327314458} + - component: {fileID: 4799508192264281601} m_Layer: 7 m_Name: TestMonster m_TagString: Untagged @@ -166,12 +166,12 @@ MonoBehaviour: ShowTopMostFoldoutHeaderGroup: 1 data: directionChangingSoftness: - targetValue: 1 - currentValue: 1 + targetValue: 5 + currentValue: 5 targetSmoothing: 1 targetEasing: 2 currentSmoothing: 1 - defaultValue: 1 + defaultValue: 5 defaultSmoothing: 1 defaultEasing: 2 directionSpinningHardness: @@ -411,21 +411,6 @@ MonoBehaviour: tagEntryCosts: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 graphMask: value: -1 ---- !u!114 &1077794308846883818 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 9098724353270996650} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1a67969fa2454c8f8b5c84c31c95d890, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::Reset.Units.EnemyPathfinding - ShowTopMostFoldoutHeaderGroup: 1 - nextWaypointDistance: 3 - reachedEndOfPath: 0 --- !u!143 &6620953456884791151 CharacterController: m_ObjectHideFlags: 0 @@ -473,6 +458,22 @@ MonoBehaviour: bezierTangentLength: 0.4 offset: 0.2 factor: 0.1 +--- !u!114 &4799508192264281601 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9098724353270996650} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a72dabd280fe71488a78596bd852afc, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Reset.Units.UnitPathfinding + ShowTopMostFoldoutHeaderGroup: 1 + seeker: {fileID: 0} + nextWaypointDistance: 3 + reachedEndOfPath: 0 --- !u!1001 &8807019661255186479 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Units/Enemy/EnemyCombat.cs b/Assets/Scripts/Units/Enemy/EnemyCombat.cs index 2a5e295..a450aaf 100644 --- a/Assets/Scripts/Units/Enemy/EnemyCombat.cs +++ b/Assets/Scripts/Units/Enemy/EnemyCombat.cs @@ -1,8 +1,15 @@ -using UnityEngine; +using Sirenix.OdinInspector; +using UnityEngine; namespace Reset.Units{ public class EnemyCombat : UnitCombat, IUnitTargetProvider{ public GameObject target; public GameObject UnitTarget => target; + + [Button] + public void SetNewTarget(GameObject newTarget){ + Unit.Graph.SendEvent("New Target Set"); + target = newTarget; + } } } diff --git a/Assets/Scripts/Units/Enemy/EnemySpawn.cs b/Assets/Scripts/Units/Enemy/EnemySpawn.cs index 9368661..3c48ea2 100644 --- a/Assets/Scripts/Units/Enemy/EnemySpawn.cs +++ b/Assets/Scripts/Units/Enemy/EnemySpawn.cs @@ -32,7 +32,7 @@ namespace Reset.Units{ relatedGraph.collision.diameter = 3f; AstarPath.active.Scan(relatedGraph); - + GetComponent().graph = relatedGraph; } @@ -59,6 +59,39 @@ namespace Reset.Units{ // Update is called once per frame void Update(){ Draw.WireCylinder(transform.position, transform.position + Vector3.up * 7f, radius); + + if (PlayerIsInRange()) { + SetPlayerAsTarget(); + } + } + + GameObject PlayerIsInRange(){ + // TODO: Make compatible with all players + Vector3 playerPos = PlayerManager.Player.transform.position; + + // Skip checking and return null/false if the player is nowhere near the spawn + if (Vector3.Distance(playerPos, transform.position) < radius * 1.5f) { + return null; + } + + // If they are in range, check if the player is close enough to either an enemy or the spawn center + if (Vector3.Distance(playerPos, transform.position) < radius * .33f) { + return PlayerManager.Player; + } + + foreach (GameObject thisEnemy in enemies) { + if (Vector3.Distance(playerPos, thisEnemy.transform.position) < radius / 2f) { + return PlayerManager.Player; + } + } + + return null; + } + + void SetPlayerAsTarget(){ + foreach (GameObject thisEnemy in enemies) { + thisEnemy.GetComponent().SetNewTarget(PlayerManager.Player); + } } } diff --git a/Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs b/Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs new file mode 100644 index 0000000..584c96a --- /dev/null +++ b/Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs @@ -0,0 +1,35 @@ +using NodeCanvas.Framework; +using ParadoxNotion.Design; +using UnityEngine; + +namespace Reset.Units { + [Category("Reset/Units")] + [Description("Returns true if this unit is in the same spawn group as the provided value.")] + public class CheckIfSpawnmate : ConditionTask{ + protected override string info{ get => $"{target} is spawnmate"; } + + public BBParameter target; + + //Use for initialization. This is called only once in the lifetime of the task. + //Return null if init was successfull. Return an error string otherwise + protected override string OnInit(){ + return null; + } + + //Called whenever the condition gets enabled. + protected override void OnEnable() { + + } + + //Called whenever the condition gets disabled. + protected override void OnDisable() { + + } + + //Called once per frame while the condition is active. + //Return whether the condition is success or failure. + protected override bool OnCheck(){ + return agent.relatedSpawner.enemies.Contains(target.value); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs.meta b/Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs.meta new file mode 100644 index 0000000..687c9e8 --- /dev/null +++ b/Assets/Scripts/Units/Graph Tasks/CheckIfSpawnmate.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 847ff34f59879c844b597a39884f5fe8 \ No newline at end of file diff --git a/Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs b/Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs new file mode 100644 index 0000000..6997e36 --- /dev/null +++ b/Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs @@ -0,0 +1,64 @@ +using NodeCanvas.Framework; +using ParadoxNotion.Design; +using Pathfinding; +using UnityEngine; + + +namespace Reset.Units { + + [Category("Reset/Pathfinding")] + [Description("Set the agent's current path to a wandering path.")] + public class SetWanderingPath : ActionTask { + + //Use for initialization. This is called only once in the lifetime of the task. + //Return null if init was successfull. Return an error string otherwise + protected override string OnInit() { + return null; + } + + //This is called once each time the task is enabled. + //Call EndAction() to mark the action as finished, either in success or failure. + //EndAction can be called from anywhere. + protected override void OnExecute(){ + Enemy thisEnemy = agent.Unit as Enemy; + Vector3 pathTargetPos = agent.transform.position; + + if (thisEnemy.relatedSpawner) { + pathTargetPos = thisEnemy.relatedSpawner.transform.position; + } + + Vector3 randomizedDestination = new Vector3( + Random.Range(-thisEnemy.relatedSpawner.radius, thisEnemy.relatedSpawner.radius), + 0f, + Random.Range(-thisEnemy.relatedSpawner.radius, thisEnemy.relatedSpawner.radius) + ); + + pathTargetPos += randomizedDestination; + + agent.seeker.StartPath(agent.transform.position, pathTargetPos, OnPathComplete); + + EndAction(true); + } + + public void OnPathComplete(Path p){ + if (!p.error) { + agent.AssignNewPath(p); + } + } + + //Called once per frame while the action is active. + protected override void OnUpdate() { + + } + + //Called when the task is disabled. + protected override void OnStop() { + + } + + //Called when the task is paused. + protected override void OnPause() { + + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs.meta b/Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs.meta new file mode 100644 index 0000000..bd94dd2 --- /dev/null +++ b/Assets/Scripts/Units/Graph Tasks/SetWanderingPath.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a8b7661016b47ae4e9137833e7111460 \ No newline at end of file diff --git a/Assets/Scripts/Units/Unit.cs b/Assets/Scripts/Units/Unit.cs index f6e45a3..471cf72 100644 --- a/Assets/Scripts/Units/Unit.cs +++ b/Assets/Scripts/Units/Unit.cs @@ -24,6 +24,14 @@ namespace Reset.Units{ get{ if (!_graph) { _graph = GetComponent(); } return _graph; } } + private UnitCombat _combat; + internal UnitCombat Combat{ + get { + if (_combat == null) { _combat = GetComponent(); } + return _combat; + } + } + // Debug and Gizmos public NetworkVariable graphStateAsString; diff --git a/Assets/Scripts/Units/Enemy/EnemyPathfinding.cs b/Assets/Scripts/Units/UnitPathfinding.cs similarity index 71% rename from Assets/Scripts/Units/Enemy/EnemyPathfinding.cs rename to Assets/Scripts/Units/UnitPathfinding.cs index 9e10e0e..50d8dc6 100644 --- a/Assets/Scripts/Units/Enemy/EnemyPathfinding.cs +++ b/Assets/Scripts/Units/UnitPathfinding.cs @@ -9,18 +9,16 @@ using Vector3 = UnityEngine.Vector3; namespace Reset.Units{ [RequireComponent(typeof(Seeker))] - public class EnemyPathfinding : UnitComponent, IUnitDirectionProvider{ + public class UnitPathfinding : UnitComponent, IUnitDirectionProvider{ public Vector2 Direction{ get; set; } - - private Seeker seeker; + + public Seeker seeker; public float nextWaypointDistance = 3; private int currentWaypoint; public Path path; public bool reachedEndOfPath; - - private Coroutine wanderPathCoroutine; public void Start(){ seeker = GetComponent(); @@ -32,37 +30,9 @@ namespace Reset.Units{ } else { Debug.LogWarning("Creating a graph for a singular enemy is not yet implemented. Graph mask not set on this unit.", transform); } - - StartCoroutine(WaitForWanderPath()); } - IEnumerator WaitForWanderPath(){ - yield return new WaitForSeconds(Random.Range(1f, 7f)); - StartWanderPath(); - - wanderPathCoroutine = null; - } - - void StartWanderPath(){ - Enemy thisEnemy = (Unit as Enemy); - Vector3 pathTargetPos = transform.position; - - if (thisEnemy.relatedSpawner) { - pathTargetPos = thisEnemy.relatedSpawner.transform.position; - } - - Vector3 randomizedDestination = new Vector3( - Random.Range(-thisEnemy.relatedSpawner.radius, thisEnemy.relatedSpawner.radius), - 0f, - Random.Range(-thisEnemy.relatedSpawner.radius, thisEnemy.relatedSpawner.radius) - ); - - pathTargetPos += randomizedDestination; - - seeker.StartPath(transform.position, pathTargetPos, OnPathComplete); - } - - public void OnPathComplete(Path p){ + public void AssignNewPath(Path p){ if (!p.error) { path = p; // Reset the waypoint counter so that we start to move towards the first point in the path @@ -71,6 +41,10 @@ namespace Reset.Units{ } public void Update(){ + FollowCurrentPath(); + } + + private void FollowCurrentPath(){ if (path == null) { // We have no path to follow yet, so don't do anything return; @@ -92,10 +66,6 @@ namespace Reset.Units{ // Set a status variable to indicate that the agent has reached the end of the path. // You can use this to trigger some special code if your game requires that. reachedEndOfPath = true; - - if (wanderPathCoroutine == null) { - wanderPathCoroutine = StartCoroutine(WaitForWanderPath()); - } break; } @@ -111,7 +81,7 @@ namespace Reset.Units{ } else { Direction = (path.vectorPath[currentWaypoint] - transform.position).normalized.ToVector2(); } - + // Draw an indicator for the path Draw.ingame.SolidCircle(path.vectorPath[currentWaypoint] + Vector3.up * .02f, Vector3.up, .3f); Draw.ingame.Arrow(transform.position, transform.position + Direction.ToVector3(), Vector3.up, .3f); diff --git a/Assets/Scripts/Units/UnitPathfinding.cs.meta b/Assets/Scripts/Units/UnitPathfinding.cs.meta new file mode 100644 index 0000000..2d5b33b --- /dev/null +++ b/Assets/Scripts/Units/UnitPathfinding.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1a72dabd280fe71488a78596bd852afc \ No newline at end of file