// Returns a separation Vector based upon the distance between the current agent and each agent in the flock, // and the current strength of Separation. Vector3 CalculateSeparationAcceleration(ai_flock_agent _agent) { Vector3 _sum = Vector3.zero; for (int i = 0; i < Agents.Count; i++) { // if we are not looking at ourself: if (Agents[i] != _agent && Agents[i]) { Vector3 _toAgent = _agent.transform.position - Agents[i].transform.position; float _distance = _toAgent.magnitude; float _safeDistance = _agent.safeRadius + Agents[i].safeRadius; // If we're too close to this agent, // we need to modify the outgoing vector by a ratio based upon our desired distances. if (_distance < _safeDistance) { _toAgent = _toAgent.normalized; _toAgent *= ((_safeDistance - _distance) / _safeDistance); _sum += _toAgent; } } } if (_sum.magnitude > 1.0f) { _sum = _sum.normalized; } return(_sum * SeparationStrength); }
// Returns an acceleration Vector based upon the average forward of the flock, // the current strength of Allignment, and the max speed of the agent. Vector3 CalculateAlignmentAcceleration(ai_flock_agent _agent) { Vector3 _forward = AverageForward; _forward /= _agent.maxSpeed; if (_forward.magnitude > 1) { _forward = _forward.normalized; } return(_forward * AlignmentStrength); }
// Returns a target direction Vector based upon the desired cohesion point of the flock, // and the strength of Cohesion. // *In flocking, the CohesionPoint is usually the "AveragePosition" of the flock. // However, in this example, we use the "Mother Ship" as our cohesion point.* Vector3 CalculateCohesionAcceleration(ai_flock_agent _agent, Vector3 CohesionPoint) { Vector3 _toTarget = CohesionPoint - _agent.transform.position; float _distance = _toTarget.magnitude; _toTarget = _toTarget.normalized; if (_distance < flockRadius) { _toTarget *= (_distance / flockRadius); } return(_toTarget * CohesionStrength); }
// Update is called once per frame void Update() { if (Agents.Count > 0) { // Calculates averages for the position and forward vector of the Flock. CalculateAverages(); // Each agent's rigidbody needs to be given the updated average information. for (int i = 0; i < Agents.Count; i++) { ai_flock_agent _agent = Agents[i]; // Paranoia check to remove any unwanted null references. if (!_agent) { Agents.Remove(_agent); continue; } // Acceleration for each agent is calculated based upon 3 values: // Alignment, Cohesion, and Separation. // These are calculated using the averages found above. Vector3 _acceleration = CalculateAlignmentAcceleration(_agent); _acceleration += CalculateCohesionAcceleration(_agent, TargetPosition); _acceleration += CalculateSeparationAcceleration(_agent); float _accelerationMultiplier = _agent.maxSpeed; _acceleration *= _accelerationMultiplier * Time.deltaTime; // Update the velocity of the agent, and lerp their forward towards the "target" (Gives an organic feel to the flying agent). _agent._rigidbody.velocity += _acceleration; Vector3 _forward = _agent.transform.forward; _forward = Vector3.Lerp(_forward, (TargetPosition - _agent.transform.position).normalized, 5 * Time.deltaTime); _agent.transform.forward = _forward; } } }
// Add a new set of agents to the flock based on "flockSize." public void AddToFlock() { for (int i = 0; i < flockSize; i++) { GameObject _agent = (GameObject)Instantiate(AgentToInstantiate, transform.position, transform.rotation); AgentObjs.Add(_agent); ai_flock_agent _ai = _agent.GetComponent <ai_flock_agent>(); _ai.maxSpeed = maxSpeed; _ai.safeRadius = safeRadius; _agent.transform.position = transform.position + new Vector3(Random.Range(-flockRadius, flockRadius), Random.Range(-flockRadius, flockRadius), Random.Range(-flockRadius, flockRadius)); if (!InitVelocityZero) { _ai.GetComponent <Rigidbody>().velocity = new Vector3(Random.Range(-maxSpeed, maxSpeed), Random.Range(-maxSpeed, maxSpeed), Random.Range(-maxSpeed, maxSpeed)); } else { _ai.GetComponent <Rigidbody>().velocity = Vector3.zero; } _ai.Update(); Agents.Add(_ai); } }