//--------------------------------------------------
// Motion Framework
// Copyright©2018-2020 何冠峰
// Licensed under the MIT license
//--------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
namespace MotionFramework.AI
{
///
/// 有限状态机
///
public class FiniteStateMachine
{
private readonly List _nodes = new List();
private IFsmNode _curNode;
private IFsmNode _preNode;
///
/// 节点转换关系图
/// 注意:如果为NULL则不检测转换关系
///
public FsmGraph Graph;
///
/// 当前运行的节点名称
///
public string CurrentNodeName
{
get { return _curNode != null ? _curNode.Name : string.Empty; }
}
///
/// 之前运行的节点名称
///
public string PreviousNodeName
{
get { return _preNode != null ? _preNode.Name : string.Empty; }
}
///
/// 启动状态机
///
/// 入口节点
public void Run(string entryNode)
{
_curNode = GetNode(entryNode);
_preNode = GetNode(entryNode);
if (_curNode != null)
_curNode.OnEnter();
else
MotionLog.Error($"Not found entry node : {entryNode}");
}
///
/// 显示帧更新
///
public void Update()
{
if (_curNode != null)
_curNode.OnUpdate();
}
///
/// 物理帧更新
///
public void FixedUpdate()
{
if (_curNode != null)
_curNode.OnFixedUpdate();
}
///
/// 加入一个节点
///
public void AddNode(IFsmNode node)
{
if (node == null)
throw new ArgumentNullException();
if (_nodes.Contains(node) == false)
{
_nodes.Add(node);
}
else
{
MotionLog.Warning($"Node {node.Name} already existed");
}
}
///
/// 转换节点
///
public void Transition(string nodeName)
{
if (string.IsNullOrEmpty(nodeName))
throw new ArgumentNullException();
IFsmNode node = GetNode(nodeName);
if (node == null)
{
MotionLog.Error($"Can not found node {nodeName}");
return;
}
// 检测转换关系
if (Graph != null)
{
if (Graph.CanTransition(_curNode.Name, node.Name) == false)
{
MotionLog.Error($"Can not transition {_curNode} to {node}");
return;
}
}
MotionLog.Log($"FSM transition {_curNode.Name} to {node.Name}");
_preNode = _curNode;
_curNode.OnExit();
_curNode = node;
_curNode.OnEnter();
}
///
/// 返回到之前的节点
///
public void RevertToPreviousNode()
{
Transition(PreviousNodeName);
}
///
/// 接收消息
///
public void HandleMessage(object msg)
{
if (_curNode != null)
_curNode.OnHandleMessage(msg);
}
private bool IsContains(string nodeName)
{
for (int i = 0; i < _nodes.Count; i++)
{
if (_nodes[i].Name == nodeName)
return true;
}
return false;
}
private IFsmNode GetNode(string nodeName)
{
for (int i = 0; i < _nodes.Count; i++)
{
if (_nodes[i].Name == nodeName)
return _nodes[i];
}
return null;
}
}
}