Welcome to my journey of realistic environments! I’ve always wanted to create an amazing 3D world but even after I purchased tons of vegetation assets and did my best designing, the world always would feel.. empty. Immersion is an important factor in most games, even the little things count.
So taking a step back I decided to work from the small to the big. The first system I planned to work on was an insect / seasonal feature. Where a manager will contain the information on what season it currently is and depending on the insect they will cocoon, sleep, die, etc based on realistic insects. Starting off with the most famous insect, a butterfly! I don’t have the season features implemented yet but they are coming soon. For now, I stuck with the basic core of my insect system, the flocking!
Explaining The Code:
There are two scripts we need in order to control our insects, which for now we will refer to as butterflies to keep it simple! The first script is the ButterflyManager, which will be responsible for containing all the butterflies settings like speed, prefabs to spawn, avoidance layers & distance, etc. The second script is the ButterflyController, which is responsible for its own variables, and telling itself where to go depending on where everyone else is, which is inside of the ButterflyManager along with many other mass group settings.
Inside the ButterflyManager we spawn our prefabs, make sure they all have the needed components set and make them a child to our prefab for the organization. It is the simpler of the two scripts.
With nothing added to the butterflies, all it really ends up being is a script that spawns a random selection of prefabs inside a given area.
Now inside the ButterflyController is where all the fun stuff happens! Before anything, I had to get these butterflies flocking. In order to create a flocking effect, we needed to get the positions of every other butterfly so we can maneuver our current butterfly accordingly. For that I used ButterflyManager by adding each spawned butterfly to an array that we can keep track of.
Once we had our controllers set and ready to go I began by creating the variables. We created a holder for a reference, connected it to our ButterflyManager and made two new vectors, one is an average center of the entire group, the other is an average avoidance distance, we then have our global speed and the group size our current prefab is flocking in.
Once we finally had our variables set up, we went to work assigning them! Running a foreach loop for every butterfly except our own we can figure out where each one is. So depending on if the butterfly we were checking was within the correct distance to be inside our group, we would run this code that we can refer to as the FlockRules.
What’s really going on here is we are adding the average group center to our transform position, making it move but since most the time the average center will be Vector3.zero, nothing will happen. That is until we are not close enough to the global center and need to move.
Just like above we are also checking for the avoidance vector, this will add a negative value based on the distance of each butterfly that is to close to us, making us avoid the butterfly that's too close. (Remember each butterfly will have this so that means they will avoid each other)
Finally, we will be setting our global speed! Which is grabbing the speed of every butterfly we are flocking with and changing our speed based on theirs, almost like traffic.
After all that we have one final rule to work out, what actions to take when we are within a group. Which is adding all the explained up but dividing the speed and center from the group size, giving us an average of each.
Once we have our FlockRules set down we can drop the mic because the flocking is basically finished!
After you watch the beauty, you will notice some butterflies just go straight and never return, well that's because they don't have bounds set yet, so they don't know when they have crossed the line.
We also want to create a way for our butterflies to know when they’re about to hit a collider and not just each other to give them interaction with the world. So we create a RaycastHit variable, another direction variable and a bounds variable to replicate our wanderLimits. With a boolen we can now tell our butterflies when to start turning, so we check if our butterfly is outside the bounds and if they are, make turning true and head back towards home else make it false and continue with flocking.
Next, we will focus on adding collision avoidance to our butterflies by using unitys Vector3.Reflect, giving us our new direction, anywhere but a crash!
An explanation on how our butterflies check for head-on collision using raycasts
Add the end of this void we have a transform.translate(x,y,z) which moves our butterfly along the Z-Axis. If your prefab is a different forward axis, you need to change the axis of: "transform.Translate(0, 0, Time.deltaTime * speed); "
Now we have our butterflies checking for collisions! We set up a randomized timer so that our raycasts are not always running.
And voila that's it! After tons of headaches, we have an intelligent flocking system that can avoid any object we want that has colliders. Making an awesome butterfly system seem not just like particle effects and more apart of the world.. But wait there's more! You can walk away now or you can learn how we added stop points for our butterflies.
Adding Small Features:
So that's right there's more, a small little feature that will give your butterflies the randomly generated idea to go rest on a flower and start sipping some nectar!
Notice the right flower getting attacked for its nectar!
For this to work we added some simple functions, first off we enclosed our flocking functions into a void called Flocking, and to only be set to be true if we are not “goingToFlower”. Then we set up a random timer to generate a random chance of our butterfly going to the nearest flower. If our butterfly lands on our nearest flower we set a random reset to bring out buddy back in the air.