Skip to content

Commit 103dd05

Browse files
committed
Update file(s) "Packages/unity-utils/." from "unity-korea-community/unity-utils"
1 parent 62f8abf commit 103dd05

File tree

3 files changed

+219
-2
lines changed

3 files changed

+219
-2
lines changed

Runtime/StateMachineGeneric.cs

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using UnityEngine;
5+
using UNKO.Utils;
6+
7+
namespace UNKO.Utils
8+
{
9+
public interface IState
10+
{
11+
void OnAwake();
12+
IEnumerator OnStartCoroutine();
13+
void OnChangeState(IState newState);
14+
void OnFinishState();
15+
}
16+
17+
/// <summary>
18+
/// State를 관리하는 머신
19+
/// </summary>
20+
public class StateMachineGeneric<STATE_ID, TSTATE>
21+
where TSTATE : class, IState
22+
{
23+
public enum CommandType
24+
{
25+
Change,
26+
Finish,
27+
}
28+
29+
[System.Serializable]
30+
public struct Command
31+
{
32+
public CommandType commandType { get; private set; }
33+
public STATE_ID stateID { get; private set; }
34+
35+
public Command(CommandType commandType)
36+
{
37+
this.commandType = commandType;
38+
stateID = default;
39+
}
40+
41+
public Command(CommandType commandType, STATE_ID stateID)
42+
{
43+
this.commandType = commandType;
44+
this.stateID = stateID;
45+
}
46+
}
47+
48+
public event System.Action<STATE_ID, TSTATE> OnChangeState;
49+
50+
public STATE_ID currentStateID => _currentStateID;
51+
[SerializeField]
52+
private STATE_ID _currentStateID;
53+
54+
public TSTATE currentState { get; private set; }
55+
protected MonoBehaviour _owner;
56+
protected Dictionary<STATE_ID, TSTATE> _stateInstance;
57+
58+
// inspector에서 보기 위해 queue 대신 list 사용
59+
[SerializeField]
60+
List<Command> _commandQueue = new List<Command>();
61+
[SerializeField]
62+
List<STATE_ID> _waitQueue = new List<STATE_ID>();
63+
64+
private Coroutine _currentCoroutine;
65+
66+
public StateMachineGeneric(Dictionary<STATE_ID, TSTATE> stateInstances)
67+
{
68+
_stateInstance = stateInstances;
69+
}
70+
71+
/// <summary>
72+
/// FSM을 시작합니다.
73+
/// </summary>
74+
/// <param name="owner">Mono</param>
75+
/// <param name="startState">시작할 스테이트</param>
76+
/// <param name="nextStates">시작 스테이트 다음 시작할 스테이트들</param>
77+
public void Start(MonoBehaviour owner, STATE_ID startState, params STATE_ID[] nextStates)
78+
{
79+
_owner = owner;
80+
81+
Clear();
82+
ChangeState(startState);
83+
EnqueueToWaitQueue(nextStates);
84+
_owner.StartCoroutine(UpdateCoroutine());
85+
}
86+
87+
88+
/// <summary>
89+
/// 스테이트를 다음 스테이트로 변경합니다.
90+
/// </summary>
91+
/// <param name="state">변경할 스테이트</param>
92+
public void ChangeState(STATE_ID state)
93+
{
94+
_commandQueue.Add(new Command(CommandType.Change, state));
95+
}
96+
97+
/// <summary>
98+
/// 현재 스테이트를 종료합니다.
99+
/// </summary>
100+
public void FinishState()
101+
{
102+
_commandQueue.Add(new Command(CommandType.Finish));
103+
}
104+
105+
/// <summary>
106+
/// WaitQueue에 스테이트를 삽입합니다.
107+
/// </summary>
108+
/// <param name="nextStates"></param>
109+
public void EnqueueToWaitQueue(params STATE_ID[] nextStates)
110+
{
111+
// List version
112+
// _waitQueue.AddRange(nextStates.Select(item => new StateWithParam(item)));
113+
if (_waitQueue.Count > 10)
114+
Debug.LogWarning($"{_owner.name} _waitQueue.Count > 10", _owner);
115+
nextStates.Foreach(state => _waitQueue.Add(state));
116+
}
117+
118+
public StateMachineGeneric<STATE_ID, TSTATE> ForEachState(System.Action<TSTATE> OnEach)
119+
{
120+
_stateInstance.Values.Foreach(OnEach);
121+
122+
return this;
123+
}
124+
125+
public StateMachineGeneric<STATE_ID, TSTATE> Clear()
126+
{
127+
_waitQueue.Clear();
128+
_commandQueue.Clear();
129+
currentState = null;
130+
_currentStateID = default;
131+
132+
return this;
133+
}
134+
135+
IEnumerator UpdateCoroutine()
136+
{
137+
while (true)
138+
{
139+
while (_commandQueue.Count > 0)
140+
ProcessCommand(_commandQueue.Dequeue());
141+
142+
if (currentState == null && _waitQueue.Count > 0)
143+
OnStartState(_waitQueue.Dequeue());
144+
145+
yield return null;
146+
}
147+
}
148+
149+
private void ProcessCommand(Command command)
150+
{
151+
switch (command.commandType)
152+
{
153+
case CommandType.Change:
154+
OnStartState(command.stateID);
155+
break;
156+
157+
case CommandType.Finish:
158+
OnFinishState();
159+
break;
160+
161+
default:
162+
throw new System.ArgumentOutOfRangeException();
163+
}
164+
}
165+
166+
private void OnStartState(STATE_ID stateID)
167+
{
168+
if (_stateInstance.TryGetValue(stateID, out TSTATE state) == false)
169+
{
170+
Debug.LogError($"{_owner.name}.FSM.OnStartState(StateWithParam:'{stateID}') state is not found", _owner);
171+
return;
172+
}
173+
174+
if (state.Equals(currentState))
175+
{
176+
return;
177+
}
178+
179+
// Debug.Log($"OnStartState current:{currentState?.GetType().Name}, new:{state.GetType().Name}");
180+
181+
currentState?.OnChangeState(state);
182+
state.OnAwake();
183+
currentState = state;
184+
_currentStateID = stateID;
185+
_currentCoroutine = _owner.StartCoroutine(StateCoroutine());
186+
OnChangeState?.Invoke(stateID, currentState);
187+
}
188+
189+
private void OnFinishState()
190+
{
191+
// Debug.Log($"OnFinishState current:{currentState?.GetType().Name}");
192+
193+
if (_currentCoroutine != null)
194+
_owner.StopCoroutine(_currentCoroutine);
195+
currentState?.OnFinishState();
196+
currentState = null;
197+
_currentStateID = default;
198+
}
199+
200+
private IEnumerator StateCoroutine()
201+
{
202+
yield return currentState.OnStartCoroutine();
203+
_commandQueue.Add(new Command(CommandType.Finish));
204+
}
205+
}
206+
}

Runtime/StateMachineGeneric.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.unko.unity-utils",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"displayName": "UNKO Utils",
55
"description": "This is an example package",
66
"unity": "2019.1",
@@ -15,4 +15,4 @@
1515
"type": "git",
1616
"url": "https://github.com/unity-korea-community/unity-utils.git"
1717
}
18-
}
18+
}

0 commit comments

Comments
 (0)