[FreedomAI] Week 1 - FSM

FSM is a very mature technology, but we have added our own understanding to the algorithm framework.

One is to add probability mechanism.

  Evolving FSM into a probabilistic FSM is the first manifestation of degrees of freedom. It is not fixed that it will change from one node to another, but it may change in a certain interval.

The second is to add a feedback mechanism.

  Since it is based on probability, each node connection can be attached with a weight. For example, if the weight is 3, it is equivalent to 3 times the probability of this transformation. In this way, we can add a learning mechanism like feedback. First of all, we think that the node The transformation has a goal, such as Idle->RunToPlayer. The goal of this transformation is to be close to the Player. Our objective function is to detect whether there is a closer to the Player, so within 10 frames of the transformation, we all perform the objective function The detection and statistics of the final total revenue, if the conversion goal has a tendency to be more achieved, the node connection will be strengthened, otherwise it will be weakened.

The third is to add emotional mechanism.

  In the process of node transformation, we also considered the emotion of AI. First, the emotion of AI has a transformation mechanism similar to that of FSM, and then the specific probability calculation of the node is transformed. The variable of AI emotion can be introduced at any time (or not citation), depending on the needs, for example, if an AI is set to be angry, it is easier to attack the player, and this emotional mechanism is very convenient.

Fourth, the introduction of entrustment makes the project more convenient.

  In the past, when writing FSM, it was necessary to write a lot of switch-cases to a large extent. Not only the code was very long, but also it was difficult to change. We introduced delegates and used the node function as a data, just like the nodes in the graph, and newly written A dynamic forget to insert on it.

Code:

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;
			mEnter [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);
		}

	}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325802266&siteId=291194637