This is it, the final sprint, the last push. This week I have added in a music player and have begun my last round of bug fixing and optimization before submission.
My music player script stores a number of licenced music tracks in an array, and plays them in a shuffled order.
// Picks next track
nextTrack = Random.Range(0, tracks.Length - 1);
// Avoids the same track replaying
if (nextTrack == currentTrack)
nextTrack += 1;
// Starts playing the next track
audioSource.clip = tracks[nextTrack];
currentTrack = nextTrack;
trackName.text = tracks[currentTrack].name;
// Waits until track is finished playing
yield return new WaitWhile(() => audioSource.isPlaying);
By naming each audio clip as the track title and artist separated by a dash then I can send the name of the currently playing trach to a text element in the UI. Also in the UI I’ve added a slider that controls the audio source volume. If I were adding more sound effects I would instead control the volume of a mixer where multiple audio sources would be sent. However due to the creative decision to avoid sound effects this was unnecessary.
The remainder of this sprint is going to be spent bug fixing and completing my portfolio submission for the module.
This week just a short post about the user testing I’ve been conducting. I’ve sent the game to a number of people who have been reporting any bugs they’ve found back to me. So far I was aware of all the bugs sent to me and have a plan in place to sort each one. The main take away from the testing is the performance limit.
My laptop can simulate 100 BOIDs before a significant frame rate drop. Initially I assumed this was just the limit of processor but this limit appears to be universal on different hardware.
After some back of the napkin calculations I worked out that the number of calculations per frame increases at a factor of:
f(x) = x2 – x
…where x is equal to the number of BOIDs. This is because each BOID is collecting vector information on every other BOID. Which means there’s no way round this.
However I have noticed the simulation doesn’t take full advantage of all the cores on mine and other testers processors. Which has lead to me researching the data orientated tech stack, or DOTS in Unity. It would allow the simulation to run on multiple threads and therefore utilise all a processors cores. Rather than using game objects DOTS keeps track of entities and pieces of data. Here’s a tech demo of DOTS being used to simulate a futuristic city in Unity:
After reading the documentation it is clear DOTS is perfect for this type of application, but though super cool far exceeds this projects scope. If I where to implement DOTS it would require rewriting most of my object oriented code with new syntax I’m unfamiliar with. If the project had set out to use DOTS from the beginning it might have been possible but with the due date in a months time and with the development portfolio and video still to make I don’t have the time.
Come to terms with the fact that without DOTS the simulation will probably be limited to 100 fish 😥 . Continue bug fixing and user testing. Implement the music and UI elements I talked about last week.
Sprint 3 is finished and a version of the simulation with all the major features is complete. I’ve begun sending the simulation to people for testing and am hosting it on itch.io. Click here to download the latest version.
The features I spent this week working on were the UI and menus. The UI is made up three parts, the main menu, the tutorial screen and the parameter menu. All the UI elements were designed in a flat style using the British colour palette from flatcolors.com.
I started the main menu by designing a simple logo for the simulation which I have simply named ‘shoal’. The menu has four options: a quit button which closes the application; the inspiration button which opens a link to the YouTube video that inspired the project; the blog button which links to this blog and the play button which opens the tutorial screen.
The tutorial screen tells the player how to place food for the fish and open the parameter menu. The contents of the screen fades in sequentially after the main menu has faded out when the play button is clicked. By clicking anywhere on the screen after the play button is clicked will trigger the the scene manager to change the games scene to the main simulation scene. By keeping the backgrounds of each scene the same transitions appear seamless.
The parameter menu is accessed in the main scene by pressing the escape key. Currently the screen allows the user to adjust sliders controlling different parameters of the simulation. The value of each slider is displayed in the input field next to it. The user can also type desired values directly into the box, these values can exceed the maximum values of the slider (though the slider values are my recommended parameters through testing). Due to time constraints the elements in this menu still use the Unity default elements. I aim to replace these with elements in a similar style to the rest of the UI in the next version.
With the major features implemented my time over the foreseeable future will be spent user testing and bug fixing. Though I would like to find time to include some stretch goal features I didn’t think I’d have time for, like putting in some relaxing royalty free music. I’d also like to have the option to change the tank size in the parameter menu.
I have now started with my scheduled goal of adding animations and sprites to the simulation. To make this easier I decided to pick a species of fish and predator to base mine on. Inspired by this dramatic scene from the BBC documentary The Hunt in 2017 I decided to go with Sardines as the BOIDs and Tuna as the predators:
Another reason for picking sardines is they are of the Clupeidae family meaning they have short lateral lines. Lateral lines are sensory organs that aid fish sense water pressure and therefore objects around them. This means my model of fish vision in the simulation fits sardines quite well.
As for art style I decided to make things easy for myself and draw the fish as silhouettes viewed from the surface, much like the fish seen in Animal Crossing: New Horizons:
First I drew a silhouette roughly proportional to a sardine in Adobe Illustrator. I then took this silhouette into Unity, and after watching some tutorials used the skinning editor to create a skeletal mesh. To save myself key framing each bone I used the 2D Inverse Kinematics package to chain bones together. After a few more tutorials I got this working and created an animation that looks like this:
It wasn’t too bad, but it didn’t look quite right. So I’ve spent some time researching the strangely interesting world of fish movement and locomotion. I’m going to unload some useful terms and explanations I’ve learnt.
Sardines are of a fusiform shape meaning they are very hydro dynamic, like little torpedoes.
They use body caudal fin propulsion, meaning their bodies move in oscillating waves as they swim. There are five different classifications of body caudal fin propulsion that determine how much the tail moves in proportion the head.
Eels for example fall into the anguilliform group since the amplitude of the wave travelling through their body changes very little as it moves from head to tail.
Fish in the thunniform group however move their head very little and the tail does the majority of the work, this is useful for predators like sharks and tuna who use their heads when attacking.
Finally we come to sardines which primarily fall in the sub-carangiform group, they are relatively stiff with the tail doing most the work, but still use their upper bodies slightly when moving, this gives them a good balance of speed and manoeuvrability.
Armed with this knowledge I returned to Unity and created some new animations settling on this:
In order to make the animation seem more life like in the simulation I had to set an offset in the starting point of the animation cycle so all the fish aren’t in perfect sync when they spawn. I also set the animation speed to multiplied by a fraction of the current velocity and the max velocity. This means that the animation speed set in the clip is the max speed the animation can be played at, giving me more control over how the simulation looks. All this code is kept in a single class assigned to each BOID:
animator = GetComponent<Animator>();
parentRb = GetComponentInParent<Rigidbody2D>();
maxSpeed = GetComponentInParent<Pilot>().speed;
//set animation playback start position
//calculate current velocity as a fraction of max velocity
float speed = parentRb.velocity.magnitude / maxSpeed;
//set animation speed multiplyier as fraction
And here is the result:
Next I need to create a sprite and animation for the predator tuna, since they are of the thunniform group this animation will have less head and body movement than the sardines. Next week I also aim to implement a UI that allows the user to change parameters within the simulation.