// Recursively build a tree by separating points at plane boundaries. static KDTreeFree MakeFromPointsInner( int depth, int stIndex, int enIndex, Vector3[] points, int[] inds ) { KDTreeFree root = new KDTreeFree(); root.axis = depth % numDims; int splitPoint = FindPivotIndex(points, inds, stIndex, enIndex, root.axis); root.pivotIndex = inds[splitPoint]; root.pivot = points[root.pivotIndex]; int leftEndIndex = splitPoint - 1; if (leftEndIndex >= stIndex) { root.lr[0] = MakeFromPointsInner(depth + 1, stIndex, leftEndIndex, points, inds); } int rightStartIndex = splitPoint + 1; if (rightStartIndex <= enIndex) { root.lr[1] = MakeFromPointsInner(depth + 1, rightStartIndex, enIndex, points, inds); } return(root); }
// The main coroutine, which starts to search for nearest enemies neighbours and set them for attack // NN search works with kdtree.cs NN search class, implemented by A. Stark at 2009. // Target candidates are put on kdtree, while attackers used to search for them. // NN searches are based on position coordinates in 3D. public IEnumerator SearchPhase() { float timeBegin, timeEnd; List <GameObject>[] attackers = new List <GameObject> [2]; List <GameObject>[] defenders = new List <GameObject> [2]; for (int i = 0; i < attackers.Length; i++) { attackers[i] = new List <GameObject>(); defenders[i] = new List <GameObject>(); } while (true) { timeBegin = Time.realtimeSinceStartup; for (int i = 0; i < attackers.Length; i++) { attackers[i].Clear(); defenders[i].Clear(); } // adding back units which becomes attackable (if they get less attackers than defined by critical number) var searchCounter = 0; for (int i = 0; i < aliveUnits.Count; i++) { var unit = aliveUnits[i]; var unitPars = unit.GetComponent <UnitParsFree>(); int alliance = unitPars.alliance; if (unitPars.mode == Mode.SEARCH) { attackers[alliance].Add(unit); searchCounter++; } defenders[alliance].Add(unit); } var defenderPoints = new List <Vector3[]>(); for (int i = 0; i < attackers.Length; i++) { var points = new Vector3[defenders[i].Count]; for (int j = 0; j < defenders[i].Count; ++j) { points[j] = defenders[i][j].transform.position; } defenderPoints.Add(points); } var kdTrees = new List <KDTreeFree>(); for (int i = 0; i < attackers.Length; i++) { kdTrees.Add(KDTreeFree.MakeFromPoints(defenderPoints[i])); } timeEnd = Time.realtimeSinceStartup; yield return(new WaitForSeconds(0.5f)); timeloops[1] = timeEnd - timeBegin; timeBegin = Time.realtimeSinceStartup; for (int i = 0; i < attackers.Length; i++) { if (defenders[1 - i].Count == 0) { continue; } for (int j = 0; j < attackers[i].Count; ++j) { var att = attackers[i][j]; var attPars = att.GetComponent <UnitParsFree>(); // Skipp all units which may have changed states during the yield if (attPars.mode != Mode.SEARCH) { continue; } var defenderId = kdTrees[1 - i].FindNearest(att.transform.position); var def = defenders[1 - i][defenderId]; attPars.setApproach(def); } } timeEnd = Time.realtimeSinceStartup; yield return(new WaitForSeconds(0.5f)); timeloops[1] += timeEnd - timeBegin; timeall[1] = timeloops[1] + 1.0f; performance[1] = timeloops[1] * 100.0f / timeall[1]; message1 = "Search: " + searchCounter.ToString() + "; " + timeloops[1].ToString() + "; " + performance[1].ToString() + "%"; } }
public IEnumerator SearchPhase() { // The main coroutine, which starts to search for nearest enemies neighbours and set them for attack // NN search works with kdtree.cs NN search class, implemented by A. Stark at 2009. // Target candidates are put on kdtree, while attackers used to search for them. // NN searches are based on position coordinates in 3D. float t1 = 0.0f; float t2 = 0.0f; float twaiter = 0.0f; float t3 = Time.realtimeSinceStartup; int indmindisti = 0; yield return(new WaitForSeconds(1.0f)); while (true) { t1 = Time.realtimeSinceStartup; twaiter = 0; KDTreeFree RTree1 = new KDTreeFree(); KDTreeFree RTree2 = new KDTreeFree(); // adding back units which becomes attackable (if they get less attackers than defined by critical number) for (int i = 0; i < unitss.Count; i++) { GameObject go = unitss[i]; if (go.GetComponent <UnitParsFree>().isReady) { int alliance = go.GetComponent <UnitParsFree>().alliance; if (go.GetComponent <UnitParsFree>().isAttackable == true) { if (go.GetComponent <UnitParsFree>().onTargetSearch == false) { runits[alliance].Add(go); go.GetComponent <UnitParsFree>().onTargetSearch = true; } } rfunits[alliance].Add(go); go.GetComponent <UnitParsFree>().isReady = false; } } // resetting copies arrays. cprunits[1].Clear(); cprunits[2].Clear(); cprfunits[1].Clear(); cprfunits[2].Clear(); for (int i = 1; i < runits[1].Count; i++) { cprunits[1].Add(runits[1][i]); } for (int i = 0; i < runits[2].Count; i++) { cprunits[2].Add(runits[2][i]); } for (int i = 1; i < rfunits[1].Count; i++) { cprfunits[1].Add(rfunits[1][i]); } for (int i = 1; i < rfunits[2].Count; i++) { cprfunits[2].Add(rfunits[2][i]); } // finding counters for copies arrays countr1 = cprunits[1].Count; countr2 = cprunits[2].Count; countrf1 = cprfunits[1].Count; countrf2 = cprfunits[2].Count; // initialising vector arrays Vector3[] rtreePoints1 = new Vector3[countr1]; Vector3[] rtreePoints2 = new Vector3[countr2]; int [] iorig1 = new int[countr1]; int [] iorig2 = new int[countr2]; Vector3[] rftreePoints1 = new Vector3[countrf1]; Vector3[] rftreePoints2 = new Vector3[countrf2]; int [] iorigf1 = new int[countrf1]; int [] iorigf2 = new int[countrf2]; // putting target candidates coordinates onto arrays and setting non attackable targets not to be used on search // rtreePoints1[0] = new Vector3 (-999999999999.99f,-999999999999.99f,-999999999999.99f); // iorig1[0]=0; // rtreePoints2[0] = new Vector3 (-999999999999.99f,-999999999999.99f,-999999999999.99f); // iorig2[0]=0; for (int i = 1; i < countr1; i++) { rtreePoints1[i] = cprunits[1][i].transform.position; iorig1[i] = i; if (cprunits[1][i].GetComponent <UnitParsFree>().isAttackable == false) { if (cprunits[1][i].GetComponent <UnitParsFree>().onTargetSearch == true) { cprunits[1][i].GetComponent <UnitParsFree>().onTargetSearch = false; runits[1].Remove(cprunits[1][i]); } } // } for (int i = 1; i < countr2; i++) { rtreePoints2[i] = cprunits[2][i].transform.position; iorig2[i] = i; if (cprunits[2][i].GetComponent <UnitParsFree>().isAttackable == false) { if (cprunits[2][i].GetComponent <UnitParsFree>().onTargetSearch == true) { cprunits[2][i].GetComponent <UnitParsFree>().onTargetSearch = false; runits[2].Remove(cprunits[2][i]); } } } // putting attackers candidates coordinates onto arrays and removing them from original arrays, // as they all will get targets for (int i = 1; i < countrf1; i++) { rftreePoints1[i] = cprfunits[1][i].transform.position; iorigf1[i] = i; rfunits[1].Remove(cprfunits[1][i]); } for (int i = 1; i < countrf2; i++) { rftreePoints2[i] = cprfunits[2][i].transform.position; iorigf2[i] = i; rfunits[2].Remove(cprfunits[2][i]); } // sorting vector arrays for faster searches in kdtree // HeapSort(rtreePoints1, iorig1); // HeapSort(rtreePoints2, iorig2); // HeapSort(rftreePoints1, iorigf1); // HeapSort(rftreePoints2, iorigf2); // putting target candidates onto kdtree RTree1 = KDTreeFree.MakeFromPoints(rtreePoints1); RTree2 = KDTreeFree.MakeFromPoints(rtreePoints2); GameObject tempObj1; GameObject tempObj2; // first team attackers searching and setting their targets for (int i = 1; i < countrf1; i++) { indmindisti = RTree2.FindNearest(rftreePoints1[i]); int io = iorigf1[i]; int iomind = iorig2[indmindisti]; tempObj1 = cprfunits[1][io]; tempObj2 = cprunits[2][iomind]; tempObj1.GetComponent <UnitParsFree>().target = tempObj2; // adding attacker to target attackers list tempObj2.GetComponent <UnitParsFree>().attackers.Add(tempObj1); tempObj2.GetComponent <UnitParsFree>().noAttackers = tempObj2.GetComponent <UnitParsFree>().noAttackers + 1; tempObj1.GetComponent <UnitParsFree>().isApproaching = true; if (Time.realtimeSinceStartup - t3 > 0.005f) { twaiter = twaiter + 0.1f * (Time.realtimeSinceStartup - t3) + 0.05f; yield return(new WaitForSeconds(0.1f * (Time.realtimeSinceStartup - t3) + 0.05f)); t3 = Time.realtimeSinceStartup; } } // second team attackers searching and setting their targets for (int i = 1; i < countrf2; i++) { indmindisti = RTree1.FindNearest(rftreePoints2[i]); int io = iorigf2[i]; int iomind = iorig1[indmindisti]; tempObj1 = cprfunits[2][io]; tempObj2 = cprunits[1][iomind]; tempObj1.GetComponent <UnitParsFree>().target = tempObj2; // adding attacker to target attackers list tempObj2.GetComponent <UnitParsFree>().attackers.Add(tempObj1); tempObj2.GetComponent <UnitParsFree>().noAttackers = tempObj2.GetComponent <UnitParsFree>().noAttackers + 1; tempObj1.GetComponent <UnitParsFree>().isApproaching = true; if (Time.realtimeSinceStartup - t3 > 0.005f) { twaiter = twaiter + 0.1f * (Time.realtimeSinceStartup - t3) + 0.05f; yield return(new WaitForSeconds(0.1f * (Time.realtimeSinceStartup - t3) + 0.05f)); t3 = Time.realtimeSinceStartup; } } t2 = Time.realtimeSinceStartup; displayMessage = true; // main coroutine wait statement and performance information collection from search coroutine twaiter = twaiter + 0.5f + 1.0f * (t2 - t1); yield return(new WaitForSeconds(0.5f + 1.0f * (t2 - t1))); float curTime = Time.realtimeSinceStartup; timeloops[1] = curTime - t1 - twaiter; timeall[1] = curTime - t1; performance[1] = (curTime - t1 - twaiter) * 100.0f / (curTime - t1); message1 = ("Search: " + (countr1 + countr2).ToString() + "; " + countrf1 + "; " + countrf2 + "; " + (curTime - t1 - twaiter).ToString() + "; " + (performance[1]).ToString() + "% "); } }