Controlling object group movement through flocking

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:

  • Separation: Avoid getting too close to neighbors
  • Avoid obstacles: Turn away from an obstacle which is immediately ahead
  • Alignment: Move in the direction the flock is heading
  • Cohesion: Move towards the location in the middle of the flock

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.

Getting ready

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.

How to do it...

To make a group of objects flock together, perform the following steps:

  1. Add the following C# script class to the Main Camera:
    // 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);	
      }
    }
  2. Create a new cube GameObject named Cube-boid, at (0, 0, 0) and add a RigidBody component from Physics to Cube-boid with the following properties:
    • Mass as 1
    • Drag is 0
    • Angular Drag is 0.05
    • Use Gravity and Is Kinematic are both un-checked
    • Under Constrains Freeze Position for the Y axis is checked
  3. You should see the following Inspector values for your cube's rigid body component:
    How to do it...
  4. Add the following C# script class to 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);
      }
    }
  5. Create a new empty Prefab named prefab_Boid, and from the Hierarchy panel drag Cube-boid GameObject into this Prefab.
  6. Delete Cube-boid from the Scene panel.
  7. With Main Camera selected in the Hierarchy panel, drag prefab_Boid from the Project panel over the public variable of Drone Prefab.
  8. Create a new cube named wall-left, with the following properties:
    • Position: (-15, 0.5, 0)
    • Scale: (1, 1, 20)
  9. Duplicate the wall-left object naming the new object wall-right, and change the position of wall-right to (15, 0.5, 0).
  10. Create a new cube named wall-top, with the following properties:
    • Position: (0, 0.5, 10)
    • Scale: (31, 1, 1)
  11. Duplicate the wall-top object naming the new object wall-bottom, and change the position of wall-bottom to (0, 0.5, -10).
  12. Finally, make the player's red cube larger, set its Scale to (3, 3, 3).

How it works...

The Swarm class contains the following three variables:

  • Integer droneCount: This is the number of swam members to be created
  • GameObject dronePrefab: This is a reference to the Prefab to be cloned to create swarm members
  • List of Drone object references drones: This is a list of all the scripted Drone components inside all of the swarm GameObjects that have been created

Upon 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.

How it works...

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
    • What is the general direction the swarm is moving?
    • This is known as alignment—a swarm member attempting to move in the same direction as the swarm average
  • swarmCenterAverage
    • What is the center position of the swarm?
    • This is know as cohesion—a swarm member attempting to move towards the center of the swarm

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.

See also

  • The Controlling cube movement through player controls recipe
  • The Controlling object look-at behavior recipe
  • The Controlling object-to-object movements (seek, flee, follow at a distance) recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.223.10