[FreedomAI]第三週——InfluenceMap

勢力圖或影響圖被認爲是AI進行決策時獲取外界信息的一種良好方法。這些外界的信息可能包括,友方信息,敵方信息,地形及道具信息,這些東西我們如果讓每個AI都用GameObject.Find....Withtag 那麼可想而知,其複雜度就是N個AI*M個信息提供者。

但我們如果換個思路,在每一幀內這些物品信息都是固定(甚至有一些遊戲開始時就固定了),我們爲什麼不設置一張圖預處理這些信息呢?就像我們在圖形學中經常做的烘焙一樣?

所以影響圖就是這樣的一個算法。

首先我們會將這個地圖Grid化,先不妨認爲這是2D或2.5D的情況。然後每一個信息源都會計算一個值(把自己量化),然後有一個輻射半徑,對周圍的格子進行進行影響,格子上的值是不斷疊加的。

當然這些信息並不能使得AI就立刻發生什麼,準確的說,我們收集了這些信息,再進一步用於尋路和決策的邏輯纔有意義。

先上代碼:

public Vector2 center;
		public float width;
		public float height;
		public int wtileCount;
		public int htileCount;
		public float[][][] IMData;
		public int allCount = 0;
		public Dictionary<string,int> mDictionary = new Dictionary<string, int>();
		private static InfluenceMap mInfluenceMapsingleton;
		public Dictionary<int,bool> mDicStatic = new Dictionary<int, bool>();
		public bool Debugging;
		private Vector2[] NineGrid = new Vector2[]{new Vector2(0,1),new Vector2(0,-1),
			new Vector2(1,1),new Vector2(1,0),new Vector2(1,-1),
			new Vector2(-1,1),new Vector2(-1,0),new Vector2(-1,-1)};

		public Vector2 deltaTileSize
		{
			get
			{
				return new Vector2 (width/wtileCount,height/htileCount);
			}
		}

		public static InfluenceMap getInstance()
		{
			if (mInfluenceMapsingleton == null)
				mInfluenceMapsingleton = new InfluenceMap ();
			return mInfluenceMapsingleton;
		}

		public override void Init ()
		{
			base.Init ();
			IMData = new float[11][][];
			for (int i = 0; i < 11; i++) 
			{
				IMData[i] = new float[wtileCount][];
				for (int j = 0; j < wtileCount; j++)
				{
					IMData[i][j] = new float[htileCount];
					for (int k = 0; k < htileCount; k++) 
					{
						IMData [i] [j] [k] = 0.0f;
					}
				}
			}
			AddConverage (0.0f,"Collision",false);
		}

		public void AddConverage(float defaultValue,string name,bool isStatic)
		{
			if (allCount > 10)
				return;
			mDictionary.Add (name,allCount);
			mDicStatic.Add (allCount,isStatic);
			allCount++;
		}

		public Vector2 getTilefromPosition(Vector2 pcenter)
		{
			Vector2 pfir = center - new Vector2 (width/2,height/2);
			Vector2 delta = new Vector2 (width/wtileCount,height/htileCount);
			Vector2 size = new Vector2 ((pcenter-pfir).x/delta.x,(pcenter-pfir).y/delta.y);
			return size;
		}

這是InfluenceMap中的部分定義,可以看到最重要的屬性是IMData 這樣一個三維數組,爲什麼要設置3維數組,因爲我們可以設置多個圖層,比如0圖層存儲障礙信息,1圖層存儲友方信息,2圖層設置危險級信息,等等。

