Example #1
0
        /// <summary>
        /// Generates a flocking behavior based on parameters contained within FlockingData.
        /// </summary>
        public static void Flock(FlockingData flockingData, bool checkForBounds = true, bool checkForCollision = true)
        {
            // Change goal position within flock limits based on random frequency
            if (Random.Range(0, 100) < flockingData.positionGoalChangeFrequency)
            {
                flockingData.AdjustGoalWithinFlockRange(Random.Range(-flockingData.FlockLimits.x, flockingData.FlockLimits.x),
                                                        Random.Range(-flockingData.FlockLimits.y, flockingData.FlockLimits.y),
                                                        Random.Range(-flockingData.FlockLimits.z, flockingData.FlockLimits.z));
            }

            for (int i = 0; i < flockingData.allUnits.Length; i++)
            {
                UnitData unitData = flockingData.allUnits[i];

                Vector3    direction       = Vector3.zero;
                Bounds     bounds          = new Bounds(flockingData.FlockGoal, flockingData.FlockLimits * 2);
                RaycastHit?nullableHitInfo = CheckForCollision(unitData.transform);

                // Rotate unit back towards the flock if they move outside of flock limit
                if (CheckFlockBounds(unitData.transform, bounds) && checkForBounds)
                {
                    direction = flockingData.FlockGoal - unitData.transform.position;
                    unitData.transform.rotation = Quaternion.Slerp(unitData.transform.rotation, Quaternion.LookRotation(direction), flockingData.unitRotationSpeed * Time.deltaTime);
                }
                // Rotate unit away to avoid obstacles
                else if (nullableHitInfo != null && checkForCollision)
                {
                    RaycastHit hitInfo = (RaycastHit)nullableHitInfo;
                    Debug.DrawRay(unitData.transform.position, hitInfo.point, Color.yellow);
                    direction = Vector3.Reflect(unitData.transform.forward, hitInfo.normal);
                    Debug.DrawRay(unitData.transform.position, direction, Color.red);
                    unitData.transform.rotation = Quaternion.Slerp(unitData.transform.rotation, Quaternion.LookRotation(direction), flockingData.unitRotationSpeed * Time.deltaTime);
                }
                // Apply regular flocking behavior based on random frequency
                else
                {
                    //direction = new Vector3(Random.Range(-flockingData.FlockLimits.x, flockingData.FlockLimits.x),
                    //                        Random.Range(-flockingData.FlockLimits.y, flockingData.FlockLimits.y),
                    //                        Random.Range(-flockingData.FlockLimits.z, flockingData.FlockLimits.z));

                    if (Random.Range(0, 100) < 1)
                    {
                        unitData.speed = Random.Range(flockingData.unitMinSpeed, flockingData.unitMaxSpeed);
                    }

                    if (Random.Range(0, 100) < flockingData.flockingFrequency)
                    {
                        direction = FlockDirection(unitData, flockingData);
                    }
                }

                if (direction != Vector3.zero)
                {
                    unitData.transform.rotation = Quaternion.Slerp(unitData.transform.rotation, Quaternion.LookRotation(direction), flockingData.unitRotationSpeed * Time.deltaTime);
                }

                unitData.transform.Translate(0, 0, Time.deltaTime * unitData.speed);
            }
        }
Example #2
0
        public static Vector3 FlockDirection(UnitData unitData, FlockingData flockingData)
        {
            Vector3 headingVector   = Vector3.zero;
            Vector3 avoidanceVector = Vector3.zero;
            Vector3 direction       = Vector3.zero;

            float groupSpeed = 0.01f;
            float minDistanceToGroup;
            int   groupSize = 0;

            foreach (var unit in flockingData.allUnits)
            {
                if (unit.transform != unitData.transform)
                {
                    // Check distance to each fish in flock
                    minDistanceToGroup = Vector3.Distance(unit.transform.position, unitData.transform.position);
                    if (minDistanceToGroup <= flockingData.maximumGroupDistance)
                    {
                        //Add that fish to group & add their position to group avg (flock center avg)
                        headingVector += unit.transform.position;
                        groupSize++;

                        // Check if distance is bigger than minimum distance value
                        if (minDistanceToGroup < flockingData.minimumUnitProximity)
                        {
                            // Include that unit's position to the avoidance vector (don't hit neighbours)
                            avoidanceVector = avoidanceVector + (unitData.transform.position - unit.transform.position);
                        }

                        // TEMPORARY - Grab the speed of each unit and add it to the global speed value (determine global flock speed)
                        groupSpeed = groupSpeed + unitData.speed;
                    }
                }
            }

            if (groupSize > 0)
            {
                // Find the avg vector of the flock's center based on group size
                headingVector = headingVector / groupSize;

                // If a goal position is set, calculate the flock's heading based on goal location
                if (flockingData.FlockGoal != null)
                {
                    headingVector = headingVector + (flockingData.FlockGoal - unitData.transform.position);
                }

                // Set the individual's speed to the avg group speed
                unitData.speed = groupSpeed / groupSize;

                // Determine the direction the fish wants to travel to (based on center of flock & avoidance of neighbours)
                direction = (headingVector + avoidanceVector) - unitData.transform.position;
            }

            return(direction);
        }
Example #3
0
        /// <summary>
        /// Create a new flock and assign the necessary behavior.
        /// </summary>
        public static void CreateFlock(FlockingData flockingData)
        {
            flockingData.FlockGoal = flockingData.FlockCenter.position;
            flockingData.allUnits  = new UnitData[flockingData.numUnits];

            for (int i = 0; i < flockingData.numUnits; i++)
            {
                Vector3 pos = flockingData.FlockGoal + new Vector3(Random.Range(-flockingData.FlockLimits.x, flockingData.FlockLimits.x),
                                                                   Random.Range(-flockingData.FlockLimits.y, flockingData.FlockLimits.y),
                                                                   Random.Range(-flockingData.FlockLimits.z, flockingData.FlockLimits.z));

                flockingData.allUnits[i].transform = GameObject.Instantiate(flockingData.unitPrefab, pos, Quaternion.identity).transform;
                flockingData.allUnits[i].speed     = Random.Range(flockingData.unitMinSpeed, flockingData.unitMaxSpeed);
            }
        }