Realistic, natural looking flocking behavior (for example, birds, antelopes, or bats) can be created through creating collections of objects with the following four simple rules:
Each member of the "flock" acts independently, but needs to know about the current heading and location of the members of its flock. This recipe shows you how to create a scene of flocking cubes. To keep things simple, we'll only implement basic versions of the last two rules of the preceding list: alignment and cohesion.
This recipe builds upon the player-controlled cube Unity project you created in the first recipe. So make a copy of that project, open it, and then follow the steps of this recipe.
To make a group of objects flock together, perform the following steps:
// file: Swarm using UnityEngine; using System.Collections; using System.Collections.Generic; public class Swarm : MonoBehaviour { public int droneCount = 20; public GameObject dronePrefab; private List<Drone> drones = new List<Drone>(); private void Awake(){ for (int i = 0; i < droneCount; i++){ AddDrone(); } } private void AddDrone(){ GameObject newDroneGO = (GameObject)Instantiate(dronePrefab); Drone newDrone = newDroneGO.GetComponent<Drone>(); drones.Add( newDrone ); float speed = 5f; float maxSpeed = 10f; float maxDirectionChange = .05f; newDrone.SetParameters(speed, maxSpeed, maxDirectionChange); } private void FixedUpdate(){ Vector3 swarmCenter = SwarmCenterAverage(); Vector3 swarmMovement = SwarmMovementAverage(); foreach(Drone drone in drones ) { drone.UpdateVelocity(swarmCenter, swarmMovement); } } private Vector3 SwarmCenterAverage() { // cohesion (swarm center point) Vector3 locationTotal = Vector3.zero; foreach(Drone drone in drones ) { locationTotal += drone.transform.position; } return (locationTotal / drones.Count); } private Vector3 SwarmMovementAverage() { // alignment (swarm direction average) Vector3 velocityTotal = Vector3.zero; foreach(Drone drone in drones ) { velocityTotal += drone.rigidbody.velocity; } return (velocityTotal / drones.Count); } }
Cube-boid
, at (0, 0, 0) and add a RigidBody component from Physics to Cube-boid
with the following properties:Cube-boid
:// file: Drone.cs using UnityEngine; using System.Collections; using System.Collections.Generic; public class Drone : MonoBehaviour { public void SetParameters(float speed, float maxSpeed, float maxDirectionChange){ _speed = speed; _maxSpeed = maxSpeed; _maxDirectionChange = maxDirectionChange; } private float _speed = 5f; private float _maxSpeed = 10f; private float _maxDirectionChange = .05f; public void UpdateVelocity(Vector3 swarmCenterAverage, Vector3 swarmMovementAverage){ // calc velocity adjustment for swarm Vector3 moveTowardsSwarmCenter = VectorTowards( swarmCenterAverage ); Vector3 adjustment = moveTowardsSwarmCenter + (2 * swarmMovementAverage ); Vector3 swarmVelocityAdjustment = UsefulFunctions.ClampMagnitude(adjustment, _maxDirectionChange); // apply velocity adjustment to this drone rigidbody.velocity += (swarmVelocityAdjustment * _speed); rigidbody.velocity = UsefulFunctions.ClampMagnitude(rigidbody.velocity, _maxSpeed); } private Vector3 VectorTowards(Vector3 target) { Vector3 targetDirection = target - transform.position; targetDirection.Normalize(); targetDirection *= _maxSpeed; return (targetDirection - rigidbody.velocity); } }
prefab_Boid
, and from the Hierarchy panel drag Cube-boid GameObject into this Prefab.Drone
Prefab.wall-left
, with the following properties:wall-left
object naming the new object wall-right
, and change the position of wall-right
to (15, 0.5, 0).wall-top
, with the following properties:wall-top
object naming the new object wall-bottom
, and change the position of wall-bottom
to (0, 0.5, -10).The Swarm
class contains the following three variables:
droneCount
: This is the number of swam members to be createddronePrefab
: This is a reference to the Prefab to be cloned to create swarm membersDrone
object references drones
: This is a list of all the scripted Drone
components inside all of the swarm GameObjects that have been createdUpon creation, as the scene starts, the Awake()
methods of the Swarm
class loops to create droneCount
swarm members by repeatedly calling the AddDrone()
method. This method instantiates a new GameObject from the Prefab and then sets variable newDrone
to be a reference to the Drone
-scripted object inside the new swarm member. Parameters for changing speed
, maxSpeed
, and maxDirection
are set in the newDrone
object.
Each frame FixedUpdate()
method (used since physics is involved, so Update()
would not be appropriate), loops through the list of Drone
objects, calling their UpdateVelocity()
methods, passing in the swarm center location and the average of all the swarm member velocities.
The rest of this Swarm
class is made up of two methods: one (SwarmCenterAverage
) returns a Vector3
object representing the average position of all the Drone
objects, and the other (SwarmMovementAverage
) returns a Vector3
object representing the average velocity (movement force) of all the Drone
objects.
The hard work is undertaken by the Drone
class. The SetParameters()
method stores the movement settings for the swarm into local variables for each Drone object's calculations.
The UpdateVelocity()
method inputs Vector3
arguments: swarmCenterAverage
and swarmMovementAverage
. This method then calculates the desired change in velocity for this particular Drone
object (swarmVelocityAdjustment
). The current movement velocity of the swarm member (rigidbody.velocity
) has added to it swarmVelocityAdjustment
multiplied by the _speed
variable. The velocity of the Drone
object is then limited to a maximum magnitude of _maxSpeed
to prevent situations where the addition of the new velocity to the existing movement results in movement that is faster than their maximum speed.
In order to calculate swarmVelocityAdjustment
, each Drone
object needs to use the following to decide what to do:
swarmMovementAverage
swarmCenterAverage
Variable moveTowardsSwarmCenter
calculates a vector pointing towards the center of the swarm, by calling the VectorTowards()
method and passing the swarm center position. The total swarm adjustment vector (swarmVelocityAdjustment
) is the sum of this vector towards the swarm center, added to two times the average velocity of the swarm (swarmMovementAverage
). This weighting of twice the average velocity compared to just one-times the swarm center position direction means that each Drone
object will try to keep moving with the swarm, rather than just cluster at some center point. Without this weighting, the swarm may simply stop moving after it forms a tight grouping. The size of this weighted velocity adjustment is limited to the value of the _maxDirectionChange
variable, which prevents Drone
objects from changing their direction too abruptly.
The VectorTowards()
method creates a unit vector in the direction of the given target position and then multiplies this by _maxSpeed
to create a velocity vector of length _maxSpeed
in the direction of the given target position. It then returns this vector with the Drone object's current velocity subtracted from it, that is, the force to be applied to make the already moving Drone
object move towards the target position at speed equaling to _maxSpeed
.
18.116.14.245