From ce5862131629fe30595f55c2389d8e622f6c07b5 Mon Sep 17 00:00:00 2001 From: art Date: Sat, 21 Jun 2025 11:07:16 +0900 Subject: [PATCH] =?UTF-8?q?[feat]=20=EB=B9=84=EB=8F=99=EA=B8=B0=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EB=A8=B8=EC=8B=A0=20=EB=B0=8F=20=EC=8B=B1?= =?UTF-8?q?=EA=B8=80=ED=86=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/1_Script/Common/AsyncStateMachine.cs | 94 ++++++++++++++++ .../1_Script/Common/AsyncStateMachine.cs.meta | 11 ++ .../Common/AsyncStateMachineContext.cs | 103 ++++++++++++++++++ .../Common/AsyncStateMachineContext.cs.meta | 11 ++ Assets/1_Script/System/Singleton.cs | 20 ++++ Assets/1_Script/System/Singleton.cs.meta | 11 ++ 6 files changed, 250 insertions(+) create mode 100644 Assets/1_Script/Common/AsyncStateMachine.cs create mode 100644 Assets/1_Script/Common/AsyncStateMachine.cs.meta create mode 100644 Assets/1_Script/Common/AsyncStateMachineContext.cs create mode 100644 Assets/1_Script/Common/AsyncStateMachineContext.cs.meta create mode 100644 Assets/1_Script/System/Singleton.cs create mode 100644 Assets/1_Script/System/Singleton.cs.meta diff --git a/Assets/1_Script/Common/AsyncStateMachine.cs b/Assets/1_Script/Common/AsyncStateMachine.cs new file mode 100644 index 0000000..c38754a --- /dev/null +++ b/Assets/1_Script/Common/AsyncStateMachine.cs @@ -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> transitions = new Dictionary>(); + private List globalTransitions = new List(); + + 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 condition) + { + if (!transitions.ContainsKey(fromState)) + { + transitions[fromState] = new List(); + } + transitions[fromState].Add(new Transition(toState, condition)); + } + + public void AddGlobalTransition(IAsyncState toState, Func condition) + { + globalTransitions.Add(new Transition(toState, condition)); + } + + private class Transition + { + public IAsyncState TargetState { get; } + public Func Condition { get; } + + public Transition(IAsyncState targetState, Func condition) + { + TargetState = targetState; + Condition = condition; + } + } + } diff --git a/Assets/1_Script/Common/AsyncStateMachine.cs.meta b/Assets/1_Script/Common/AsyncStateMachine.cs.meta new file mode 100644 index 0000000..7b3990d --- /dev/null +++ b/Assets/1_Script/Common/AsyncStateMachine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 990671db329eb1043bab4ecac29c9221 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/1_Script/Common/AsyncStateMachineContext.cs b/Assets/1_Script/Common/AsyncStateMachineContext.cs new file mode 100644 index 0000000..a530206 --- /dev/null +++ b/Assets/1_Script/Common/AsyncStateMachineContext.cs @@ -0,0 +1,103 @@ +using Cysharp.Threading.Tasks; +using System; +using System.Collections.Generic; +using UnityEngine; + public interface IAsyncState + { + UniTask Enter(T context); + UniTask Execute(T context); + UniTask Exit(T context); + } + + public class AsyncStateMachine + { + private IAsyncState currentState; + private Dictionary, List> transitions = new Dictionary, List>(); + private List globalTransitions = new List(); + + public async UniTask ChangeState(IAsyncState 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 fromState, IAsyncState toState, Func condition) + { + if (!transitions.ContainsKey(fromState)) + { + transitions[fromState] = new List(); + } + transitions[fromState].Add(new Transition(toState, condition)); + } + + public void AddGlobalTransition(IAsyncState toState, Func condition) + { + globalTransitions.Add(new Transition(toState, condition)); + } + + /// + /// 상태머신 내부 데이터를 초기화합니다. + /// + public void Clear() + { + currentState = null; + transitions.Clear(); + globalTransitions.Clear(); + } + + + private class Transition + { + public IAsyncState TargetState { get; } + public Func Condition { get; } + + public Transition(IAsyncState targetState, Func condition) + { + TargetState = targetState; + Condition = condition; + } + } + } diff --git a/Assets/1_Script/Common/AsyncStateMachineContext.cs.meta b/Assets/1_Script/Common/AsyncStateMachineContext.cs.meta new file mode 100644 index 0000000..19b38f3 --- /dev/null +++ b/Assets/1_Script/Common/AsyncStateMachineContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d6e9c874a25bd84996c716c294b629c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/1_Script/System/Singleton.cs b/Assets/1_Script/System/Singleton.cs new file mode 100644 index 0000000..c643e9c --- /dev/null +++ b/Assets/1_Script/System/Singleton.cs @@ -0,0 +1,20 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System; + + public class Singleton where T : class, new() + { + private static readonly Lazy instance = new Lazy(() => new T(), true); + + public static T Instance => instance.Value; + + protected Singleton() + { + if (instance.IsValueCreated) + { + throw new InvalidOperationException("Singleton instance already created."); + } + } + } + diff --git a/Assets/1_Script/System/Singleton.cs.meta b/Assets/1_Script/System/Singleton.cs.meta new file mode 100644 index 0000000..0af06e8 --- /dev/null +++ b/Assets/1_Script/System/Singleton.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9867a93428506e49a36d6ed9da583c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: