/// <summary>
        /// Assigning the target group and the fringe group
        /// </summary>
        private void UpdateActiveGroups(List <Boid> boidList)
        {
            targetGroup.Clear();
            fringeGroup.Clear();

            if (boidList == null || boidList.Count == 0)
            {
                return;
            }

            //find the nearest boid and form the target group from it and its neighbours
            Boid nearestBoid = BoidUtility.GetNearest(boidList, Position);

            targetGroup.Add(nearestBoid);
            foreach (var boid in nearestBoid.Neighbours)
            {
                targetGroup.Add(boid);
            }

            //form the fringe group from the neighbours of the target group that arent in the target group
            foreach (var boid in targetGroup)
            {
                foreach (var neighbour in boid.Neighbours)
                {
                    if (!targetGroup.Contains(neighbour) && !fringeGroup.Contains(neighbour))
                    {
                        fringeGroup.Add(neighbour);
                    }
                }
            }
        }
        /// <summary>
        /// Vector away from the average heading of the target group.
        /// We use a timer to track how long we have been attempting an attack, and based on this we
        /// decide how strongly we should be withdrawing.
        /// </summary>
        private Vector3 CalculateAttemptWithdrawal(List <Boid> boids, float currentWithdrawalWeight)
        {
            if (boids == null || boids.Count == 0)
            {
                return(Vector3.zero);
            }

            return((Position - BoidUtility.GetAveragePosition(boids)).normalized * currentWithdrawalWeight);
        }
        /// <summary>
        /// Vector towards the average position of the targets.
        /// By directing to the center of the group, we can achieve maximum
        /// fragmentation of the group and hopefully futher isolate target boids.
        /// </summary>
        private Vector3 CalculateGroupDisruption(HashSet <Boid> targets, float currentWithdrawalWeight)
        {
            if (targets == null || targets.Count == 0)
            {
                return(Vector3.zero);
            }

            return((BoidUtility.GetAveragePosition(targets) - Position).normalized * (1f - currentWithdrawalWeight));
        }
        /// <summary>
        /// Vector towards the the average position of the fringes.
        /// By directing to the position of the fringe group, we act to cut off
        /// the target group from reconnecting with the main flock.
        /// </summary>
        private Vector3 CalculateFlockSeparation(HashSet <Boid> fringes, float currentWithdrawalWeight)
        {
            if (fringes == null || fringes.Count == 0)
            {
                return(Vector3.zero);
            }

            return((BoidUtility.GetAveragePosition(fringes) - Position).normalized * (1f - currentWithdrawalWeight));
        }
        /// <summary>
        /// Vector towards the nearest target.
        /// This is the actual attack of a particular boid. As we get closer to a boid,
        /// our tendency to attack it increases.
        /// </summary>
        private Vector3 CalculateAttackEagerness(HashSet <Boid> targets, float currentWithdrawalWeight)
        {
            if (targets == null || targets.Count == 0)
            {
                return(Vector3.zero);
            }

            var toNearestBoid = BoidUtility.GetNearest(targets, Position).Position - Position;
            var weight        = 1f - Mathf.Clamp01(toNearestBoid.sqrMagnitude / attackRadiusSqr);      //weight nearer boids most heavily

            return(toNearestBoid.normalized * weight * (1f - currentWithdrawalWeight));
        }
        /// <summary>
        /// Vector away from other predators.
        /// This prevents the predator from targeting boids that are also
        /// being targeted by other predators.
        /// </summary>
        private Vector3 CalculateIndependence(List <BoidPredator> predators)
        {
            HashSet <BoidPredator> others = new HashSet <BoidPredator>(predators);

            others.Remove(this);

            if (others.Count > 0)
            {
                var toNearestPred = BoidUtility.GetNearest(others, Position).Position - Position;
                var weight        = 1f - Mathf.Clamp01(toNearestPred.sqrMagnitude / viewRadius);          //weight nearer predators most heavily
                return(-toNearestPred.normalized * weight);
            }

            return(Vector3.zero);
        }
        private bool CheckForTargetCapture()
        {
            if (targetGroup == null || targetGroup.Count == 0)
            {
                return(false);
            }

            var nearestBoid = BoidUtility.GetNearest(targetGroup, Position);

            if ((nearestBoid.Position - Position).sqrMagnitude <= captureRadiusSqr)
            {
                nearestBoid.Kill();
                killCount++;
                return(true);
            }

            return(false);
        }
        private void OnDrawGizmosSelected()
        {
            if (!showDebug)
            {
                return;
            }

            //Targets
            Gizmos.color = Color.red;

            ///draw average position of target group
            var avgTargetPos = BoidUtility.GetAveragePosition(targetGroup);

            if (avgTargetPos != Vector3.zero)
            {
                Gizmos.DrawSphere(avgTargetPos, 0.33f);
            }

            ///draw position of each target
            foreach (var b in targetGroup)
            {
                Gizmos.DrawWireSphere(b.Position, 0.25f);
            }

            //Fringes
            Gizmos.color = Color.yellow;

            ///draw average position of fringe group
            var avgFringePos = BoidUtility.GetAveragePosition(fringeGroup);

            if (avgFringePos != Vector3.zero)
            {
                Gizmos.DrawSphere(avgFringePos, 0.33f);
            }

            ///draw position of each fringe boid
            foreach (var b in fringeGroup)
            {
                Gizmos.DrawWireSphere(b.Position, 0.25f);
            }

            //Withdrawal
            float currentWithdrawlWeighting = Mathf.InverseLerp(withdrawalStartTime, withdrawalEndTime, timeSinceAttackStarted);

            if (currentWithdrawlWeighting <= 0.5f)
            {
                Gizmos.color = Color.Lerp(Color.green, Color.yellow, currentWithdrawlWeighting * 2);
            }
            else
            {
                Gizmos.color = Color.Lerp(Color.yellow, Color.red, 2 * currentWithdrawlWeighting - 1f);
            }

            Gizmos.DrawCube(Position + Vector3.up * 0.2f, Vector3.one * 0.4f);

            var separation   = flockSeparation * separationWeightNorm;
            var disruption   = groupDisruption * disruptionWeightNorm;
            var eagerness    = attackEagerness * eagernessWeightNorm;
            var withdrawal   = attemptWithdrawal * withdrawalWeightNorm;
            var independence = huntIndependence * independenceWeightNorm;

            Gizmos.color = Color.white;
            Gizmos.DrawLine(Position, Position + separation * 5);
            Gizmos.color = Color.cyan;
            Gizmos.DrawLine(Position, Position + disruption * 5);
            Gizmos.color = Color.magenta;
            Gizmos.DrawLine(Position, Position + eagerness * 5);
            Gizmos.color = Color.blue;
            Gizmos.DrawLine(Position, Position + withdrawal * 5);
            Gizmos.color = Color.black;
            Gizmos.DrawLine(Position, Position + independence * 5);
        }
Beispiel #9
0
 /// <summary>
 /// Flock Cohesion
 /// </summary>
 private Vector3 CalculateCohesion(List <Boid> neighbours)
 {
     return((Vector3.Lerp(BoidUtility.GetAveragePosition(neighbours), Position, 0.5f) - Position).normalized);
 }
Beispiel #10
0
 /// <summary>
 /// Velocity Alignment
 /// </summary>
 private Vector3 CalculateAlignment(List <Boid> neighbours)
 {
     return(BoidUtility.GetAverageHeading(neighbours, Position, controller.ViewRadiusSqr, VelocityNormalized));
 }