mirror of
https://github.com/Bragin-Stepan/project-entity.git
synced 2026-03-02 14:29:23 +00:00
feat: add state machine
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,6 +27,7 @@
|
||||
|
||||
# Visual Studio cache directory
|
||||
.vs/
|
||||
.agent/
|
||||
|
||||
# Gradle cache directory
|
||||
.gradle/
|
||||
|
||||
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"visualstudiotoolsforunity.vstuc"
|
||||
]
|
||||
}
|
||||
10
.vscode/launch.json
vendored
Normal file
10
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach to Unity",
|
||||
"type": "vstuc",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -15,6 +15,7 @@ using Assets._Project.Develop.Runtime.Utilities.DataManagement;
|
||||
using Assets._Project.Develop.Runtime.Utilities.DataManagement.DataProviders;
|
||||
using Assets._Project.Develop.Runtime.Utilities.LoadingScreen;
|
||||
using Assets._Project.Develop.Runtime.Utilities.SceneManagement;
|
||||
using Assets._Project.Develop.Runtime.Utilities.Timer;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Infrastructure.EntryPoint
|
||||
@@ -24,6 +25,7 @@ namespace Assets._Project.Develop.Runtime.Infrastructure.EntryPoint
|
||||
public static void Process(DIContainer container)
|
||||
{
|
||||
container.RegisterAsSingle<ICoroutinesPerformer>(CreateCoroutinesPerformer);
|
||||
container.RegisterAsSingle(CreateTimerServiceFactory);
|
||||
container.RegisterAsSingle(CreateConfigsProviderService);
|
||||
container.RegisterAsSingle(CreateResourcesAssetsLoader);
|
||||
container.RegisterAsSingle(CreateSceneLoaderService);
|
||||
@@ -64,6 +66,8 @@ namespace Assets._Project.Develop.Runtime.Infrastructure.EntryPoint
|
||||
|
||||
private static InputFactory CreateInputFactory(DIContainer c) => new();
|
||||
|
||||
private static TimerServiceFactory CreateTimerServiceFactory(DIContainer c) => new (c);
|
||||
|
||||
private static PlayerInput CreatePlayerInput(DIContainer c) => c.Resolve<InputFactory>().CreatePlayerInput();
|
||||
|
||||
private static UIInput CreateUIInput(DIContainer c) => c.Resolve<InputFactory>().CreateUIInput();
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d79e4112f0c64a90b05cae78e957a829
|
||||
timeCreated: 1772454294
|
||||
@@ -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
|
||||
@@ -3,7 +3,7 @@ using _Project.Develop.Runtime.Entities;
|
||||
using _Project.Develop.Runtime.Utilities.Conditions;
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement;
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement.Event;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Energy.Systems
|
||||
{
|
||||
@@ -45,12 +45,12 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Energy.Systems
|
||||
if (energyDifference <= 0)
|
||||
return;
|
||||
|
||||
int regenAmount= (int)math.floor(_maxEnergy.Value * (percentage / 100f));
|
||||
int regenAmount = (int)Mathf.Floor(_maxEnergy.Value * (percentage / 100f));
|
||||
|
||||
if (regenAmount < 1 && _maxEnergy.Value > 0)
|
||||
regenAmount = 1;
|
||||
|
||||
int valueAdded = math.min(regenAmount, energyDifference);
|
||||
int valueAdded = Mathf.Min(regenAmount, energyDifference);
|
||||
|
||||
_currentEnergy.Value += valueAdded;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using _Project.Develop.Runtime.Entities;
|
||||
using _Project.Develop.Runtime.Utilities.Conditions;
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement;
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement.Event;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Energy.Systems
|
||||
@@ -46,7 +45,7 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features.Energy.Systems
|
||||
if (energyDifference <= 0)
|
||||
return;
|
||||
|
||||
int valueAdded = math.min(value, energyDifference);
|
||||
int valueAdded = Mathf.Min(value, energyDifference);
|
||||
|
||||
_currentEnergy.Value += valueAdded;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections;
|
||||
using _Project.Develop.Runtime.Entities;
|
||||
using _Project.Develop.Runtime.Logic.Gameplay.Features;
|
||||
using _Project.Develop.Runtime.Logic.Gameplay.Features.AI;
|
||||
using _Project.Develop.Runtime.Utils.InputManagement;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -16,7 +17,7 @@ namespace Assets._Project.Develop.Runtime.Gameplay.Infrastructure
|
||||
|
||||
private DIContainer _container;
|
||||
private EntitiesLifeContext _entitiesLifeContext;
|
||||
private GameplayInputArgs _gameplayArgs;
|
||||
private AIBrainsContext _aiBrainsContext;
|
||||
|
||||
private IPlayerInput _playerInput;
|
||||
|
||||
@@ -28,12 +29,12 @@ namespace Assets._Project.Develop.Runtime.Gameplay.Infrastructure
|
||||
throw new ArgumentException($"{nameof(sceneArgs)} is not match with {typeof(GameplayInputArgs)} type");
|
||||
|
||||
GameplayContextRegistrations.Process(_container);
|
||||
_gameplayArgs = gameplayInputArgs;
|
||||
}
|
||||
|
||||
public override IEnumerator Initialize()
|
||||
{
|
||||
_entitiesLifeContext = _container.Resolve<EntitiesLifeContext>();
|
||||
_aiBrainsContext = _container.Resolve<AIBrainsContext>();
|
||||
|
||||
_testGameplay.Initialize(_container);
|
||||
yield break;
|
||||
@@ -46,6 +47,7 @@ namespace Assets._Project.Develop.Runtime.Gameplay.Infrastructure
|
||||
|
||||
private void Update()
|
||||
{
|
||||
_aiBrainsContext?.Update(Time.deltaTime);
|
||||
_entitiesLifeContext?.Update(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using _Project.Develop.Runtime.Entities;
|
||||
using _Project.Develop.Runtime.Logic.Gameplay.Features.AI;
|
||||
using _Project.Develop.Runtime.UI;
|
||||
using _Project.Develop.Runtime.UI.Core;
|
||||
using _Project.Develop.Runtime.UI.Screens.Gameplay;
|
||||
@@ -21,9 +22,13 @@ namespace Assets._Project.Develop.Runtime.Gameplay.Infrastructure
|
||||
container.RegisterAsSingle(CreateEntitiesFactory);
|
||||
container.RegisterAsSingle(CreateEntitiesLifeContext);
|
||||
container.RegisterAsSingle(CreateCollidersRegistryService);
|
||||
container.RegisterAsSingle(CreateAIBrainContext);
|
||||
container.RegisterAsSingle(CreateBrainsFactory);
|
||||
container.RegisterAsSingle(CreateMonoEntitiesFactory).NonLazy();
|
||||
}
|
||||
|
||||
private static AIBrainsContext CreateAIBrainContext(DIContainer c) => new();
|
||||
private static BrainsFactory CreateBrainsFactory(DIContainer c) => new(c);
|
||||
private static EntitiesLifeContext CreateEntitiesLifeContext(DIContainer c) => new();
|
||||
|
||||
private static EntitiesFactory CreateEntitiesFactory(DIContainer c) => new(c);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using _Project.Develop.Runtime.Entities;
|
||||
using _Project.Develop.Runtime.Logic.Gameplay.Features.AI;
|
||||
using _Project.Develop.Runtime.Utils.InputManagement;
|
||||
using Assets._Project.Develop.Runtime.Infrastructure.DI;
|
||||
using UnityEngine;
|
||||
@@ -10,8 +11,11 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features
|
||||
{
|
||||
private DIContainer _container;
|
||||
private EntitiesFactory _entitiesFactory;
|
||||
private BrainsFactory _brainsFactory;
|
||||
|
||||
private Entity _hero;
|
||||
private Entity _ghost;
|
||||
|
||||
private Entity _entity;
|
||||
private bool _isRunning;
|
||||
|
||||
public void Initialize(DIContainer container)
|
||||
@@ -20,15 +24,15 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features
|
||||
|
||||
_container.Resolve<IPlayerInput>().Enable();
|
||||
_entitiesFactory = _container.Resolve<EntitiesFactory>();
|
||||
_brainsFactory = _container.Resolve<BrainsFactory>();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
_entity = _entitiesFactory.CreateTeleportWizard(Vector3.zero);
|
||||
_hero = _entitiesFactory.CreateTeleportWizard(Vector3.zero);
|
||||
_ghost = _entitiesFactory.CreateGhost(Vector3.zero + Vector3.forward * 5);
|
||||
|
||||
_entitiesFactory.CreateGhost(Vector3.zero + Vector3.forward * 5);
|
||||
_entitiesFactory.CreateGhost(Vector3.zero + Vector3.right * 5);
|
||||
_entitiesFactory.CreateGhost(Vector3.zero + Vector3.left * 5);
|
||||
_brainsFactory.CreateGhostBrain(_ghost);
|
||||
|
||||
_isRunning = true;
|
||||
}
|
||||
@@ -41,11 +45,11 @@ namespace _Project.Develop.Runtime.Logic.Gameplay.Features
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (_entity == null)
|
||||
if (_hero == null)
|
||||
return;
|
||||
|
||||
GUI.Label(new Rect(10, 20, 200, 50), $"Health: {_entity.CurrentHealth.Value}/{_entity.MaxHealth.Value}");
|
||||
GUI.Label(new Rect(10, 40, 200, 50), $"Energy: {_entity.CurrentEnergy.Value}/{_entity.MaxEnergy.Value}");
|
||||
GUI.Label(new Rect(10, 20, 200, 50), $"Health: {_hero.CurrentHealth.Value}/{_hero.MaxHealth.Value}");
|
||||
GUI.Label(new Rect(10, 40, 200, 50), $"Energy: {_hero.CurrentEnergy.Value}/{_hero.MaxEnergy.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,9 +41,9 @@ namespace _Project.Develop.Runtime.Utils.ReactiveManagement.Event
|
||||
|
||||
public class ReactiveEvent : IReadOnlyEvent
|
||||
{
|
||||
private readonly List<Subscriber> _subscribers = new();
|
||||
private readonly List<Subscriber> _toAdd = new();
|
||||
private readonly List<Subscriber> _toRemove = new();
|
||||
private readonly List<Subscriber> _subscribers = new List<Subscriber>();
|
||||
private readonly List<Subscriber> _toAdd = new List<Subscriber>();
|
||||
private readonly List<Subscriber> _toRemove = new List<Subscriber>();
|
||||
|
||||
public IDisposable Subscribe(Action action)
|
||||
{
|
||||
|
||||
@@ -5,9 +5,9 @@ namespace _Project.Develop.Runtime.Utils.ReactiveManagement
|
||||
{
|
||||
public class ReactiveVariable<T> : IReadOnlyVariable<T> where T : IEquatable<T>
|
||||
{
|
||||
private readonly List<Subscriber<T, T>> _subscribers = new ();
|
||||
private readonly List<Subscriber<T, T>> _toAddList = new ();
|
||||
private readonly List<Subscriber<T, T>> _toRemoveList = new ();
|
||||
private readonly List<Subscriber<T, T>> _subscribers = new List<Subscriber<T, T>>();
|
||||
private readonly List<Subscriber<T, T>> _toAddList = new List<Subscriber<T, T>>();
|
||||
private readonly List<Subscriber<T, T>> _toRemoveList = new List<Subscriber<T, T>>();
|
||||
|
||||
public ReactiveVariable() => _value = default(T);
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace _Project.Develop.Runtime.Utils.ReactiveManagement
|
||||
|
||||
public IDisposable Subscribe(Action<T, T> action)
|
||||
{
|
||||
Subscriber<T, T> subscriber = new (action, RemoveSubscriber);
|
||||
Subscriber<T, T> subscriber = new Subscriber<T, T>(action, RemoveSubscriber);
|
||||
_toAddList.Add(subscriber);
|
||||
|
||||
return subscriber;
|
||||
@@ -40,13 +40,13 @@ namespace _Project.Develop.Runtime.Utils.ReactiveManagement
|
||||
|
||||
private void Invoke(T oldValue, T newValue)
|
||||
{
|
||||
if(_toAddList.Count > 0)
|
||||
if (_toAddList.Count > 0)
|
||||
{
|
||||
_subscribers.AddRange(_toAddList);
|
||||
_toAddList.Clear();
|
||||
}
|
||||
|
||||
if(_toRemoveList.Count > 0)
|
||||
if (_toRemoveList.Count > 0)
|
||||
{
|
||||
foreach (Subscriber<T, T> subscriber in _toRemoveList)
|
||||
_subscribers.Remove(subscriber);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement.Event;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public interface IState
|
||||
{
|
||||
IReadOnlyEvent Entered { get; }
|
||||
IReadOnlyEvent Exited { get; }
|
||||
|
||||
void Enter();
|
||||
void Exit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aed062833c374a6c8f4f784616dad179
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public interface IUpdatableState : IState
|
||||
{
|
||||
void Update(float deltaTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1ea582554484972bd37276974ad4434
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public abstract class ParallelState<TState> : State where TState : class, IState
|
||||
{
|
||||
private List<TState> _states;
|
||||
|
||||
public ParallelState(params TState[] states)
|
||||
{
|
||||
_states = new List<TState>(states);
|
||||
}
|
||||
|
||||
protected IReadOnlyList<TState> States => _states;
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
base.Enter();
|
||||
|
||||
foreach (TState state in _states)
|
||||
state.Enter();
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
base.Exit();
|
||||
|
||||
foreach (TState state in _states)
|
||||
state.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3084d8be941e4eb89f019da66b818702
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,18 @@
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement.Event;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public abstract class State : IState
|
||||
{
|
||||
private ReactiveEvent _entered = new();
|
||||
private ReactiveEvent _exited = new();
|
||||
|
||||
public IReadOnlyEvent Entered => _entered;
|
||||
|
||||
public IReadOnlyEvent Exited => _exited;
|
||||
|
||||
public virtual void Enter() => _entered.Invoke();
|
||||
|
||||
public virtual void Exit() => _exited.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 975fa4387d1e4f37afb584f32071e4bc
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using _Project.Develop.Runtime.Utilities.Conditions;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public abstract class StateMachine<TState> : State, IDisposable, IUpdatableState where TState : class, IState
|
||||
{
|
||||
private List<StateNode<TState>> _states = new();
|
||||
|
||||
private StateNode<TState> _currentState;
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
private List<IDisposable> _disposables;
|
||||
|
||||
protected StateMachine(List<IDisposable> disposables)
|
||||
{
|
||||
_disposables = new List<IDisposable>(disposables);
|
||||
}
|
||||
|
||||
protected TState CurrentState => _currentState.State;
|
||||
|
||||
public void AddState(TState state) => _states.Add(new StateNode<TState>(state));
|
||||
|
||||
public void AddTransition(TState fromState, TState toState, ICondition condition)
|
||||
{
|
||||
StateNode<TState> from = _states.First(stateNode => stateNode.State == fromState);
|
||||
StateNode<TState> to = _states.First(stateNode => stateNode.State == toState);
|
||||
|
||||
from.AddTransition(new StateTransition<TState>(to, condition));
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (_isRunning == false)
|
||||
return;
|
||||
|
||||
foreach (StateTransition<TState> transition in _currentState.Transitions)
|
||||
{
|
||||
if (transition.Condition.Evaluate())
|
||||
{
|
||||
SwitchState(transition.ToState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateLogic(deltaTime);
|
||||
}
|
||||
|
||||
protected virtual void UpdateLogic(float deltaTime) { }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_isRunning = false;
|
||||
|
||||
foreach (StateNode<TState> stateNode in _states)
|
||||
if (stateNode.State is IDisposable disposableState)
|
||||
disposableState.Dispose();
|
||||
|
||||
_states.Clear();
|
||||
|
||||
foreach (IDisposable disposable in _disposables)
|
||||
disposable.Dispose();
|
||||
|
||||
_disposables.Clear();
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
base.Enter();
|
||||
|
||||
if (_currentState == null)
|
||||
SwitchState(_states[0]);
|
||||
|
||||
_isRunning = true;
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
base.Exit();
|
||||
|
||||
_currentState?.State.Exit();
|
||||
|
||||
_isRunning = false;
|
||||
}
|
||||
|
||||
private void SwitchState(StateNode<TState> nextState)
|
||||
{
|
||||
_currentState?.State.Exit();
|
||||
_currentState = nextState;
|
||||
_currentState.State.Enter();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 421f6f14fa064baaa737bea3684d473f
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public class StateNode<TState> where TState : class, IState
|
||||
{
|
||||
private List<StateTransition<TState>> _transitions = new();
|
||||
|
||||
public StateNode(TState state)
|
||||
{
|
||||
State = state;
|
||||
}
|
||||
|
||||
public TState State { get; }
|
||||
|
||||
public IReadOnlyList<StateTransition<TState>> Transitions => _transitions;
|
||||
|
||||
public void AddTransition(StateTransition<TState> transition) => _transitions.Add(transition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dce697e6ac3b45b497e8e89c5ca258cc
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,16 @@
|
||||
using _Project.Develop.Runtime.Utilities.Conditions;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.StateMachineCore
|
||||
{
|
||||
public class StateTransition<TState> where TState : class, IState
|
||||
{
|
||||
public StateTransition(StateNode<TState> toState, ICondition condition)
|
||||
{
|
||||
ToState = toState;
|
||||
Condition = condition;
|
||||
}
|
||||
|
||||
public StateNode<TState> ToState { get; }
|
||||
public ICondition Condition { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07aef2e29c2643419ff17e32556da944
|
||||
timeCreated: 1772453453
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 831af1f46fb24b5c89e15c287f7bdfad
|
||||
timeCreated: 1772456814
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement;
|
||||
using _Project.Develop.Runtime.Utils.ReactiveManagement.Event;
|
||||
using Assets._Project.Develop.Runtime.Utilities.CoroutinesManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.Timer
|
||||
{
|
||||
public class TimerService : IDisposable
|
||||
{
|
||||
private float _cooldown;
|
||||
|
||||
private ReactiveEvent _cooldownEnded;
|
||||
|
||||
private ReactiveVariable<float> _currentTime;
|
||||
|
||||
private ICoroutinesPerformer _coroutinePerformer;
|
||||
private Coroutine _cooldownProcess;
|
||||
|
||||
public TimerService(
|
||||
float cooldown,
|
||||
ICoroutinesPerformer coroutinePerformer)
|
||||
{
|
||||
_cooldown = cooldown;
|
||||
_coroutinePerformer = coroutinePerformer;
|
||||
|
||||
_cooldownEnded = new ReactiveEvent();
|
||||
_currentTime = new ReactiveVariable<float>();
|
||||
}
|
||||
|
||||
public IReadOnlyEvent CooldownEnded => _cooldownEnded;
|
||||
public IReadOnlyVariable<float> CurrentTime => _currentTime;
|
||||
public bool IsOver => _currentTime.Value <= 0;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_cooldownProcess != null)
|
||||
_coroutinePerformer.StopPerform(_cooldownProcess);
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
Stop();
|
||||
|
||||
_cooldownProcess = _coroutinePerformer.StartPerform(CooldownProcess());
|
||||
}
|
||||
|
||||
private IEnumerator CooldownProcess()
|
||||
{
|
||||
_currentTime.Value = _cooldown;
|
||||
|
||||
while (IsOver == false)
|
||||
{
|
||||
_currentTime.Value -= Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
_cooldownEnded.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5636415f9a840ab8ff88d96719179ec
|
||||
timeCreated: 1772456820
|
||||
@@ -0,0 +1,18 @@
|
||||
using Assets._Project.Develop.Runtime.Infrastructure.DI;
|
||||
using Assets._Project.Develop.Runtime.Utilities.CoroutinesManagement;
|
||||
|
||||
namespace Assets._Project.Develop.Runtime.Utilities.Timer
|
||||
{
|
||||
public class TimerServiceFactory
|
||||
{
|
||||
private readonly DIContainer _container;
|
||||
|
||||
public TimerServiceFactory(DIContainer container)
|
||||
{
|
||||
_container = container;
|
||||
}
|
||||
|
||||
public TimerService Create(float cooldown)
|
||||
=> new TimerService(cooldown, _container.Resolve<ICoroutinesPerformer>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fbab9cab89b4ad094fc636facb8597a
|
||||
timeCreated: 1772456820
|
||||
@@ -924,7 +924,7 @@ PlayerSettings:
|
||||
embeddedLinuxEnableGamepadInput: 1
|
||||
hmiLogStartupTiming: 0
|
||||
hmiCpuConfiguration:
|
||||
apiCompatibilityLevel: 6
|
||||
apiCompatibilityLevel: 3
|
||||
activeInputHandler: 2
|
||||
windowsGamepadBackendHint: 0
|
||||
cloudProjectId: 4a15d730-99ee-4a69-b00c-c0c75aa639bd
|
||||
|
||||
33
project-entity.slnx
Normal file
33
project-entity.slnx
Normal file
@@ -0,0 +1,33 @@
|
||||
<Solution>
|
||||
<Project Path="Unity.Timeline.csproj" />
|
||||
<Project Path="Unity.Timeline.Editor.csproj" />
|
||||
<Project Path="Assembly-CSharp.csproj" />
|
||||
<Project Path="Unity.InputSystem.csproj" />
|
||||
<Project Path="Unity.TextMeshPro.Editor.csproj" />
|
||||
<Project Path="Unity.PlasticSCM.Editor.csproj" />
|
||||
<Project Path="Unity.VisualScripting.Flow.csproj" />
|
||||
<Project Path="Unity.VisualScripting.Core.csproj" />
|
||||
<Project Path="Unity.Mathematics.csproj" />
|
||||
<Project Path="Unity.VisualScripting.Core.Editor.csproj" />
|
||||
<Project Path="Unity.VisualScripting.Flow.Editor.csproj" />
|
||||
<Project Path="UnityEditor.TestRunner.csproj" />
|
||||
<Project Path="Unity.VisualScripting.SettingsProvider.Editor.csproj" />
|
||||
<Project Path="UnityEngine.TestRunner.csproj" />
|
||||
<Project Path="Unity.Searcher.Editor.csproj" />
|
||||
<Project Path="Unity.Burst.csproj" />
|
||||
<Project Path="Unity.VisualStudio.Editor.csproj" />
|
||||
<Project Path="Unity.Rider.Editor.csproj" />
|
||||
<Project Path="Unity.CollabProxy.Editor.csproj" />
|
||||
<Project Path="Unity.VisualScripting.State.Editor.csproj" />
|
||||
<Project Path="Unity.Burst.CodeGen.csproj" />
|
||||
<Project Path="Unity.VisualScripting.State.csproj" />
|
||||
<Project Path="Unity.TextMeshPro.csproj" />
|
||||
<Project Path="Assembly-CSharp-firstpass.csproj" />
|
||||
<Project Path="Unity.VSCode.Editor.csproj" />
|
||||
<Project Path="Unity.Burst.Editor.csproj" />
|
||||
<Project Path="Unity.InputSystem.ForUI.csproj" />
|
||||
<Project Path="Unity.Mathematics.Editor.csproj" />
|
||||
<Project Path="Unity.InputSystem.TestFramework.csproj" />
|
||||
<Project Path="Unity.VisualScripting.Shared.Editor.csproj" />
|
||||
<Project Path="Assembly-CSharp-Editor.csproj" />
|
||||
</Solution>
|
||||
Reference in New Issue
Block a user