[feat] 비동기 상태 머신 및 싱글톤 추가
This commit is contained in:
parent
abc2cfb3ca
commit
ce58621316
|
@ -0,0 +1,94 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
public interface IAsyncState
|
||||
{
|
||||
UniTask Enter();
|
||||
UniTask Execute();
|
||||
UniTask Exit();
|
||||
}
|
||||
|
||||
public class AsyncStateMachine
|
||||
{
|
||||
private IAsyncState currentState;
|
||||
private Dictionary<IAsyncState, List<Transition>> transitions = new Dictionary<IAsyncState, List<Transition>>();
|
||||
private List<Transition> globalTransitions = new List<Transition>();
|
||||
|
||||
public async UniTask ChangeState(IAsyncState newState)
|
||||
{
|
||||
if (newState == currentState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
await currentState.Exit();
|
||||
}
|
||||
|
||||
currentState = newState;
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
await currentState.Enter();
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask Update()
|
||||
{
|
||||
foreach (var transition in globalTransitions)
|
||||
{
|
||||
if (transition.Condition())
|
||||
{
|
||||
await ChangeState(transition.TargetState);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState != null && transitions.ContainsKey(currentState))
|
||||
{
|
||||
foreach (var transition in transitions[currentState])
|
||||
{
|
||||
if (transition.Condition())
|
||||
{
|
||||
await ChangeState(transition.TargetState);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
await currentState.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddTransition(IAsyncState fromState, IAsyncState toState, Func<bool> condition)
|
||||
{
|
||||
if (!transitions.ContainsKey(fromState))
|
||||
{
|
||||
transitions[fromState] = new List<Transition>();
|
||||
}
|
||||
transitions[fromState].Add(new Transition(toState, condition));
|
||||
}
|
||||
|
||||
public void AddGlobalTransition(IAsyncState toState, Func<bool> condition)
|
||||
{
|
||||
globalTransitions.Add(new Transition(toState, condition));
|
||||
}
|
||||
|
||||
private class Transition
|
||||
{
|
||||
public IAsyncState TargetState { get; }
|
||||
public Func<bool> Condition { get; }
|
||||
|
||||
public Transition(IAsyncState targetState, Func<bool> condition)
|
||||
{
|
||||
TargetState = targetState;
|
||||
Condition = condition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 990671db329eb1043bab4ecac29c9221
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,103 @@
|
|||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
public interface IAsyncState<T>
|
||||
{
|
||||
UniTask Enter(T context);
|
||||
UniTask Execute(T context);
|
||||
UniTask Exit(T context);
|
||||
}
|
||||
|
||||
public class AsyncStateMachine<T>
|
||||
{
|
||||
private IAsyncState<T> currentState;
|
||||
private Dictionary<IAsyncState<T>, List<Transition>> transitions = new Dictionary<IAsyncState<T>, List<Transition>>();
|
||||
private List<Transition> globalTransitions = new List<Transition>();
|
||||
|
||||
public async UniTask ChangeState(IAsyncState<T> newState, T context)
|
||||
{
|
||||
if (newState == currentState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (currentState != null)
|
||||
{
|
||||
await currentState.Exit(context);
|
||||
}
|
||||
|
||||
//Debug.Log($"{context} -> {currentState} -> {newState}");
|
||||
currentState = newState;
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
await currentState.Enter(context);
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask Update(T context)
|
||||
{
|
||||
foreach (var transition in globalTransitions)
|
||||
{
|
||||
if (transition.Condition())
|
||||
{
|
||||
await ChangeState(transition.TargetState, context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState != null && transitions.ContainsKey(currentState))
|
||||
{
|
||||
foreach (var transition in transitions[currentState])
|
||||
{
|
||||
if (transition.Condition())
|
||||
{
|
||||
await ChangeState(transition.TargetState, context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
await currentState.Execute(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddTransition(IAsyncState<T> fromState, IAsyncState<T> toState, Func<bool> condition)
|
||||
{
|
||||
if (!transitions.ContainsKey(fromState))
|
||||
{
|
||||
transitions[fromState] = new List<Transition>();
|
||||
}
|
||||
transitions[fromState].Add(new Transition(toState, condition));
|
||||
}
|
||||
|
||||
public void AddGlobalTransition(IAsyncState<T> toState, Func<bool> condition)
|
||||
{
|
||||
globalTransitions.Add(new Transition(toState, condition));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 상태머신 내부 데이터를 초기화합니다.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
currentState = null;
|
||||
transitions.Clear();
|
||||
globalTransitions.Clear();
|
||||
}
|
||||
|
||||
|
||||
private class Transition
|
||||
{
|
||||
public IAsyncState<T> TargetState { get; }
|
||||
public Func<bool> Condition { get; }
|
||||
|
||||
public Transition(IAsyncState<T> targetState, Func<bool> condition)
|
||||
{
|
||||
TargetState = targetState;
|
||||
Condition = condition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8d6e9c874a25bd84996c716c294b629c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,20 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
public class Singleton<T> where T : class, new()
|
||||
{
|
||||
private static readonly Lazy<T> instance = new Lazy<T>(() => new T(), true);
|
||||
|
||||
public static T Instance => instance.Value;
|
||||
|
||||
protected Singleton()
|
||||
{
|
||||
if (instance.IsValueCreated)
|
||||
{
|
||||
throw new InvalidOperationException("Singleton instance already created.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9867a93428506e49a36d6ed9da583c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue