diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Entities/EntitiesFactory.cs b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Entities/EntitiesFactory.cs index a289a9e..1edc7a8 100644 --- a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Entities/EntitiesFactory.cs +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Entities/EntitiesFactory.cs @@ -64,7 +64,8 @@ namespace _Project.Develop.Runtime.Entities .AddAttackCanceledEvent() .AddAttackCooldownInitialTime() .AddAttackCooldownCurrentTime() - .AddInAttackCooldown(); + .AddInAttackCooldown() + .AddCurrentTarget(); ICompositeCondition canMove = new CompositeCondition() .Add(new FuncCondition(() => entity.IsDead.Value == false)); @@ -218,6 +219,7 @@ namespace _Project.Develop.Runtime.Entities .AddFindTeleportPointEvent() .AddFindTeleportPointRequest() .AddEndTeleportEvent() + .AddCurrentTarget() .AddTeleportDamage(new ReactiveVariable(50)) .AddTeleportDamageRadius(new ReactiveVariable(6)) @@ -227,8 +229,8 @@ namespace _Project.Develop.Runtime.Entities .AddTeleportSearchRadius(new ReactiveVariable(6)) .AddTeleportCooldownInitialTime(new ReactiveVariable(3)) - .AddTeleportCooldownCurrentTime() - .AddInTeleportCooldown() + .AddTeleportCooldownCurrentTime(new ReactiveVariable(3)) + .AddInTeleportCooldown(new ReactiveVariable(true)) .AddCurrentEnergy(new ReactiveVariable(60)) .AddMaxEnergy(new ReactiveVariable(60)) @@ -258,7 +260,9 @@ namespace _Project.Develop.Runtime.Entities ICompositeCondition canStartTeleport = new CompositeCondition() .Add(new FuncCondition(() => entity.IsDead.Value == false)) .Add(new FuncCondition(() => entity.InTeleportCooldown.Value == false)) - .Add(new FuncCondition(() => entity.CurrentEnergy.Value >= entity.TeleportEnergyCost.Value)); + .Add(new FuncCondition(() => entity.CurrentEnergy.Value >= entity.TeleportEnergyCost.Value)) + .Add(new FuncCondition(() => entity.CurrentEnergy.Value >= entity.MaxEnergy.Value * 0.4f)) + .Add(new FuncCondition(() => entity.CurrentTarget.Value != null)); ICompositeCondition mustDie = new CompositeCondition() .Add(new FuncCondition(() => entity.CurrentHealth.Value <= 0)); @@ -279,8 +283,6 @@ namespace _Project.Develop.Runtime.Entities .AddMustSelfRelease(mustSelfRelease); entity - .AddSystem(new TeleportByInputSystem(_playerInput)) - // .AddSystem(new RegenEnergyByValueSystem()) .AddSystem(new RegenEnergyByPercentageSystem()) .AddSystem(new UseEnergySystem()) @@ -288,7 +290,8 @@ namespace _Project.Develop.Runtime.Entities .AddSystem(new TeleportStartByEnergySystem()) .AddSystem(new TeleportProcessSystem()) - .AddSystem(new FindRandomPointForTeleportSystem()) + // .AddSystem(new FindRandomPointForTeleportSystem()) + .AddSystem(new FindTargetPointForTeleportSystem()) .AddSystem(new EndTeleportSystem()) .AddSystem(new InstantTeleportSystem()) .AddSystem(new TeleportCooldownTimerSystem()) diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/BrainsFactory.cs b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/BrainsFactory.cs index 8cd1ec4..d154225 100644 --- a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/BrainsFactory.cs +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/BrainsFactory.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using _Project.Develop.Runtime.Entities; using _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States; +using _Project.Develop.Runtime.Logic.Gameplay.Features.Selectors; using _Project.Develop.Runtime.Utilities.Conditions; using _Project.Develop.Runtime.Utils.InputManagement; using _Project.Develop.Runtime.Utils.ReactiveManagement; @@ -46,9 +47,22 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI return brain; } - public StateMachineBrain CreateDangerWizardBrain(Entity entity) + // самый лучший нейминг + public StateMachineBrain CreateDangerWizardBrain(Entity entity, ITargetSelector targetSelector) { - return null; + AIStateMachine teleportStateMachine = CreateRandomTeleportStateMachine(entity); + + FindTargetState findTargetState = new (_entitiesLifeContext, entity, targetSelector); + AIParallelState parallelState = new (findTargetState, teleportStateMachine); + + AIStateMachine rootStateMachine = new (); + rootStateMachine.AddState(parallelState); + + StateMachineBrain brain = new (rootStateMachine); + + _aiBrainsContext.SetFor(entity, brain); + + return brain; } public StateMachineBrain CreateMainHeroBrain(Entity entity, ITargetSelector targetSelector) @@ -171,8 +185,8 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI AIStateMachine stateMachine = new (); - stateMachine.AddState(teleportTriggerState); stateMachine.AddState(emptyState); + stateMachine.AddState(teleportTriggerState); stateMachine.AddTransition(emptyState, teleportTriggerState, fromIdleToTeleportCondition); stateMachine.AddTransition(teleportTriggerState, emptyState, fromTeleportToIdleCondition); diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/States/NearestDamageableTargetSelector.cs.meta b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/States/NearestDamageableTargetSelector.cs.meta deleted file mode 100644 index 66a19df..0000000 --- a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/States/NearestDamageableTargetSelector.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 5efdb899e3ea4373b66f0610ea05b5c5 -timeCreated: 1772538727 \ No newline at end of file diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors.meta b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors.meta new file mode 100644 index 0000000..1c065c2 --- /dev/null +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9cad98614dbc342418111ffa383350b3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/LowestHealthTargetSelector.cs b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/LowestHealthTargetSelector.cs new file mode 100644 index 0000000..781a0a1 --- /dev/null +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/LowestHealthTargetSelector.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Linq; +using _Project.Develop.Runtime.Entities; +using _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States; +using _Project.Develop.Runtime.Logic.Gameplay.Features.Damage; +using _Project.Develop.Runtime.Utilities.Conditions; + +namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Selectors +{ + public class LowestHealthTargetSelector : ITargetSelector + { + private readonly Entity _source; + + public LowestHealthTargetSelector(Entity entity) + { + _source = entity; + } + + public Entity SelectTargetFrom(IEnumerable targets) + { + IEnumerable selectedTargets = FindSelectedTargets(targets); + + IEnumerable enumerable = selectedTargets.ToList(); + + if (enumerable.Any() == false) + return null; + + Entity lowestHealthTarget = enumerable.First(); + float minHealth = lowestHealthTarget.CurrentHealth.Value; + + foreach (Entity target in enumerable) + { + float health = target.CurrentHealth.Value; + + if (health < minHealth) + { + minHealth = health; + lowestHealthTarget = target; + } + } + + return lowestHealthTarget; + } + + private IEnumerable FindSelectedTargets(IEnumerable targets) + { + return targets.Where(target => + { + bool result = target.HasComponent(); + + if (target.TryGetCanApplyDamage(out ICompositeCondition value)) + result = result && value.Evaluate(); + + result = result && (target != _source); + + return result; + }); + } + } +} diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/LowestHealthTargetSelector.cs.meta b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/LowestHealthTargetSelector.cs.meta new file mode 100644 index 0000000..1ae8e45 --- /dev/null +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/LowestHealthTargetSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fb30a1545f3a234ea08e5b6bc188a6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/States/NearestDamageableTargetSelector.cs b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/NearestDamageableTargetSelector.cs similarity index 93% rename from Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/States/NearestDamageableTargetSelector.cs rename to Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/NearestDamageableTargetSelector.cs index b77c8ae..ddb335e 100644 --- a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/AI/States/NearestDamageableTargetSelector.cs +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/NearestDamageableTargetSelector.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using System.Linq; using _Project.Develop.Runtime.Entities; +using _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States; using _Project.Develop.Runtime.Logic.Gameplay.Features.Damage; using _Project.Develop.Runtime.Utilities.Conditions; using UnityEngine; -namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States +namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Selectors { public class NearestDamageableTargetSelector : ITargetSelector { diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/NearestDamageableTargetSelector.cs.meta b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/NearestDamageableTargetSelector.cs.meta new file mode 100644 index 0000000..5f7b576 --- /dev/null +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Selectors/NearestDamageableTargetSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b545627e47777f64d9ce0c2c27de4469 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Teleport/Systems/FindTargetPointForTeleportSystem.cs b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Teleport/Systems/FindTargetPointForTeleportSystem.cs new file mode 100644 index 0000000..19c1036 --- /dev/null +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Teleport/Systems/FindTargetPointForTeleportSystem.cs @@ -0,0 +1,62 @@ +using System; +using _Project.Develop.Runtime.Entities; +using _Project.Develop.Runtime.Utils.ReactiveManagement; +using _Project.Develop.Runtime.Utils.ReactiveManagement.Event; +using UnityEngine; + +namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Teleport.Systems +{ + public class FindTargetPointForTeleportSystem : IInitializableSystem, IDisposableSystem + { + private Transform _source; + private Transform _toPoint; + + private ReactiveEvent _findPointRequest; + private ReactiveEvent _findPointEvent; + + private ReactiveVariable _radius; + private ReactiveVariable _currentTarget; + + private IDisposable _findPointRequestDisposable; + + public void OnInit(Entity entity) + { + _source = entity.TeleportSource; + _toPoint = entity.TeleportToPoint; + _radius = entity.TeleportSearchRadius; + _currentTarget = entity.CurrentTarget; + _findPointRequest = entity.FindTeleportPointRequest; + _findPointEvent = entity.FindTeleportPointEvent; + + _findPointRequestDisposable = _findPointRequest.Subscribe(OnFindPointRequest); + } + + public void OnDispose() + { + _findPointRequestDisposable.Dispose(); + } + + private void OnFindPointRequest() + { + Entity target = _currentTarget.Value; + + if (target == null) + { + _toPoint.position = _source.position; + _findPointEvent.Invoke(); + return; + } + + Vector3 sourcePosition = _source.position; + Vector3 targetPosition = target.Transform.position; + Vector3 direction = targetPosition - sourcePosition; + + if (direction.magnitude <= _radius.Value) + _toPoint.position = targetPosition; + else + _toPoint.position = sourcePosition + direction.normalized * _radius.Value; + + _findPointEvent.Invoke(); + } + } +} diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Teleport/Systems/FindTargetPointForTeleportSystem.cs.meta b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Teleport/Systems/FindTargetPointForTeleportSystem.cs.meta new file mode 100644 index 0000000..e9946d4 --- /dev/null +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Features/Teleport/Systems/FindTargetPointForTeleportSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d40bb9d705ad5024dbda23882203437a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Infrastructure/TestGameplay.cs b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Infrastructure/TestGameplay.cs index 18a58ad..985a2d3 100644 --- a/Assets/_Project/Develop/Runtime/Logic/Gameplay/Infrastructure/TestGameplay.cs +++ b/Assets/_Project/Develop/Runtime/Logic/Gameplay/Infrastructure/TestGameplay.cs @@ -1,7 +1,7 @@ using System; using _Project.Develop.Runtime.Entities; using _Project.Develop.Runtime.Logic.Gameplay.Features.AI; -using _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States; +using _Project.Develop.Runtime.Logic.Gameplay.Features.Selectors; using _Project.Develop.Runtime.Utils.InputManagement; using Assets._Project.Develop.Runtime.Infrastructure.DI; using UnityEngine; @@ -26,17 +26,19 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features _container.Resolve().Enable(); _entitiesFactory = _container.Resolve(); _brainsFactory = _container.Resolve(); + + _hero = _entitiesFactory.CreateHero(Vector3.zero); + _brainsFactory.CreateMainHeroBrain(_hero, new NearestDamageableTargetSelector(_hero)); + + // _enemy = _entitiesFactory.CreateTeleportWizard(Vector3.zero + Vector3.forward * 5); + // _brainsFactory.CreateWizardBrain(_enemy); + + _enemy = _entitiesFactory.CreateTeleportWizard(Vector3.zero + Vector3.forward * 5); + _brainsFactory.CreateDangerWizardBrain(_enemy, new LowestHealthTargetSelector(_enemy)); } public void Run() { - _hero = _entitiesFactory.CreateHero(Vector3.zero); - _hero.AddCurrentTarget(); - _brainsFactory.CreateMainHeroBrain(_hero, new NearestDamageableTargetSelector(_hero)); - - _enemy = _entitiesFactory.CreateTeleportWizard(Vector3.zero + Vector3.forward * 5); - _brainsFactory.CreateWizardBrain(_enemy); - _isRunning = true; }