public class InfluenceMapTrigger:UComponent
	{
		public IMComputer mIMComputer;
		public float maxInfluence;
		public string mWhere;
		public GameObject mGameObject;

		public override void Init ()
		{
			base.Init ();
			string tWhere = mWhere;
			InfluenceMap tInfluenceMap = InfluenceMap.getInstance ();
			int index = tInfluenceMap.mDictionary [tWhere];
			bool isStatic = tInfluenceMap.mDicStatic [index];
			if (isStatic)
			{
				Vector3 position = mGameObject.transform.position;
				Vector2 center = new Vector2 (position.x,position.z);
				Vector2 tile = InfluenceMap.getInstance ().getTilefromPosition (center);
				float IMdata = mIMComputer (mUEntity);
				for (int i = (int)(tile.x - maxInfluence / 2); i <= (int)(tile.x + maxInfluence / 2); i++) 
				{
					for(int j = (int)(tile.y - maxInfluence / 2); j <= (int)(tile.y + maxInfluence / 2); j++)
					{
						i = Mathf.Clamp (i,0,InfluenceMap.getInstance().wtileCount-1);
						j = Mathf.Clamp (i,0,InfluenceMap.getInstance().htileCount-1);
						Vector2 v = new Vector2 ((i-tile.x)/maxInfluence,(j-tile.y)/maxInfluence);
						InfluenceMap.getInstance ().IMData [index] [i] [j] += IMdata * Gauss (v);
					}
				}
			}
		}

		private float Gauss(Vector2 v)
		{
			return Mathf.Exp(-(v.x*v.x/2.0f+v.y*v.y/2.0f));		
		}

	};

這裏是信息源的組件,可以看到,如果信息源填寫的影響圖層被認爲是Static的,可以在遊戲開始時處理它,之後的每幀都不做任何計算。

且我們使用高斯分佈的擴散方式。

public class InfluenceMapUpdateSystem:USystem
	{
		
		public override void Init ()
		{
			base.Init ();
			this.AddRequestComponent (typeof(InfluenceMapTrigger));
			power = 90;
		}	

		public override void Update (UEntity uEntity)
		{
			base.Update (uEntity);
			string tWhere = uEntity.GetComponent<InfluenceMapTrigger> ().mWhere;
			InfluenceMap tInfluenceMap = InfluenceMap.getInstance ();
			int index = tInfluenceMap.mDictionary [tWhere];
			bool isStatic = tInfluenceMap.mDicStatic [index];
			if (!isStatic)
			{
				Vector3 position = uEntity.GetComponent<InfluenceMapTrigger> ().mGameObject.transform.position;
				Vector2 center = new Vector2 (position.x,position.z);
				Vector2 tile = InfluenceMap.getInstance ().getTilefromPosition (center);
				float IMdata = uEntity.GetComponent<InfluenceMapTrigger> ().mIMComputer (uEntity);
				for (int i = (int)(tile.x - uEntity.GetComponent<InfluenceMapTrigger> ().maxInfluence / 2); i <= (int)(tile.x + uEntity.GetComponent<InfluenceMapTrigger> ().maxInfluence / 2); i++) 
				{
					for(int j = (int)(tile.y - uEntity.GetComponent<InfluenceMapTrigger> ().maxInfluence / 2); j <= (int)(tile.y + uEntity.GetComponent<InfluenceMapTrigger> ().maxInfluence / 2); j++)
					{
						i = Mathf.Clamp (i,0,InfluenceMap.getInstance().wtileCount-1);
						j = Mathf.Clamp (i,0,InfluenceMap.getInstance().htileCount-1);
						Vector2 v = new Vector2 ((i-tile.x)/uEntity.GetComponent<InfluenceMapTrigger>().maxInfluence,(j-tile.y)/uEntity.GetComponent<InfluenceMapTrigger>().maxInfluence);
						InfluenceMap.getInstance ().IMData [index] [i] [j] += IMdata * Gauss (v);
					}
				}
			}
		}

		private float Gauss(Vector2 v)
		{
			return Mathf.Exp(-(v.x*v.x/2.0f+v.y*v.y/2.0f));		
		}

	};

	public class InfluenceMapFlushSystem:USystem
	{
		public override void Init ()
		{
			base.Init ();
			this.AddRequestComponent (typeof(InfluenceMap));
			power = 89;
		}

		public override void Update (UEntity uEntity)
		{
			base.Update (uEntity);
			for (int i = 0; i < uEntity.GetComponent<InfluenceMap> ().allCount; i++)
			{
				if (!uEntity.GetComponent<InfluenceMap> ().mDicStatic [i]) 
				{
					for (int j = 0; j < uEntity.GetComponent<InfluenceMap> ().wtileCount; j++) 
					{
						for (int k = 0; k < uEntity.GetComponent<InfluenceMap> ().htileCount; k++) 
						{
							uEntity.GetComponent<InfluenceMap> ().IMData [i] [j] [k] = 0.0f;
						}
					}
				}
			}
		}

	};


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章