mirror of
https://github.com/Bragin-Stepan/project-entity.git
synced 2026-04-19 13:09:41 +00:00
Compare commits
3 Commits
d3dce07cf5
...
1356b8bfb2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1356b8bfb2 | ||
|
|
51fd4cdc8d | ||
|
|
ffeb1655c8 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -28,6 +28,7 @@
|
|||||||
# Visual Studio cache directory
|
# Visual Studio cache directory
|
||||||
.vs/
|
.vs/
|
||||||
.agent/
|
.agent/
|
||||||
|
.agents/
|
||||||
|
|
||||||
# Gradle cache directory
|
# Gradle cache directory
|
||||||
.gradle/
|
.gradle/
|
||||||
@@ -65,6 +66,9 @@ sysinfo.txt
|
|||||||
*.unitypackage.meta
|
*.unitypackage.meta
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
# AI
|
||||||
|
Antigravity.Ide.Editor.csproj
|
||||||
|
|
||||||
# Crashlytics generated file
|
# Crashlytics generated file
|
||||||
crashlytics-build.properties
|
crashlytics-build.properties
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,12 @@ namespace _Project.Develop.Runtime.Entities
|
|||||||
private readonly EntitiesLifeContext _entitiesLifeContext;
|
private readonly EntitiesLifeContext _entitiesLifeContext;
|
||||||
private readonly MonoEntitiesFactory _monoEntitiesFactory;
|
private readonly MonoEntitiesFactory _monoEntitiesFactory;
|
||||||
private readonly CollidersRegistryService _collidersRegistryService;
|
private readonly CollidersRegistryService _collidersRegistryService;
|
||||||
private readonly IPlayerInput _playerInput;
|
|
||||||
|
|
||||||
public EntitiesFactory(DIContainer container)
|
public EntitiesFactory(DIContainer container)
|
||||||
{
|
{
|
||||||
_collidersRegistryService = container.Resolve<CollidersRegistryService>();
|
_collidersRegistryService = container.Resolve<CollidersRegistryService>();
|
||||||
_entitiesLifeContext = container.Resolve<EntitiesLifeContext>();
|
_entitiesLifeContext = container.Resolve<EntitiesLifeContext>();
|
||||||
_monoEntitiesFactory = container.Resolve<MonoEntitiesFactory>();
|
_monoEntitiesFactory = container.Resolve<MonoEntitiesFactory>();
|
||||||
_playerInput = container.Resolve<IPlayerInput>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity CreateHero(Vector3 position)
|
public Entity CreateHero(Vector3 position)
|
||||||
@@ -58,7 +56,7 @@ namespace _Project.Develop.Runtime.Entities
|
|||||||
.AddStartAttackRequest()
|
.AddStartAttackRequest()
|
||||||
.AddStartAttackEvent()
|
.AddStartAttackEvent()
|
||||||
.AddEndAttackEvent()
|
.AddEndAttackEvent()
|
||||||
.AddAttackDelayTime(new ReactiveVariable<float>(1))
|
.AddAttackDelayTime(new ReactiveVariable<float>(0.1f))
|
||||||
.AddAttackDelayEndEvent()
|
.AddAttackDelayEndEvent()
|
||||||
.AddInstantAttackDamage(new ReactiveVariable<float>(50))
|
.AddInstantAttackDamage(new ReactiveVariable<float>(50))
|
||||||
.AddAttackCanceledEvent()
|
.AddAttackCanceledEvent()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using _Project.Develop.Runtime.Entities;
|
using _Project.Develop.Runtime.Entities;
|
||||||
using _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States;
|
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.Utilities.Conditions;
|
||||||
using _Project.Develop.Runtime.Utils.InputManagement;
|
using _Project.Develop.Runtime.Utils.InputManagement;
|
||||||
using _Project.Develop.Runtime.Utils.ReactiveManagement;
|
using _Project.Develop.Runtime.Utils.ReactiveManagement;
|
||||||
@@ -56,6 +55,7 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
|||||||
AIParallelState parallelState = new (findTargetState, teleportStateMachine);
|
AIParallelState parallelState = new (findTargetState, teleportStateMachine);
|
||||||
|
|
||||||
AIStateMachine rootStateMachine = new ();
|
AIStateMachine rootStateMachine = new ();
|
||||||
|
|
||||||
rootStateMachine.AddState(parallelState);
|
rootStateMachine.AddState(parallelState);
|
||||||
|
|
||||||
StateMachineBrain brain = new (rootStateMachine);
|
StateMachineBrain brain = new (rootStateMachine);
|
||||||
@@ -65,13 +65,13 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
|||||||
return brain;
|
return brain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StateMachineBrain CreateMainHeroBrain(Entity entity, ITargetSelector targetSelector)
|
public StateMachineBrain CreateArcheroHeroBrain(Entity entity, ITargetSelector targetSelector)
|
||||||
{
|
{
|
||||||
AIStateMachine combatState = CreateAutoAttackStateMachine(entity);
|
AIStateMachine combatState = CreateAutoAttackStateMachine(entity);
|
||||||
PlayerInputMovementState movementState = new (entity, _playerInput);
|
PlayerInputMovementState movementState = new (entity, _playerInput);
|
||||||
|
|
||||||
ReactiveVariable<Entity> currentTarget = entity.CurrentTarget;
|
ReactiveVariable<Entity> currentTarget = entity.CurrentTarget;
|
||||||
|
|
||||||
ICompositeCondition fromMovementToCombatStateCondition = new CompositeCondition()
|
ICompositeCondition fromMovementToCombatStateCondition = new CompositeCondition()
|
||||||
.Add(new FuncCondition(() => currentTarget.Value != null))
|
.Add(new FuncCondition(() => currentTarget.Value != null))
|
||||||
.Add(new FuncCondition(() => _playerInput.Move.Value == Vector2.zero));
|
.Add(new FuncCondition(() => _playerInput.Move.Value == Vector2.zero));
|
||||||
@@ -79,6 +79,39 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
|||||||
ICompositeCondition fromCombatToMovementStateCondition = new CompositeCondition(LogicOperationsUtils.Or)
|
ICompositeCondition fromCombatToMovementStateCondition = new CompositeCondition(LogicOperationsUtils.Or)
|
||||||
.Add(new FuncCondition(() => currentTarget.Value == null))
|
.Add(new FuncCondition(() => currentTarget.Value == null))
|
||||||
.Add(new FuncCondition(() => _playerInput.Move.Value != Vector2.zero));
|
.Add(new FuncCondition(() => _playerInput.Move.Value != Vector2.zero));
|
||||||
|
|
||||||
|
AIStateMachine behaviour = new ();
|
||||||
|
|
||||||
|
behaviour.AddState(combatState);
|
||||||
|
behaviour.AddState(movementState);
|
||||||
|
|
||||||
|
behaviour.AddTransition(combatState, movementState, fromCombatToMovementStateCondition);
|
||||||
|
behaviour.AddTransition(movementState, combatState, fromMovementToCombatStateCondition);
|
||||||
|
|
||||||
|
FindTargetState findTargetState = new (_entitiesLifeContext, entity, targetSelector);
|
||||||
|
AIParallelState parallelState = new (findTargetState, behaviour);
|
||||||
|
|
||||||
|
AIStateMachine rootStateMachine = new ();
|
||||||
|
|
||||||
|
rootStateMachine.AddState(parallelState);
|
||||||
|
|
||||||
|
StateMachineBrain brain = new (rootStateMachine);
|
||||||
|
|
||||||
|
_aiBrainsContext.SetFor(entity, brain);
|
||||||
|
|
||||||
|
return brain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateMachineBrain CreateMainHeroBrain(Entity entity)
|
||||||
|
{
|
||||||
|
AIStateMachine combatState = CreateSteeringAttackStateMachine(entity);
|
||||||
|
PlayerInputMovementState movementState = new (entity, _playerInput);
|
||||||
|
|
||||||
|
ICompositeCondition fromMovementToCombatStateCondition = new CompositeCondition()
|
||||||
|
.Add(new FuncCondition(() => _playerInput.Move.Value == Vector2.zero));
|
||||||
|
|
||||||
|
ICompositeCondition fromCombatToMovementStateCondition = new CompositeCondition()
|
||||||
|
.Add(new FuncCondition(() => _playerInput.Move.Value != Vector2.zero));
|
||||||
|
|
||||||
AIStateMachine behaviour = new ();
|
AIStateMachine behaviour = new ();
|
||||||
|
|
||||||
@@ -88,15 +121,8 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
|||||||
behaviour.AddTransition(combatState, movementState, fromCombatToMovementStateCondition);
|
behaviour.AddTransition(combatState, movementState, fromCombatToMovementStateCondition);
|
||||||
behaviour.AddTransition(movementState, combatState, fromMovementToCombatStateCondition);
|
behaviour.AddTransition(movementState, combatState, fromMovementToCombatStateCondition);
|
||||||
|
|
||||||
FindTargetState findTargetState = new (_entitiesLifeContext, entity, targetSelector);
|
StateMachineBrain brain = new (behaviour);
|
||||||
AIParallelState parallelState = new (findTargetState, behaviour);
|
|
||||||
|
|
||||||
AIStateMachine rootStateMachine = new ();
|
|
||||||
|
|
||||||
rootStateMachine.AddState(parallelState);
|
|
||||||
|
|
||||||
StateMachineBrain brain = new (rootStateMachine);
|
|
||||||
|
|
||||||
_aiBrainsContext.SetFor(entity, brain);
|
_aiBrainsContext.SetFor(entity, brain);
|
||||||
|
|
||||||
return brain;
|
return brain;
|
||||||
@@ -130,6 +156,43 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
|||||||
|
|
||||||
return stateMachine;
|
return stateMachine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// На сколько хорошая идея дробить на маленькие стейтмашины?
|
||||||
|
private AIStateMachine CreateSteeringAttackStateMachine(Entity entity)
|
||||||
|
{
|
||||||
|
AIStateMachine steeringState = CreateSteeringInputStateMachine(entity); // просто это уже 3 по вложенности
|
||||||
|
PlayerInputAttackTriggerState attackTriggerState = new (entity, _playerInput);
|
||||||
|
|
||||||
|
AIParallelState parallelState = new (steeringState, attackTriggerState);
|
||||||
|
|
||||||
|
AIStateMachine stateMachine = new ();
|
||||||
|
|
||||||
|
stateMachine.AddState(parallelState);
|
||||||
|
|
||||||
|
return stateMachine;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AIStateMachine CreateSteeringInputStateMachine(Entity entity)
|
||||||
|
{
|
||||||
|
EmptyState emptyState = new ();
|
||||||
|
PlayerInputRotationState rotationState = new (entity, _playerInput);
|
||||||
|
|
||||||
|
ICondition fromIdleToRotateStateCondition = new CompositeCondition()
|
||||||
|
.Add(new FuncCondition(() => _playerInput.Look.Value != Vector2.zero));
|
||||||
|
|
||||||
|
ICondition fromRotateToIdleStateCondition = new CompositeCondition()
|
||||||
|
.Add(new FuncCondition(() => _playerInput.Look.Value == Vector2.zero));
|
||||||
|
|
||||||
|
AIStateMachine stateMachine = new ();
|
||||||
|
|
||||||
|
stateMachine.AddState(emptyState);
|
||||||
|
stateMachine.AddState(rotationState);
|
||||||
|
|
||||||
|
stateMachine.AddTransition(rotationState, emptyState, fromRotateToIdleStateCondition);
|
||||||
|
stateMachine.AddTransition(emptyState, rotationState, fromIdleToRotateStateCondition);
|
||||||
|
|
||||||
|
return stateMachine;
|
||||||
|
}
|
||||||
|
|
||||||
private AIStateMachine CreateAutoAttackStateMachine(Entity entity)
|
private AIStateMachine CreateAutoAttackStateMachine(Entity entity)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using _Project.Develop.Runtime.Entities;
|
||||||
|
using _Project.Develop.Runtime.Utils.InputManagement;
|
||||||
|
using _Project.Develop.Runtime.Utils.ReactiveManagement.Event;
|
||||||
|
using Assets._Project.Develop.Runtime.Utilities.StateMachineCore;
|
||||||
|
|
||||||
|
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States
|
||||||
|
{
|
||||||
|
public class PlayerInputAttackTriggerState : State, IUpdatableState
|
||||||
|
{
|
||||||
|
private readonly IPlayerInput _playerInput;
|
||||||
|
private ReactiveEvent _request;
|
||||||
|
|
||||||
|
public PlayerInputAttackTriggerState(Entity entity, IPlayerInput playerInput)
|
||||||
|
{
|
||||||
|
_playerInput = playerInput;
|
||||||
|
_request = entity.StartAttackRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Enter()
|
||||||
|
{
|
||||||
|
base.Enter();
|
||||||
|
_playerInput.Attack.Enter += OnAttack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float deltaTime)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public override void Exit()
|
||||||
|
{
|
||||||
|
base.Exit();
|
||||||
|
_playerInput.Attack.Enter -= OnAttack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAttack(float value)
|
||||||
|
{
|
||||||
|
_request.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6e82caaf47984b6982642cf87f3bf1fc
|
||||||
|
timeCreated: 1772810576
|
||||||
@@ -10,21 +10,18 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States
|
|||||||
{
|
{
|
||||||
private readonly IPlayerInput _playerInput;
|
private readonly IPlayerInput _playerInput;
|
||||||
|
|
||||||
private ReactiveVariable<Vector3> _rotateDirection;
|
|
||||||
private ReactiveVariable<Vector3> _moveDirection;
|
private ReactiveVariable<Vector3> _moveDirection;
|
||||||
|
|
||||||
public PlayerInputMovementState(Entity entity, IPlayerInput playerInput)
|
public PlayerInputMovementState(Entity entity, IPlayerInput playerInput)
|
||||||
{
|
{
|
||||||
_playerInput = playerInput;
|
_playerInput = playerInput;
|
||||||
|
|
||||||
_rotateDirection = entity.RotateDirection;
|
|
||||||
_moveDirection = entity.MoveDirection;
|
_moveDirection = entity.MoveDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
_moveDirection.Value = new Vector3(_playerInput.Move.Value.x, 0, _playerInput.Move.Value.y);
|
_moveDirection.Value = new Vector3(_playerInput.Move.Value.x, 0, _playerInput.Move.Value.y);
|
||||||
_rotateDirection.Value = new Vector3(_playerInput.Move.Value.x, 0, _playerInput.Move.Value.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Exit()
|
public override void Exit()
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using _Project.Develop.Runtime.Entities;
|
||||||
|
using _Project.Develop.Runtime.Utils.InputManagement;
|
||||||
|
using _Project.Develop.Runtime.Utils.ReactiveManagement;
|
||||||
|
using Assets._Project.Develop.Runtime.Utilities.StateMachineCore;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States
|
||||||
|
{
|
||||||
|
public class PlayerInputRotationState : State, IUpdatableState
|
||||||
|
{
|
||||||
|
private readonly IPlayerInput _playerInput;
|
||||||
|
private readonly Transform _transform;
|
||||||
|
|
||||||
|
private ReactiveVariable<Vector3> _rotateDirection;
|
||||||
|
|
||||||
|
private const float Sensitivity = 0.5f;
|
||||||
|
private const float DeadZone = 0.1f;
|
||||||
|
|
||||||
|
public PlayerInputRotationState(Entity entity, IPlayerInput playerInput)
|
||||||
|
{
|
||||||
|
_playerInput = playerInput;
|
||||||
|
_transform = entity.Transform;
|
||||||
|
|
||||||
|
_rotateDirection = entity.RotateDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
float lookX = _playerInput.Look.Value.x;
|
||||||
|
|
||||||
|
if (Mathf.Abs(lookX) > DeadZone)
|
||||||
|
{
|
||||||
|
Vector3 currentDirection = _rotateDirection.Value;
|
||||||
|
|
||||||
|
if (currentDirection == Vector3.zero)
|
||||||
|
currentDirection = _transform.forward;
|
||||||
|
|
||||||
|
currentDirection.y = 0;
|
||||||
|
|
||||||
|
if (currentDirection.sqrMagnitude < DeadZone)
|
||||||
|
currentDirection = Vector3.forward;
|
||||||
|
|
||||||
|
currentDirection.Normalize();
|
||||||
|
|
||||||
|
float angle = lookX * Sensitivity;
|
||||||
|
Quaternion rotation = Quaternion.Euler(0, angle, 0);
|
||||||
|
|
||||||
|
_rotateDirection.Value = rotation * currentDirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f85bcb531011e7049b6d03f311ff377f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -46,7 +46,8 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Teleport.Systems
|
|||||||
|
|
||||||
private void OnEndTeleport()
|
private void OnEndTeleport()
|
||||||
{
|
{
|
||||||
if (_radius <= 0 || _damage <= 0) return;
|
if (_radius <= 0 || _damage <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
int count = Physics.OverlapSphereNonAlloc(
|
int count = Physics.OverlapSphereNonAlloc(
|
||||||
_toPoint.position,
|
_toPoint.position,
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Teleport.Systems
|
|||||||
private Vector3 GetRandomPointInRadius(Vector3 center, float radius)
|
private Vector3 GetRandomPointInRadius(Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
Vector2 randomPoint = Random.insideUnitCircle * radius;
|
Vector2 randomPoint = Random.insideUnitCircle * radius;
|
||||||
|
|
||||||
return center + new Vector3(randomPoint.x, 0f, randomPoint.y);
|
return center + new Vector3(randomPoint.x, 0f, randomPoint.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,7 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features
|
|||||||
_brainsFactory = _container.Resolve<BrainsFactory>();
|
_brainsFactory = _container.Resolve<BrainsFactory>();
|
||||||
|
|
||||||
_hero = _entitiesFactory.CreateHero(Vector3.zero);
|
_hero = _entitiesFactory.CreateHero(Vector3.zero);
|
||||||
_brainsFactory.CreateMainHeroBrain(_hero, new NearestDamageableTargetSelector(_hero));
|
_brainsFactory.CreateMainHeroBrain(_hero);
|
||||||
|
|
||||||
// _enemy = _entitiesFactory.CreateTeleportWizard(Vector3.zero + Vector3.forward * 5);
|
|
||||||
// _brainsFactory.CreateWizardBrain(_enemy);
|
|
||||||
|
|
||||||
_enemy = _entitiesFactory.CreateTeleportWizard(Vector3.zero + Vector3.forward * 5);
|
_enemy = _entitiesFactory.CreateTeleportWizard(Vector3.zero + Vector3.forward * 5);
|
||||||
_brainsFactory.CreateDangerWizardBrain(_enemy, new LowestHealthTargetSelector(_enemy));
|
_brainsFactory.CreateDangerWizardBrain(_enemy, new LowestHealthTargetSelector(_enemy));
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace _Project.Develop.Runtime.Utils.InputManagement
|
|||||||
|
|
||||||
ICompositeCondition playerToUiStateCondition = new CompositeCondition(LogicOperationsUtils.Or)
|
ICompositeCondition playerToUiStateCondition = new CompositeCondition(LogicOperationsUtils.Or)
|
||||||
.Add(new FuncCondition(() => _uiInput.IsEnabled));
|
.Add(new FuncCondition(() => _uiInput.IsEnabled));
|
||||||
// .Add(new FuncCondition(() => _playerHorseInput.IsEnabled));
|
// .Add(new FuncCondition(() => _playerHorseInput.IsEnabled)); просто как пример что включен только 1 вариант
|
||||||
|
|
||||||
ICompositeCondition uiToPlayerStateCondition = new CompositeCondition(LogicOperationsUtils.Or)
|
ICompositeCondition uiToPlayerStateCondition = new CompositeCondition(LogicOperationsUtils.Or)
|
||||||
.Add(new FuncCondition(() => _playerInput.IsEnabled));
|
.Add(new FuncCondition(() => _playerInput.IsEnabled));
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
|||||||
|
|
||||||
if (_currentState == null)
|
if (_currentState == null)
|
||||||
SwitchState(_states[0]);
|
SwitchState(_states[0]);
|
||||||
|
else
|
||||||
|
_currentState.State.Enter();
|
||||||
|
|
||||||
_isRunning = true;
|
_isRunning = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user