Fsm.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. //------------------------------------------------------------
  2. // Game Framework
  3. // Copyright © 2013-2021 loyalsoft. All rights reserved.
  4. // Homepage: http://www.game7000.com/
  5. // Feedback: http://www.game7000.com/
  6. //------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. namespace GameFramework.Fsm
  10. {
  11. /// <summary>
  12. /// 有限状态机。
  13. /// </summary>
  14. /// <typeparam name="T">有限状态机持有者类型。</typeparam>
  15. internal sealed class Fsm<T> : FsmBase, IReference, IFsm<T> where T : class
  16. {
  17. private T m_Owner;
  18. private readonly Dictionary<Type, FsmState<T>> m_States;
  19. private Dictionary<string, Variable> m_Datas;
  20. private FsmState<T> m_CurrentState;
  21. private float m_CurrentStateTime;
  22. private bool m_IsDestroyed;
  23. /// <summary>
  24. /// 初始化有限状态机的新实例。
  25. /// </summary>
  26. public Fsm()
  27. {
  28. m_Owner = null;
  29. m_States = new Dictionary<Type, FsmState<T>>();
  30. m_Datas = null;
  31. m_CurrentState = null;
  32. m_CurrentStateTime = 0f;
  33. m_IsDestroyed = true;
  34. }
  35. /// <summary>
  36. /// 获取有限状态机持有者。
  37. /// </summary>
  38. public T Owner
  39. {
  40. get
  41. {
  42. return m_Owner;
  43. }
  44. }
  45. /// <summary>
  46. /// 获取有限状态机持有者类型。
  47. /// </summary>
  48. public override Type OwnerType
  49. {
  50. get
  51. {
  52. return typeof(T);
  53. }
  54. }
  55. /// <summary>
  56. /// 获取有限状态机中状态的数量。
  57. /// </summary>
  58. public override int FsmStateCount
  59. {
  60. get
  61. {
  62. return m_States.Count;
  63. }
  64. }
  65. /// <summary>
  66. /// 获取有限状态机是否正在运行。
  67. /// </summary>
  68. public override bool IsRunning
  69. {
  70. get
  71. {
  72. return m_CurrentState != null;
  73. }
  74. }
  75. /// <summary>
  76. /// 获取有限状态机是否被销毁。
  77. /// </summary>
  78. public override bool IsDestroyed
  79. {
  80. get
  81. {
  82. return m_IsDestroyed;
  83. }
  84. }
  85. /// <summary>
  86. /// 获取当前有限状态机状态。
  87. /// </summary>
  88. public FsmState<T> CurrentState
  89. {
  90. get
  91. {
  92. return m_CurrentState;
  93. }
  94. }
  95. /// <summary>
  96. /// 获取当前有限状态机状态名称。
  97. /// </summary>
  98. public override string CurrentStateName
  99. {
  100. get
  101. {
  102. return m_CurrentState != null ? m_CurrentState.GetType().FullName : null;
  103. }
  104. }
  105. /// <summary>
  106. /// 获取当前有限状态机状态持续时间。
  107. /// </summary>
  108. public override float CurrentStateTime
  109. {
  110. get
  111. {
  112. return m_CurrentStateTime;
  113. }
  114. }
  115. /// <summary>
  116. /// 创建有限状态机。
  117. /// </summary>
  118. /// <param name="name">有限状态机名称。</param>
  119. /// <param name="owner">有限状态机持有者。</param>
  120. /// <param name="states">有限状态机状态集合。</param>
  121. /// <returns>创建的有限状态机。</returns>
  122. public static Fsm<T> Create(string name, T owner, params FsmState<T>[] states)
  123. {
  124. if (owner == null)
  125. {
  126. throw new GameFrameworkException("FSM owner is invalid.");
  127. }
  128. if (states == null || states.Length < 1)
  129. {
  130. throw new GameFrameworkException("FSM states is invalid.");
  131. }
  132. Fsm<T> fsm = ReferencePool.Acquire<Fsm<T>>();
  133. fsm.Name = name;
  134. fsm.m_Owner = owner;
  135. fsm.m_IsDestroyed = false;
  136. foreach (FsmState<T> state in states)
  137. {
  138. if (state == null)
  139. {
  140. throw new GameFrameworkException("FSM states is invalid.");
  141. }
  142. Type stateType = state.GetType();
  143. if (fsm.m_States.ContainsKey(stateType))
  144. {
  145. throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName));
  146. }
  147. fsm.m_States.Add(stateType, state);
  148. state.OnInit(fsm);
  149. }
  150. return fsm;
  151. }
  152. /// <summary>
  153. /// 创建有限状态机。
  154. /// </summary>
  155. /// <param name="name">有限状态机名称。</param>
  156. /// <param name="owner">有限状态机持有者。</param>
  157. /// <param name="states">有限状态机状态集合。</param>
  158. /// <returns>创建的有限状态机。</returns>
  159. public static Fsm<T> Create(string name, T owner, List<FsmState<T>> states)
  160. {
  161. if (owner == null)
  162. {
  163. throw new GameFrameworkException("FSM owner is invalid.");
  164. }
  165. if (states == null || states.Count < 1)
  166. {
  167. throw new GameFrameworkException("FSM states is invalid.");
  168. }
  169. Fsm<T> fsm = ReferencePool.Acquire<Fsm<T>>();
  170. fsm.Name = name;
  171. fsm.m_Owner = owner;
  172. fsm.m_IsDestroyed = false;
  173. foreach (FsmState<T> state in states)
  174. {
  175. if (state == null)
  176. {
  177. throw new GameFrameworkException("FSM states is invalid.");
  178. }
  179. Type stateType = state.GetType();
  180. if (fsm.m_States.ContainsKey(stateType))
  181. {
  182. throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName));
  183. }
  184. fsm.m_States.Add(stateType, state);
  185. state.OnInit(fsm);
  186. }
  187. return fsm;
  188. }
  189. /// <summary>
  190. /// 清理有限状态机。
  191. /// </summary>
  192. public void Clear()
  193. {
  194. if (m_CurrentState != null)
  195. {
  196. m_CurrentState.OnLeave(this, true);
  197. }
  198. foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
  199. {
  200. state.Value.OnDestroy(this);
  201. }
  202. Name = null;
  203. m_Owner = null;
  204. m_States.Clear();
  205. if (m_Datas != null)
  206. {
  207. foreach (KeyValuePair<string, Variable> data in m_Datas)
  208. {
  209. if (data.Value == null)
  210. {
  211. continue;
  212. }
  213. ReferencePool.Release(data.Value);
  214. }
  215. m_Datas.Clear();
  216. }
  217. m_CurrentState = null;
  218. m_CurrentStateTime = 0f;
  219. m_IsDestroyed = true;
  220. }
  221. /// <summary>
  222. /// 开始有限状态机。
  223. /// </summary>
  224. /// <typeparam name="TState">要开始的有限状态机状态类型。</typeparam>
  225. public void Start<TState>() where TState : FsmState<T>
  226. {
  227. if (IsRunning)
  228. {
  229. throw new GameFrameworkException("FSM is running, can not start again.");
  230. }
  231. FsmState<T> state = GetState<TState>();
  232. if (state == null)
  233. {
  234. throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), typeof(TState).FullName));
  235. }
  236. m_CurrentStateTime = 0f;
  237. m_CurrentState = state;
  238. m_CurrentState.OnEnter(this);
  239. }
  240. /// <summary>
  241. /// 开始有限状态机。
  242. /// </summary>
  243. /// <param name="stateType">要开始的有限状态机状态类型。</param>
  244. public void Start(Type stateType)
  245. {
  246. if (IsRunning)
  247. {
  248. throw new GameFrameworkException("FSM is running, can not start again.");
  249. }
  250. if (stateType == null)
  251. {
  252. throw new GameFrameworkException("State type is invalid.");
  253. }
  254. if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
  255. {
  256. throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
  257. }
  258. FsmState<T> state = GetState(stateType);
  259. if (state == null)
  260. {
  261. throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName));
  262. }
  263. m_CurrentStateTime = 0f;
  264. m_CurrentState = state;
  265. m_CurrentState.OnEnter(this);
  266. }
  267. /// <summary>
  268. /// 是否存在有限状态机状态。
  269. /// </summary>
  270. /// <typeparam name="TState">要检查的有限状态机状态类型。</typeparam>
  271. /// <returns>是否存在有限状态机状态。</returns>
  272. public bool HasState<TState>() where TState : FsmState<T>
  273. {
  274. return m_States.ContainsKey(typeof(TState));
  275. }
  276. /// <summary>
  277. /// 是否存在有限状态机状态。
  278. /// </summary>
  279. /// <param name="stateType">要检查的有限状态机状态类型。</param>
  280. /// <returns>是否存在有限状态机状态。</returns>
  281. public bool HasState(Type stateType)
  282. {
  283. if (stateType == null)
  284. {
  285. throw new GameFrameworkException("State type is invalid.");
  286. }
  287. if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
  288. {
  289. throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
  290. }
  291. return m_States.ContainsKey(stateType);
  292. }
  293. /// <summary>
  294. /// 获取有限状态机状态。
  295. /// </summary>
  296. /// <typeparam name="TState">要获取的有限状态机状态类型。</typeparam>
  297. /// <returns>要获取的有限状态机状态。</returns>
  298. public TState GetState<TState>() where TState : FsmState<T>
  299. {
  300. FsmState<T> state = null;
  301. if (m_States.TryGetValue(typeof(TState), out state))
  302. {
  303. return (TState)state;
  304. }
  305. return null;
  306. }
  307. /// <summary>
  308. /// 获取有限状态机状态。
  309. /// </summary>
  310. /// <param name="stateType">要获取的有限状态机状态类型。</param>
  311. /// <returns>要获取的有限状态机状态。</returns>
  312. public FsmState<T> GetState(Type stateType)
  313. {
  314. if (stateType == null)
  315. {
  316. throw new GameFrameworkException("State type is invalid.");
  317. }
  318. if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
  319. {
  320. throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName));
  321. }
  322. FsmState<T> state = null;
  323. if (m_States.TryGetValue(stateType, out state))
  324. {
  325. return state;
  326. }
  327. return null;
  328. }
  329. /// <summary>
  330. /// 获取有限状态机的所有状态。
  331. /// </summary>
  332. /// <returns>有限状态机的所有状态。</returns>
  333. public FsmState<T>[] GetAllStates()
  334. {
  335. int index = 0;
  336. FsmState<T>[] results = new FsmState<T>[m_States.Count];
  337. foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
  338. {
  339. results[index++] = state.Value;
  340. }
  341. return results;
  342. }
  343. /// <summary>
  344. /// 获取有限状态机的所有状态。
  345. /// </summary>
  346. /// <param name="results">有限状态机的所有状态。</param>
  347. public void GetAllStates(List<FsmState<T>> results)
  348. {
  349. if (results == null)
  350. {
  351. throw new GameFrameworkException("Results is invalid.");
  352. }
  353. results.Clear();
  354. foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
  355. {
  356. results.Add(state.Value);
  357. }
  358. }
  359. /// <summary>
  360. /// 是否存在有限状态机数据。
  361. /// </summary>
  362. /// <param name="name">有限状态机数据名称。</param>
  363. /// <returns>有限状态机数据是否存在。</returns>
  364. public bool HasData(string name)
  365. {
  366. if (string.IsNullOrEmpty(name))
  367. {
  368. throw new GameFrameworkException("Data name is invalid.");
  369. }
  370. if (m_Datas == null)
  371. {
  372. return false;
  373. }
  374. return m_Datas.ContainsKey(name);
  375. }
  376. /// <summary>
  377. /// 获取有限状态机数据。
  378. /// </summary>
  379. /// <typeparam name="TData">要获取的有限状态机数据的类型。</typeparam>
  380. /// <param name="name">有限状态机数据名称。</param>
  381. /// <returns>要获取的有限状态机数据。</returns>
  382. public TData GetData<TData>(string name) where TData : Variable
  383. {
  384. return (TData)GetData(name);
  385. }
  386. /// <summary>
  387. /// 获取有限状态机数据。
  388. /// </summary>
  389. /// <param name="name">有限状态机数据名称。</param>
  390. /// <returns>要获取的有限状态机数据。</returns>
  391. public Variable GetData(string name)
  392. {
  393. if (string.IsNullOrEmpty(name))
  394. {
  395. throw new GameFrameworkException("Data name is invalid.");
  396. }
  397. if (m_Datas == null)
  398. {
  399. return null;
  400. }
  401. Variable data = null;
  402. if (m_Datas.TryGetValue(name, out data))
  403. {
  404. return data;
  405. }
  406. return null;
  407. }
  408. /// <summary>
  409. /// 设置有限状态机数据。
  410. /// </summary>
  411. /// <typeparam name="TData">要设置的有限状态机数据的类型。</typeparam>
  412. /// <param name="name">有限状态机数据名称。</param>
  413. /// <param name="data">要设置的有限状态机数据。</param>
  414. public void SetData<TData>(string name, TData data) where TData : Variable
  415. {
  416. SetData(name, (Variable)data);
  417. }
  418. /// <summary>
  419. /// 设置有限状态机数据。
  420. /// </summary>
  421. /// <param name="name">有限状态机数据名称。</param>
  422. /// <param name="data">要设置的有限状态机数据。</param>
  423. public void SetData(string name, Variable data)
  424. {
  425. if (string.IsNullOrEmpty(name))
  426. {
  427. throw new GameFrameworkException("Data name is invalid.");
  428. }
  429. if (m_Datas == null)
  430. {
  431. m_Datas = new Dictionary<string, Variable>(StringComparer.Ordinal);
  432. }
  433. Variable oldData = GetData(name);
  434. if (oldData != null)
  435. {
  436. ReferencePool.Release(oldData);
  437. }
  438. m_Datas[name] = data;
  439. }
  440. /// <summary>
  441. /// 移除有限状态机数据。
  442. /// </summary>
  443. /// <param name="name">有限状态机数据名称。</param>
  444. /// <returns>是否移除有限状态机数据成功。</returns>
  445. public bool RemoveData(string name)
  446. {
  447. if (string.IsNullOrEmpty(name))
  448. {
  449. throw new GameFrameworkException("Data name is invalid.");
  450. }
  451. if (m_Datas == null)
  452. {
  453. return false;
  454. }
  455. Variable oldData = GetData(name);
  456. if (oldData != null)
  457. {
  458. ReferencePool.Release(oldData);
  459. }
  460. return m_Datas.Remove(name);
  461. }
  462. /// <summary>
  463. /// 有限状态机轮询。
  464. /// </summary>
  465. /// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
  466. /// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
  467. internal override void Update(float elapseSeconds, float realElapseSeconds)
  468. {
  469. if (m_CurrentState == null)
  470. {
  471. return;
  472. }
  473. m_CurrentStateTime += elapseSeconds;
  474. m_CurrentState.OnUpdate(this, elapseSeconds, realElapseSeconds);
  475. }
  476. /// <summary>
  477. /// 关闭并清理有限状态机。
  478. /// </summary>
  479. internal override void Shutdown()
  480. {
  481. ReferencePool.Release(this);
  482. }
  483. /// <summary>
  484. /// 切换当前有限状态机状态。
  485. /// </summary>
  486. /// <typeparam name="TState">要切换到的有限状态机状态类型。</typeparam>
  487. internal void ChangeState<TState>() where TState : FsmState<T>
  488. {
  489. ChangeState(typeof(TState));
  490. }
  491. /// <summary>
  492. /// 切换当前有限状态机状态。
  493. /// </summary>
  494. /// <param name="stateType">要切换到的有限状态机状态类型。</param>
  495. internal void ChangeState(Type stateType)
  496. {
  497. if (m_CurrentState == null)
  498. {
  499. throw new GameFrameworkException("Current state is invalid.");
  500. }
  501. FsmState<T> state = GetState(stateType);
  502. if (state == null)
  503. {
  504. throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not change state to '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName));
  505. }
  506. m_CurrentState.OnLeave(this, false);
  507. m_CurrentStateTime = 0f;
  508. m_CurrentState = state;
  509. m_CurrentState.OnEnter(this);
  510. }
  511. }
  512. }