public override void Initialize(Vector3 surfacePosition) { base.Initialize(surfacePosition); sampler.SampleMesh(false); meshBounds = sampler.Bounds; boids = new Boid[numBoids]; surfaceBoids = new SurfaceBoid[numBoids]; boidMatrices = new Matrix4x4[numBoids]; for (int i = 0; i < numBoids; i++) { Boid b = new Boid(); MeshSample s = sampler.Samples[Random.Range(0, sampler.Samples.Length)]; b.Position = s.UV; b.Rotation = Random.Range(0, 360); boids[i] = b; SurfaceBoid sb = new SurfaceBoid(); sb.Offset = Random.value; surfaceBoids[i] = sb; } forces = new Force[fingers.Length]; }
private void DrawSurfaceBoids() { Vector3 scale = Vector3.one * boidScale; for (int i = 0; i < numBoids; i++) { SurfaceBoid b = surfaceBoids[i]; float bounce = bounceCurve.Evaluate(Mathf.Repeat((b.Offset + Time.time) * (surfaceBounceSpeed * b.Agitation), 1f)) * surfaceBounce; boidMatrices[i] = Matrix4x4.TRS(b.Position + (b.Normal * bounce), b.Rotation, scale); } Graphics.DrawMeshInstanced(boidMesh, 0, boidMat, boidMatrices); }
private void UpdateBoids(float time, float deltaTime) { Vector2 sumPositions = Vector2.zero; Vector2 sumVelocities = Vector2.zero; Vector2 averagePosition = Vector2.zero; Vector2 averageVelocity = Vector2.zero; int newNumBoidFleeing = 0; for (int i = 0; i < numBoids; i++) { Boid b = boids[i]; sumPositions += b.Position; sumVelocities += b.Velocity; } averagePosition = sumPositions / numBoids; averageVelocity = sumVelocities / numBoids; for (int b1i = 0; b1i < numBoids; b1i++) { Boid b1 = boids[b1i]; Vector2 desiredAverageDirection = (averagePosition - b1.Position).normalized; Vector2 separationDirection = Vector2.zero; Vector2 fleeDirection = Vector2.zero; Vector2 forceAveragePosition = Vector2.zero; Vector2 difference = Vector2.zero; int numBoidsInRange = 0; for (int b2i = 0; b2i < numBoids; b2i++) { if (b1i == b2i) { continue; } Boid b2 = boids[b2i]; float dist = DistanceBetween(b1.Position, b2.Position, ref difference); if (dist < minDistance) { separationDirection += (difference.normalized / dist); numBoidsInRange++; } } int numForcesInRange = 0; for (int fi = 0; fi < forces.Length; fi++) { Force f = forces[fi]; if (!f.Enabled || !f.Active) { continue; } float dist = DistanceBetween(b1.Position, f.Position, ref difference); if (dist < f.Radius) { fleeDirection += (difference.normalized / dist); forceAveragePosition += f.Position; numForcesInRange++; newNumBoidFleeing++; } } // Alignment and coherence happen regardless of proximity Vector2 alignment = Steer(b1.Velocity, averageVelocity); Vector2 coherence = Steer(b1.Velocity, desiredAverageDirection); Vector2 newVelocity = (alignmentAmount * alignment) + (coherenceAmount * coherence); if (numBoidsInRange > 0) { // Separation happens if any boids were in range separationDirection = (separationDirection / numBoidsInRange).normalized; Vector2 separation = Steer(b1.Velocity, separationDirection * maxSpeed); newVelocity += (separationAmount * separation); } // Do a smooth lerp for alignment, coherence and separation b1.Velocity = Vector2.Lerp(b1.Velocity, LimitMagnitude(newVelocity, maxSpeed), deltaTime); if (numForcesInRange > 0) { // Flee is more disruptive // Use disance to force center to determine flee amount forceAveragePosition = (forceAveragePosition / numForcesInRange); fleeDirection = (fleeDirection / numForcesInRange).normalized; float distToForceCenter = DistanceBetween(b1.Position, forceAveragePosition, ref difference); float normalizedFleeForce = Mathf.Clamp01(distToForceCenter / forceRadius.y); Vector2 flee = Steer(b1.Velocity, fleeDirection * fleeAmount * normalizedFleeForce); // Don't limit flee velocity b1.Velocity = b1.Velocity + flee; } // Make sure boids don't go out of range Vector2 position = b1.Position + (b1.Velocity * deltaTime); position.x = Mathf.Repeat(position.x, 1); position.y = Mathf.Repeat(position.y, 1); b1.Position = position; b1.Rotation = Mathf.Lerp(b1.Rotation, Mathf.Atan2(b1.Velocity.y, b1.Velocity.x) * Mathf.Rad2Deg, deltaTime); boids[b1i] = b1; } numBoidsFleeing = newNumBoidFleeing; Vector3 origin = surfaceTransform.position; for (int i = 0; i < numBoids; i++) { Boid b = boids[i]; SurfaceBoid sb = surfaceBoids[i]; sb.Agitation = 1f + (b.Velocity.magnitude * agitationMultiplier); sb.Position = SampleSurface(b.Position); sb.Normal = (sb.Position - origin).normalized; Vector3 up = Quaternion.AngleAxis(b.Rotation, Vector3.forward) * Vector3.right; sb.Rotation = Quaternion.LookRotation(sb.Normal, up); surfaceBoids[i] = sb; } }