[FreedomAI]第一周——FSM

FSM是用的非常成熟的技术,不过我们在算法框架上加入了自己的理解。

一是加上概率机制。

  将FSM进化成概率FSM,是自由度的第一步体现。不在是固定会在某个节点变到另一个节点,而是在某一个区间都有可能发生变化。

二是加上反馈机制。

  由于是基于概率的,每一条节点连线都可以附上权值,比如权值是3,就相当于这个转化的概率大3倍,这样我们就可以加入反馈一样的学习机制,首先我们认为节点的转化是有一个目标的,比如Idle->RunToPlayer,这个转化的目标就是要接近Player,我们的目标函数就是检测是否有更接近这个Player,于是在发生转化的10帧内,我们都进行目标函数的检测,统计最终的总收益,如果转化的目标有更加达成的趋势,节点联系增强,反之减弱。

三是加上情绪机制。

  在节点的转化过程中,我们又考虑了,AI的情绪,首先AI的情绪有这FSM类似一套的转化机制,然后转化节点的具体概率计算,可以随时引入AI情绪的变量,(也可以不引),看需求,比如一个AI被设定成愤怒是更容易攻击玩家,这个情绪机制就很方便了。

四是引入了委托使得工程更加便利。

  以前写FSM,很大程度上要写很多的switch-case,不仅代码很长,而且很不好改,我们引入了委托,把节点函数做为了一个数据,向图中的节点一样,新写了一个就动态的忘里插入就可以了。

代码:

