void InitSpatialGrid() { spatialGrid = new List <GameObject> [flyingSpace, flyingSpace, flyingSpace]; for (int i = 0; i < numBoids; i++) { //initialize spatial grid again. //if its null at hash make a list at the voxel. currBoid = boidList[i].GetComponent <boids>(); position = currBoid.transform.position; //if boid position outside of limits, kill and reinitialize if (position.x < 0.0f || position.x > flyingSpace || position.y < 0.0f || position.y > flyingSpace || position.z < 0.0f || position.z > flyingSpace) { position = new Vector3 (Random.Range(0.0f + flyingSpace / 8, flyingSpace - flyingSpace / 8), Random.Range(0.0f + flyingSpace / 8, flyingSpace - flyingSpace / 8), Random.Range(0.0f + flyingSpace / 8, flyingSpace - flyingSpace / 8)); // calculateMedianPoint(); Destroy(boidList[i]); boidList[i] = Instantiate(boidPrefab, position, Quaternion.identity); } if (spatialGrid[(int)Mathf.Floor(position.x), (int)Mathf.Floor(position.y), (int)Mathf.Floor(position.z)] == null) { spatialGrid[(int)Mathf.Floor(position.x), (int)Mathf.Floor(position.y), (int)Mathf.Floor(position.z)] = new List <GameObject>(); } spatialGrid[(int)Mathf.Floor(position.x), (int)Mathf.Floor(position.y), (int)Mathf.Floor(position.z)].Add(boidList[i]); } }
//Update called once per update void UpdateBoidPositions() { for (int i = 0; i < flyingSpace; i++) { for (int j = 0; j < flyingSpace; j++) { for (int k = 0; k < flyingSpace; k++) { if (spatialGrid[i, j, k] != null) { //for each boid in list at voxel int count = spatialGrid[i, j, k].Count; for (int boidInVoxelList = 0; boidInVoxelList < count; boidInVoxelList++) { currBoid = spatialGrid[i, j, k][boidInVoxelList].GetComponent <boids>(); //create interaction list //everything in this voxel can be added // interactionList.AddRange(spatialGrid[i, j, k]); //plus everything that is one voxel away on all sides //this will add 27 boxes if 3x3x3 or greater. otherwise will add all 8. for (int n = i - 1; n <= i + 1; n++) { //if its less than 0 we dont want that if (n < 0) { continue; } if (n >= flyingSpace) { continue; } for (int p = j - 1; p <= j + 1; p++) { if (p < 0) { continue; } if (p >= flyingSpace) { continue; } for (int q = k - 1; q <= k + 1; q++) { if (q < 0) { continue; } if (q >= flyingSpace) { continue; } // Debug.Log("Would be adding boids from voxel [" + n + "," + p + "," + q + "]. /n/n"); if (spatialGrid[n, p, q] != null) { interactionList.AddRange(spatialGrid[n, p, q]); } } } } Vector3 ourBoidPosition = spatialGrid[i, j, k][boidInVoxelList].transform.position; //now we have interaction list with our ijk boid. iterate thru each in list and add up accelerations int interactionCount = interactionList.Count; for (int r = 0; r < interactionCount; r++) { if (interactionList[r].GetInstanceID() != currBoid.GetInstanceID()) { boids otherBoid = interactionList[r].GetComponent <boids>(); //compute distance between our boid and the boid from the interaction list distance = interactionList[r].transform.position - ourBoidPosition; //compute ktheta thetaOne = currBoid.GetThetaOne(); thetaTwo = currBoid.GetThetaTwo(); thetaMagnitude = Vector3.Angle(currBoid.getVelocity(), otherBoid.transform.position); if ((-thetaOne / 2 <= thetaMagnitude) && thetaMagnitude <= thetaOne / 2) { ktheta = 1.0f; } else if (((thetaOne / 2) <= thetaMagnitude) && (thetaMagnitude <= (thetaTwo / 2))) { ktheta = ((thetaTwo / 2) - thetaMagnitude) / ((thetaTwo / 2) - (thetaOne / 2)); } else { ktheta = 0.0f; } //compute kd if (distance.magnitude < r1) { kd = 1.0f; } else if ((r1 <= distance.magnitude) && (distance.magnitude <= r2)) { kd = (r2 - distance.magnitude) / (r2 - r1); } else { kd = 0.0f; } //pg 107 from House and Keyser's text collision += ktheta * kd * (-1.0f * (kCollisionScale / (distance.magnitude + 0.01f)) * distance.normalized); velocityMatch += ktheta * kd * (kVelocityScale * (otherBoid.getVelocity() - currBoid.getVelocity())); centering += ktheta * kd * kCenteringScale * distance; } } //prioritizing acceleration source (pg 108) float ar = accelerationCap; combinedAcceleration = Mathf.Min(ar, collision.magnitude) * collision.normalized; ar = accelerationCap - combinedAcceleration.magnitude; combinedAcceleration = combinedAcceleration + Mathf.Min(ar, velocityMatch.magnitude) * velocityMatch.normalized; ar = accelerationCap - combinedAcceleration.magnitude; combinedAcceleration = combinedAcceleration + Mathf.Min(ar, centering.magnitude) * centering.normalized; //check walls. r2 is the far distance used in calculating kd //check if our boid is nearing where X = 0 if (ourBoidPosition.x < (3 * flyingSpace / 7)) { combinedAcceleration.x += accelerationCap / 2; } //check if our boid is nearing where X = max X bound else if ((flyingSpace - ourBoidPosition.x) < 3 * flyingSpace / 7) { combinedAcceleration.x += -accelerationCap / 2; } //so if acceleration = 0 then reversing doesnt work //check if our boid is nearing bound where Y = 0 if ((ourBoidPosition.y) < 3 * flyingSpace / 7) { combinedAcceleration.y += accelerationCap / 2; } //check if our boid is nearing where Y = max Y bound else if ((flyingSpace - ourBoidPosition.y) < 3 * flyingSpace / 7) { combinedAcceleration.y -= accelerationCap / 2; } //check if our boid is nearing where Z = 0 if ((ourBoidPosition.z) < 3 * flyingSpace / 7) { combinedAcceleration.z += accelerationCap / 2; } //check if our boid is nearing where Z = max Z bound else if ((flyingSpace - ourBoidPosition.z) < 3 * flyingSpace / 7) { combinedAcceleration.z += -accelerationCap / 2; } currBoid.setVelocity(combinedAcceleration * Time.deltaTime + currBoid.getVelocity()); //update position temp = ourBoidPosition; spatialGrid[i, j, k][boidInVoxelList].transform.position = (2.0f * ourBoidPosition) - currBoid.getOldPosition() + ((Time.deltaTime * Time.deltaTime) * (combinedAcceleration)); currBoid.setOldPosition(temp); interactionList.Clear(); } } } } } System.Array.Clear(spatialGrid, 0, spatialGrid.GetLength(0) * spatialGrid.GetLength(1) * spatialGrid.GetLength(2)); }
// Start is called before the first frame update void Start() { boid = GetComponent <boids>(); }