mirror of
https://github.com/Bragin-Stepan/project-entity.git
synced 2026-03-05 07:41:10 +00:00
feat: add state machine
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using _Project.Develop.Runtime.Entities;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
||||
{
|
||||
public class AIBrainsContext : IDisposable
|
||||
{
|
||||
private readonly List<EntityToBrain> _entityToBrains = new ();
|
||||
|
||||
public void SetFor(Entity entity, IBrain brain)
|
||||
{
|
||||
foreach (EntityToBrain item in _entityToBrains)
|
||||
{
|
||||
if (item.Entity == entity)
|
||||
{
|
||||
item.Brain.Disable();
|
||||
item.Brain.Dispose();
|
||||
item.Brain = brain;
|
||||
item.Brain.Enable();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_entityToBrains.Add(new EntityToBrain(brain, entity));
|
||||
brain.Enable();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < _entityToBrains.Count; i++)
|
||||
{
|
||||
if (_entityToBrains[i].Entity.IsInit == false)
|
||||
{
|
||||
int lastIndex = _entityToBrains.Count - 1;
|
||||
|
||||
_entityToBrains[i].Brain.Dispose();
|
||||
_entityToBrains[i] = _entityToBrains[lastIndex];
|
||||
_entityToBrains.RemoveAt(lastIndex);
|
||||
i--;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
_entityToBrains[i].Brain.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (EntityToBrain entityToBrain in _entityToBrains)
|
||||
entityToBrain.Brain.Dispose();
|
||||
|
||||
_entityToBrains.Clear();
|
||||
}
|
||||
|
||||
private class EntityToBrain
|
||||
{
|
||||
public Entity Entity;
|
||||
public IBrain Brain;
|
||||
|
||||
public EntityToBrain(IBrain brain, Entity entity)
|
||||
{
|
||||
Brain = brain;
|
||||
Entity = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 647b53823c00413081b7c9221d5bb5c1
|
||||
timeCreated: 1772458604
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Assets._Project.Develop.Runtime.Utilities.StateMachineCore;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
||||
{
|
||||
public class AIStateMachine : StateMachine<IUpdatableState>
|
||||
{
|
||||
public AIStateMachine(List<IDisposable> disposables) : base(disposables)
|
||||
{
|
||||
}
|
||||
|
||||
public AIStateMachine() : base (new List<IDisposable>())
|
||||
{
|
||||
}
|
||||
|
||||
protected override void UpdateLogic(float deltaTime)
|
||||
{
|
||||
base.UpdateLogic(deltaTime);
|
||||
|
||||
CurrentState?.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e225964fa5a4120a1e4bf1cc8d47641
|
||||
timeCreated: 1772455227
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using _Project.Develop.Runtime.Entities;
|
||||
using _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States;
|
||||
using _Project.Develop.Runtime.Utilities.Conditions;
|
||||
using Assets._Project.Develop.Runtime.Infrastructure.DI;
|
||||
using Assets._Project.Develop.Runtime.Utilities.Timer;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
||||
{
|
||||
public class BrainsFactory
|
||||
{
|
||||
private readonly DIContainer _container;
|
||||
|
||||
private readonly AIBrainsContext _aiBrainsContext;
|
||||
private readonly TimerServiceFactory _timerServiceFactory;
|
||||
|
||||
public BrainsFactory(DIContainer container)
|
||||
{
|
||||
_container = container;
|
||||
_aiBrainsContext = _container.Resolve<AIBrainsContext>();
|
||||
_timerServiceFactory = _container.Resolve<TimerServiceFactory>();
|
||||
}
|
||||
|
||||
public StateMachineBrain CreateGhostBrain(Entity entity)
|
||||
{
|
||||
AIStateMachine stateMachine = CreateRandomMovementStateMachine(entity);
|
||||
StateMachineBrain brain = new (stateMachine);
|
||||
|
||||
_aiBrainsContext.SetFor(entity, brain);
|
||||
|
||||
return brain;
|
||||
}
|
||||
|
||||
private AIStateMachine CreateRandomMovementStateMachine(Entity entity)
|
||||
{
|
||||
List<IDisposable> disposables = new ();
|
||||
|
||||
RandomMovementState randomMovementState = new (entity, 0.5f);
|
||||
EmptyState emptyState = new ();
|
||||
|
||||
TimerService movementTimer = _timerServiceFactory.Create(2f);
|
||||
disposables.Add(randomMovementState.Entered.Subscribe(movementTimer.Restart));
|
||||
disposables.Add(movementTimer);
|
||||
|
||||
TimerService idleTimer = _timerServiceFactory.Create(3f);
|
||||
disposables.Add(emptyState.Entered.Subscribe(idleTimer.Restart));
|
||||
disposables.Add(idleTimer);
|
||||
|
||||
FuncCondition movementTimerEndedCondition = new (() => movementTimer.IsOver);
|
||||
FuncCondition idleTimerEndedCondition = new (() => idleTimer.IsOver);
|
||||
|
||||
AIStateMachine stateMachine = new (disposables);
|
||||
|
||||
stateMachine.AddState(randomMovementState);
|
||||
stateMachine.AddState(emptyState);
|
||||
|
||||
stateMachine.AddTransition(randomMovementState, emptyState, movementTimerEndedCondition);
|
||||
stateMachine.AddTransition(emptyState, randomMovementState, idleTimerEndedCondition);
|
||||
|
||||
return stateMachine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b566da239ac47d5b8c828cc1ac54cbe
|
||||
timeCreated: 1772455908
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
||||
{
|
||||
public interface IBrain : IDisposable
|
||||
{
|
||||
void Enable();
|
||||
|
||||
void Disable();
|
||||
|
||||
void Update(float deltaTime);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77beb88ee43645a5b0f85bf7d1518e4a
|
||||
timeCreated: 1772458164
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI
|
||||
{
|
||||
public class StateMachineBrain : IBrain
|
||||
{
|
||||
private readonly AIStateMachine _stateMachine;
|
||||
|
||||
private bool _isEnabled;
|
||||
|
||||
public StateMachineBrain(AIStateMachine stateMachine)
|
||||
{
|
||||
_stateMachine = stateMachine;
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
_stateMachine.Enter();
|
||||
_isEnabled = true;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (_isEnabled == false)
|
||||
return;
|
||||
|
||||
_stateMachine.Update(deltaTime);
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
_stateMachine.Exit();
|
||||
_stateMachine.Dispose();
|
||||
_isEnabled = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_stateMachine.Dispose();
|
||||
_isEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45f2a68dedcb4a61a4ae6dc8a50227e4
|
||||
timeCreated: 1772458266
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0534b2062654595bef4d1e59081a533
|
||||
timeCreated: 1772454304
|
||||
@@ -0,0 +1,12 @@
|
||||
using Assets._Project.Develop.Runtime.Utilities.StateMachineCore;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.AI.States
|
||||
{
|
||||
public class EmptyState : State, IUpdatableState
|
||||
{
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f40181e821046968e6c69ecef7e2384
|
||||
timeCreated: 1772454318
|
||||
@@ -0,0 +1,67 @@
|
||||
using _Project.Develop.Runtime.Entities;
|
||||
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 RandomMovementState : State, IUpdatableState
|
||||
{
|
||||
private ReactiveVariable<Vector3> _moveDirection;
|
||||
private ReactiveVariable<Vector3> _rotateDirection;
|
||||
|
||||
private float _cooldownBetweenDirection;
|
||||
|
||||
private float _time;
|
||||
|
||||
|
||||
public RandomMovementState(Entity entity, float cooldownBetweenDirection)
|
||||
{
|
||||
_moveDirection = entity.MoveDirection;
|
||||
_rotateDirection = entity.RotateDirection;
|
||||
|
||||
_cooldownBetweenDirection = cooldownBetweenDirection;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
base.Enter();
|
||||
|
||||
Vector3 randomDirection = new Vector3(Random.Range(-1f, 1f), 0, Random.Range(-1f, 1f)).normalized;
|
||||
_moveDirection.Value = randomDirection;
|
||||
_rotateDirection.Value = randomDirection;
|
||||
|
||||
_time = 0;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
_time += deltaTime;
|
||||
|
||||
if (_time >= _cooldownBetweenDirection)
|
||||
{
|
||||
Vector3 newDirection = GenerateNewDirection();
|
||||
|
||||
_moveDirection.Value = newDirection;
|
||||
_rotateDirection.Value = newDirection;
|
||||
|
||||
_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
base.Exit();
|
||||
|
||||
_moveDirection.Value = Vector3.zero;
|
||||
}
|
||||
|
||||
private Vector3 GenerateNewDirection()
|
||||
{
|
||||
Vector3 inverseDirection = -_moveDirection.Value.normalized;
|
||||
Quaternion randomTurn = Quaternion.Euler(0, Random.Range(-30, 30), 0);
|
||||
|
||||
return randomTurn * inverseDirection;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd6446a9b2f646bc870251ae870904b3
|
||||
timeCreated: 1772454385
|
||||
Reference in New Issue
Block a user