public delegate void StateEnter(AIEntity pEntity);

	public delegate void StateExit(AIEntity pEntity);

	public delegate void StateExecuter(AIEntity pEntity);

	public delegate float StateTranfer(AIEntity pEntity);

	public delegate float StateFeedbacker(AIEntity pEntity);

	public delegate void StateRecorder(AIEntity pEntity);

	public delegate void AnimationPlay(Animator pAnimator);

	public delegate float EmotionExecuter(AIEntity pEntity);

	public struct TranferNode
	{
		public StateTranfer mTranfer;
		public int id;
	}

	public struct FeedbackerNode
	{
		public StateFeedbacker mFeedbacker;
		public int id;
	}

	public struct PowerNode
	{
		public float power;
		public int id;
	}

	public class EmptyTranfer
	{
		public static float Run(AIEntity pEntity)
		{
			return 0.0f;
		}
	}

	public class EmptyExitAndEnter
	{
		public static void EmptyExit(AIEntity pEntity)
		{
			
		}

		public static void EmptyEnter(AIEntity pEntity)
		{
			
		}

	}

	public class AIStateRecord
	{
		public void Run(AIEntity pEntity)
		{
			pEntity.GetComponent<AIState> ().LastEntityData.GetComponent<AIMove> ().mDirection = pEntity.GetComponent<AIMove> ().mDirection;
			pEntity.GetComponent<AIState> ().LastEntityData.GetComponent<AIMove> ().mVelocity = pEntity.GetComponent<AIMove> ().mVelocity;
			pEntity.GetComponent<AIState> ().LastEntityData.GetComponent<AIMove> ().mMoveFunc = pEntity.GetComponent<AIMove> ().mMoveFunc;
			pEntity.GetComponent<AIState> ().LastEntityData.AIPos = pEntity.AIPos;
			pEntity.GetComponent<AIState> ().LastEntityData.PlayerPos = pEntity.PlayerPos;
			pEntity.GetComponent<AIState> ().LastEntityData.GetComponent<AIAnimation> ().tempAnim = pEntity.GetComponent<AIAnimation> ().tempAnim;
		}
	}

	public class AIState:UComponent
	{
		public StateExecuter[] mExecuter;
		public StateExit[] mExiter;
		public StateEnter[] mEnterer;
		public List<TranferNode>[] mTranfer;
		public List<FeedbackerNode>[] mFeedbacker;
		public List<PowerNode>[] mPowerEdge;
		public UEntity LastPlayerEntity;
		public AIEntity LastEntityData;
		public Dictionary<int,string> mStateAnimation;
		//public List<UComponent> LastComponent;
		public int mMaxCount = 25;
		public int mtempCount = 0;
		public int tempID = 0;
		public int mCaptureFrame = 0;
		public bool mFeedbackerState = false;
		public float[] mframebuffer = new float[10];
		public StateFeedbacker mTempFeedbacker;
		public int mid_fir, mid_sec;
		public uint IAnyway;
		public StateRecorder mStateRecorder;

		public override void Init ()
		{
			mStateAnimation = new Dictionary<int, string> ();

			mExiter = new StateExit[25];

			mEnterer = new StateEnter[25];

			mExecuter = new StateExecuter[25];

			mTranfer = new List<TranferNode>[25];
			for (int i = 0; i < 25; i++) 
			{
				mTranfer [i] = new List<TranferNode> ();
			}

			mFeedbacker = new List<FeedbackerNode>[25];
			for (int i = 0; i < 25; i++)
			{
				mFeedbacker [i] = new List<FeedbackerNode> ();
			}

			mPowerEdge = new List<PowerNode>[25];
			for (int i = 0; i < 25; i++) 
			{
				mPowerEdge [i] = new List<PowerNode> ();
			}

			LastPlayerEntity = new UEntity ();

			LastEntityData = new AIEntity ();
			LastEntityData.PlayerEntity = LastPlayerEntity;
			LastEntityData.mWorld = this.mUEntity.mWorld;
			IAnyway = (uint)mtempCount;
			mtempCount++;
		}

		public bool AddAnimation(StateExecuter pExecuter,string pName)
		{
			int index = -1;
			for (int i = 0; i < mtempCount; i++)
			{
				if (mExecuter [i] == pExecuter)
				{
					index = i;
					break;
				}
			}
			if (index != -1) 
			{
				mStateAnimation.Add (index,pName);
				return true;
			}
			else
			{
				return false;
			}
		}

		public int AddExecuter(StateExecuter pExecuter,StateExit pExit,StateEnter pEnter)
		{
			mExecuter [mtempCount] = pExecuter;
			mExiter [mtempCount] = pExit;
			mEnterer [mtempCount] = pEnter;
			mtempCount++;
			return mtempCount-1;
		}

		public void AddEdge(StateTranfer pTranfer,StateFeedbacker pFeedbacker,int id1,int id2)
		{
			TranferNode tn = new TranferNode ();
			tn.id = id2;
			tn.mTranfer = pTranfer;

			FeedbackerNode fn = new FeedbackerNode ();
			fn.id = id2;
			fn.mFeedbacker = pFeedbacker;

			PowerNode pn = new PowerNode ();
			pn.id = id2;
			pn.power = 1.0f;

			mTranfer [id1].Add (tn);
			mFeedbacker [id1].Add (fn);
			mPowerEdge [id1].Add (pn);
		}

		public void AddEdge(StateTranfer pTranfer,StateFeedbacker pFeedbacker,StateExecuter exe1,StateExecuter exe2)
		{
			int id1 = -1;
			int id2 = -1;
			for (int i = 0; i < 25; i++) 
			{
				if (mExecuter [i] == exe1) 
				{
					id1 = i;
				}
				if (mExecuter [i] == exe2)
				{
					id2 = i;
				}
				if (id1 != -1 && id2 != -1) 
				{
					AddEdge (pTranfer,pFeedbacker,id1,id2);
					break;
				}
			}
		}

		public void AddAnywayTranfer(StateTranfer pStateTranfer,StateFeedbacker pFeedbacker,int id)
		{
			AddEdge (pStateTranfer,pFeedbacker,0,id);
		}

	}

	public class StateControlSystem:USystem
	{
		
		public override void Init ()
		{
			this.AddRequestComponent (typeof(AIState));
			this.AddRequestComponent (typeof(AIAnimation));
		}

		public override void Update (UEntity uEntity)
		{
		//	Debug.Log (uEntity.GetComponent<AIState>().mStateAnimation[uEntity.GetComponent<AIState>().tempID]);
			//Debug.Log(uEntity.GetComponent<AIState>().mStateAnimation[uEntity.GetComponent<AIState>().tempID]+" "+uEntity.GetComponent<AIEmotion>().GetTempEmotion());
			uEntity.GetComponent<AIState> ().mExecuter [uEntity.GetComponent<AIState> ().tempID]((AIEntity)uEntity);

			((AIEntity)uEntity).AIPos = ((AIEntity)uEntity).GetComponent<BaseAIComponent> ().mAIRT.transform.position; 
			((AIEntity)uEntity).PlayerPos = ((AIEntity)uEntity).mPlayer.transform.position; 

			string tName = uEntity.GetComponent<AIState> ().mStateAnimation [uEntity.GetComponent<AIState> ().tempID];
			uEntity.GetComponent<AIAnimation> ().tempAnim = tName;

			for (int i = 0; i < uEntity.GetComponent<AIState> ().mTranfer[0].Count; i++)
			{
				if (uEntity.GetComponent<AIState> ().mTranfer [0] [i].id == uEntity.GetComponent<AIState> ().tempID) 
				{
					continue;
				}

				float tRate = uEntity.GetComponent<AIState> ().mTranfer [0] [i].mTranfer(((AIEntity)uEntity));
				float tPower = uEntity.GetComponent<AIState> ().mPowerEdge [0] [i].power;

				bool returning = false;
				if (tRate * tPower > 0.04f*Time.deltaTime) 
				{
					if (Random.Range (0.0f, 1.0f) <= tRate * tPower) 
					{
					//	Debug.Log (tRate+"  "+tPower+"any");
						uEntity.GetComponent<AIState> ().mTempFeedbacker = uEntity.GetComponent<AIState> ().mFeedbacker [0] [i].mFeedbacker;
						if (uEntity.GetComponent<AIState> ().mCaptureFrame > 0) 
						{
							float sum = 0.0f;
							for (int j = 0; j < 10-uEntity.GetComponent<AIState> ().mCaptureFrame; j++) 
							{
								sum += uEntity.GetComponent<AIState> ().mframebuffer [j];
							}
							sum /= 10.0f-uEntity.GetComponent<AIState> ().mCaptureFrame;
							for (int j = 0; j < uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir].Count; j++) 
							{
								if (uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j].id == uEntity.GetComponent<AIState> ().mid_sec)
								{
									PowerNode tpn = new PowerNode ();
									tpn.id = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j].id;
									tpn.power = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j].power + sum;
									if (tpn.power > 3.0f)
										tpn.power = 3.0f;
									if (tpn.power < 0.3f)
										tpn.power = 0.3f;
									uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j] = tpn;
									break;
								}
							}
						}
						uEntity.GetComponent<AIState> ().mCaptureFrame = 10;
						uEntity.GetComponent<AIState> ().mid_fir = 0;
						uEntity.GetComponent<AIState> ().mid_sec = uEntity.GetComponent<AIState> ().mTranfer [0] [i].id;
						uEntity.GetComponent<AIState> ().mExiter [uEntity.GetComponent<AIState> ().tempID] ((AIEntity)uEntity);
						uEntity.GetComponent<AIState> ().tempID = uEntity.GetComponent<AIState> ().mTranfer [0] [i].id;
						uEntity.GetComponent<AIState> ().mEnterer [uEntity.GetComponent<AIState> ().tempID] ((AIEntity)uEntity);
						returning = true;
					}
				}

				if (returning)
				{
					return;
				}
			}

			for (int i = 0; i < uEntity.GetComponent<AIState> ().mTranfer [uEntity.GetComponent<AIState> ().tempID].Count; i++) 
			{
				float tRate = uEntity.GetComponent<AIState> ().mTranfer [uEntity.GetComponent<AIState> ().tempID] [i].mTranfer(((AIEntity)uEntity));
				float tPower = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().tempID] [i].power;
				bool breaking = false;
				if (tRate * tPower > 0.04f*Time.deltaTime)
				{
					if (Random.Range (0.0f, 1.0f) <= tRate * tPower) 
					{
						uEntity.GetComponent<AIState> ().mTempFeedbacker = uEntity.GetComponent<AIState> ().mFeedbacker [uEntity.GetComponent<AIState> ().tempID] [i].mFeedbacker;
						if (uEntity.GetComponent<AIState> ().mCaptureFrame > 0) 
						{
							float sum = 0.0f;
							for (int j = 0; j < 10-uEntity.GetComponent<AIState> ().mCaptureFrame; j++) 
							{
								sum += uEntity.GetComponent<AIState> ().mframebuffer [j];
							}
							sum /= 10.0f-uEntity.GetComponent<AIState> ().mCaptureFrame;
							for (int j = 0; j < uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir].Count; j++) 
							{
								if (uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j].id == uEntity.GetComponent<AIState> ().mid_sec)
								{
									PowerNode tpn = new PowerNode ();
									tpn.id = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j].id;
									tpn.power = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j].power + sum;
									if (tpn.power > 3.0f)
										tpn.power = 3.0f;
									if (tpn.power < 0.3f)
										tpn.power = 0.3f;
									uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [j] = tpn;
									break;
								}
							}
						}
						uEntity.GetComponent<AIState> ().mCaptureFrame = 10;
						uEntity.GetComponent<AIState> ().mid_fir = uEntity.GetComponent<AIState> ().tempID;
						uEntity.GetComponent<AIState> ().mid_sec = uEntity.GetComponent<AIState> ().mTranfer [uEntity.GetComponent<AIState> ().tempID] [i].id;
						uEntity.GetComponent<AIState> ().mExiter [uEntity.GetComponent<AIState> ().tempID] ((AIEntity)uEntity);
						uEntity.GetComponent<AIState> ().tempID = uEntity.GetComponent<AIState> ().mTranfer [uEntity.GetComponent<AIState> ().tempID] [i].id;
						uEntity.GetComponent<AIState> ().mEnterer [uEntity.GetComponent<AIState> ().tempID] ((AIEntity)uEntity);
						breaking = true;
					}
				}
				if (breaking)
				{
					break;
				}
			}

		}
			
	}

	public class FrameCaptureSystem:USystem
	{
		public override void Init ()
		{
			this.AddRequestComponent (typeof(AIState));
		}

		public override void Update (UEntity uEntity)
		{
			if (uEntity.GetComponent<AIState> ().mCaptureFrame != 0) 
			{
				int tIndex = uEntity.GetComponent<AIState> ().mCaptureFrame-1;
				float tLast = uEntity.GetComponent<AIState> ().mTempFeedbacker ((AIEntity)uEntity.GetComponent<AIState>().LastEntityData);
				float tNow = uEntity.GetComponent<AIState> ().mTempFeedbacker ((AIEntity)uEntity);
				uEntity.GetComponent<AIState> ().mframebuffer [tIndex] = Mathf.Abs(tLast)-Mathf.Abs(tNow);
				uEntity.GetComponent<AIState> ().mCaptureFrame--;
				if (uEntity.GetComponent<AIState> ().mCaptureFrame == 0) 
				{
					uEntity.GetComponent<AIState> ().mFeedbackerState = true;
				}
			}
		}

	}

	public class FrameStatistics:USystem
	{
		public override void Init ()
		{
			this.AddRequestComponent (typeof(AIState));
		}

		public override void Update (UEntity uEntity)
		{
			if (uEntity.GetComponent<AIState> ().mFeedbackerState)
			{
				float sum = 0.0f;
				for (int i = 0; i < 10; i++) 
				{
					sum += uEntity.GetComponent<AIState> ().mframebuffer [i];
				}
				sum /= 10.0f;
				for (int i = 0; i < uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir].Count; i++) 
				{
					if (uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [i].id == uEntity.GetComponent<AIState> ().mid_sec)
					{
						PowerNode tpn = new PowerNode ();
						tpn.id = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [i].id;
						tpn.power = uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [i].power + sum;
						if (tpn.power > 3.0f)
							tpn.power = 3.0f;
						if (tpn.power < 0.3f)
							tpn.power = 0.3f;
						uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [i] = tpn;
						//Debug.Log (uEntity.GetComponent<AIState> ().mid_fir+" "+uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [i].power+" "+uEntity.GetComponent<AIState> ().mPowerEdge [uEntity.GetComponent<AIState> ().mid_fir] [i].id);
						break;
					}
				}
	
				uEntity.GetComponent<AIState> ().mFeedbackerState = false;
			}
		}

	}


	public class StateRecordSystem:USystem
	{
		
		public override void Init ()
		{
			this.AddRequestComponent (typeof(AIState));
			power = 2000;
		}

		public override void Update (UEntity uEntity)
		{
			uEntity.GetComponent<AIState> ().mStateRecorder ((AIEntity)uEntity);
		}

	}

猜你喜欢

转载自blog.csdn.net/qq_33999892/article/details/79851441