在寫之前,必須對 前一篇文檔補充一下。
Camera2DAngle類是 攝像機旋轉 2d人物360度,PlayerMove是人物移動。
這兩個類 都可以 360 ° 場景旋轉人物也跟着旋轉。
但不能同時用。 前者更傾向於 不移動的 人物。后者傾向於 移動的人物。 但精度 前者 高於 后者。具體根據項目需求 選擇。
今天 介紹的類 CollisionDetection 碰撞檢測類
public GameObject GridPrefab;//網格塊材料 public int RangeLength;//網格塊范圍 public bool showGrid;//是否顯示
第一個參數,是網格的圖形,你可以用 任何模型 作為一個網格的形狀。當然這不是必須要顯示的
第二個參數,取值為0--max,當0的時候,就是九宮格,1的時候是 25宮格,2的時候49宮格,3的時候81宮格,規律是 (2n+1)(2n+1);
第三個參數,是否顯示,如果不選,則第一個參數 不需要填寫。
下面我們來看看效果
說明下,添加位置和disk相同。我用cube作為網格形狀,我選擇的范圍是0和1,也就是9和25宮格,我讓他顯示,當然,最好建議不要選擇顯示,這樣會影響效率。
這張是我旋轉之后的圖,看的出人物方向還是面對面過來的。
有人問,為何范圍一定要 9,25,49,81這類的。其實 大家仔細想下就知道,我要讓 人物 永遠保證在中心點,那么 奇數 *奇數才能確保這樣。
網格計算是協程方式,測試在2000左右手機下,同屏顯示 300人 走動碰撞檢測保證在35幀以上。低端手機 也能滿足同屏 100+人 不卡。
下一篇,AI。
鏈接:http://pan.baidu.com/s/1G5DAA 密碼:v2kl
最優網格四叉法代碼
前一陣子,我想想,其實給一點代碼也沒什么,所以就放一部分 代碼大家看看。
這個是 其原理圖,我自己畫的,畫工一般。概念就是 人物在填充里面 是 只檢測 綠色填充,而走到紅藍線 開始檢測不同 的臨界區。
同時,為了記錄和檢索不要那么頻繁,也優化過了。
檢測精度非常高,比如人物在2 這個點,圖上有,那么他檢測的 首先是 0,然后是 2的對角。然后2的兩邊。
如果人物在0 那么他只檢測0;同時還有方向的約束,可以優先檢索順序。
測試下來,比觸發碰撞 效率高2倍。如果做游戲,優化最大,幾乎達到 一半的 無碰撞性能。
using UnityEngine; using System.Collections; using UnityEngine.UI; public class ceshi : MonoBehaviour { float widths, heights; public float x1; public float x2; public float y1; public float y2; private int w; private int h; public bool stop; void Start() { } void OnEnable() { stop = true; Vector2 v = Camera.main.WorldToScreenPoint(this.transform.position); widths = Screen.width / 6; heights = Screen.height / 6; w = (int)(v.x / widths); h = (int)(v.y / heights); //初始化 人物 坐標 對應的 網格 位置,並保存到 網格內 OnInstet(w, h); } //插入數據 void OnInstet(int w, int h) { Vector2 VectorGrid = new Vector2(w, h); ArrayList arrlist = GameModel.getInstance().GridList[VectorGrid]; if (!arrlist.Contains(transform.name)) { GameModel.getInstance().GridList[VectorGrid].Add(transform.name); } else { int Indexs = GameModel.getInstance().GridList[VectorGrid].IndexOf(transform.name); GameModel.getInstance().GridList[VectorGrid].RemoveAt(Indexs); } } bool sortGird(int w, int h) { ArrayList arr = new ArrayList(); if (w < 0) { w = 0; } if (h < 0) { h = 0; } if (w > 5) { w = 5; } if (h > 5) { h = 5; } Vector2 VectorGrid = new Vector2(w, h); arr = GameModel.getInstance().GridList[VectorGrid]; if (OnSetArmy(arr)) { return true; } return false; } bool OnSetArmy(ArrayList arr) { if (arr.Count > 0) { for (int i = 0; i < arr.Count; i++) { if (arr[i] != this.transform.name)//如果不是自己 { stop = false;//停止檢測 return true; } } } return false; } //查詢數據 void OnFindData(int vector) { //根據人物 角度 選擇 從 哪個開始 switch (vector) { case 0: //中間 sortGird(w, h); break; case 1: //左上 if (sortGird(w, h))//自己 { break; } if (sortGird(w - 1, h + 1)) { break; }//左上對角 if (sortGird(w - 1, h)) { break; }//左 if (sortGird(w, h + 1)) { break; }//上 //找出一個 就跳轉 break; case 2: //右上 if (sortGird(w, h)) { break; }//自己 if (sortGird(w + 1, h + 1)) { break; }//右上對角 if (sortGird(w + 1, h)) { break; }//右 if (sortGird(w, h + 1)) { break; }//上 break; case 3: //左下 if (sortGird(w, h)) { break; }//自己 if (sortGird(w - 1, h - 1)) { break; }//左下對角 if (sortGird(w - 1, h)) { break; }//左 if (sortGird(w, h - 1)) { break; }//下 break; case 4: //右下 if (sortGird(w, h)) { break; }//自己 if (sortGird(w + 1, h - 1)) { break; }//右下對角 if (sortGird(w - 1, h)) { break; }//右 if (sortGird(w, h - 1)) { break; }//下 break; case 5: //上 if (sortGird(w, h)) { break; }//自己 if (sortGird(w, h + 1)) { break; }//上 break; case 6: //右 if (sortGird(w, h)) { break; }//自己 if (sortGird(w + 1, h)) { break; }//右 break; case 7: //下 if (sortGird(w, h)) { break; }//自己 if (sortGird(w, h - 1)) { break; }//下 break; case 8: //左 if (sortGird(w, h)) { break; }//自己 if (sortGird(w - 1, h)) { break; }//左 break; default: break; } } private bool top; private bool bottom; private bool left; private bool right; //判斷是否在臨界點 void OnRectPostion(bool tops = true, bool bottoms = true, bool lefts = true, bool rights = true) { top = tops; bottom = bottoms; left = lefts; right = rights; } //存儲網格數據 void Storage() { Vector2 v = Camera.main.WorldToScreenPoint(this.transform.position); int w_new = (int)(v.x / widths); int h_new = (int)(v.y / heights); int ww = w, hh = h; if (w_new != w) { if (w_new < w) { int w1 = (int)(v.x) % (int)(widths); if (w1 < x2) { //進入了下一個格子 存儲數據 OnRectPostion();//判斷是否在臨界點 ww = w_new; // print("111"); } else { //偏左 進入臨界點 left = false; } } else { int w1 = (int)(v.x) % (int)(widths); if (w1 > x1) { //進入了下一個格子 OnRectPostion(); ww = w_new; // print("222"); } else { // 偏右 進入臨界點 right = false; } } } ///////////////////////////////////////////////////////////// if (h_new != h) { if (h_new < h) { int h1 = (int)(v.y) % (int)(heights); if (h1 < y2) { //進入了下一個格子 OnRectPostion(); hh = h_new; // print("333"); } else { //偏上 進入臨界點 top = false; } } else { int h1 = (int)(v.y) % (int)(heights); if (h1 > y1) { //進入了下一個格子 OnRectPostion(); hh = h_new; // print("444"); } else { //偏下 進入臨界點 bottom = false; } } } /////////////// OnInstet(w, h);//刪除老數據 OnInstet(ww, hh);//添加新數據 w = ww; h = hh; //換新 } //查詢人物網格內的碰撞 void FindGrid() { //如果在上面 if (!top) { if (!left)//左上 { OnFindData(1); } else if (!right)//右上 { OnFindData(2); } else { //上 OnFindData(5); } return; } //如果在下面 if (!bottom) { if (!left)//左下 { OnFindData(3); } else if (!right)//右下 { OnFindData(4); } else { //下 OnFindData(7); } return; } //如果在左邊 if (!left) { if (!top)//左上 { OnFindData(1); } else if (!bottom)//左下 { OnFindData(3); } else //左邊 { OnFindData(8); } return; } //如果在右邊 if (!right) { if (!top)//右上 { OnFindData(2); } else if (!bottom)//右下 { OnFindData(4); } else //右邊 { OnFindData(6); } return; } //不在臨界點 if (top && bottom && left && right) { OnFindData(0); } } void Update() { //存儲坐標 和 找出臨界點 Storage(); /////////////////////////// //判斷臨界點 的位置,找出 需要 檢索的 格子。 if (stop) { FindGrid(); } } }