Devlog #8 - Particles everywhere
So, big update for the development of Sound Horizons: the environments are done! All 6 layers have been designed, and they even are animated now. Let's first take a look at the last two new scenes.
Ending with epic
Last time we left with Layer 4, which was a dark and quiet one, preparing for the climax ahead. Well, here it comes now! Layer 5 is the last layer before the end of the level, and the most challenging one. I chose to make it red, it's a color that goes nicely with the environment, and it creates a tension that is appropriate for this part of the level. In the background, I used one of the early shader that I've made while experimenting with Shader Graph. I wanted to see how I could generate several shapes, randomize their positions, and deform them in interesting ways. I used this tutorial as an inspiration, and then fiddle with the different tools provided by Unity to see if I could obtain something interesting. It lead me into these kind of bubbles floating upwards with slight deformations. I initially thought it could be interesting particles for something on the floor, but eventually found out that they look really neat on the sky! I had them unused for a while, but now I can finally implement them in Layer 5. They have some issues though: they are placed on a grid, meaning that if you look closely you can see their alignment, and if they are too much deformed, they are cut out by their cell edges. Which mean I can't draw too many of them, and must use only a subtle deformation.
For the environment itself, I added basic particles that goes upward as well. While it makes the scene feels a bit more empty than the other, it conveys well the idea of something intense coming up. Since the game will be pretty challenging at this point, it's better for the background not to bee too much clustered with details.
Then comes Layer 6, which is a bit special: it's the layer that will be displayed after the player has beaten the level! There won't be any UI anymore, the player will just enter a free mode where they can play music just for fun. This means that I can use a bright color here, since there isn't the need to contrast with the game UI anymore! So I went with yellow, which offer a cool palette too. Then I added a large sun (or moon?) in the background. This element is actually something that I intend to use for a special event occurring between layers 5 and 6, and it will remains after because it creates a really great composition. Once again I used a shader to draw it. A bit overkilled you might say, but this allows me to easily animate its color, size and position. No assets used in this project, only procedural shaders! And finally I scattered some light rays in the environment. For someone who doesn't have the skill of an artist, they are something easy to model that I knew I could do. Just a tall cylinder, with an animation on their their scale. I eventually added some particles to them to make them feel less like pillars, and more like a force with a direction. What do they represent? Again, no idea, they just look neat.
Making abstract environments is pretty rewarding! I think this layer is one of the best looking. I'm glad it happens to be the last one, it's already a nice reward to the player by itself.
Next came the animations. And believe it or not, while making all these layers took me months, the work on the animations required less than two days!
Making the world alive
This is where my abstractions finally paid out! If you remember, there already were animations: while making the environments, I also implemented the animation between them. For example, this is how we go from layer 4 to layer 5:
For this, I developed an utility component called MaterialTween, which allows to transition from a Material to another with the same shader. This way I could write the look of each layers in separate materials, and then MaterialTween would interpolate the values of the animation by just changing the input parameters. It's not used for every elements of the game (the light spheres that you see above for example are moved and scaled by script), but still pretty frequently. It made working with shaders very easy!
So I intended to use the same tools for animating the impact of the notes. Whenever a note appears on screen, or the player hits them successfully, the environment should react to the action. Making it more connected to the game, and emphasizing the audio feedback.
Reacting to these events is easy. In the code, I already use events (UnityAction) to signal any change in the game's store, where all the logic data is kept. Any component can subscribe to these events to react accordingly. For example, when a "note" (in the abstract meaning) is added to the melody pool, an event is triggered. This makes the music player play the sound for the note, the UI bar draw the block and start to animate it, and the challenge manager register the game action and wait for the player's input in response. This way each component works independently, and are all synchronized with the same source of data! So for these animations to play, I just have to plug a new subscription to the events "Lead plays note" and "Player hits note".
However I made a slight variation in the logic structure. The way I handled the changes in the environment's layer was with an EnvironmentManager. Whenever the current layer changes, the EnvironmentManager would subscribe to the event, read the layer's configuration, and call the appropriate components to make them change. For example it would update the sky and fog color, then call the Cloud component to make it transition to a new Material, call the Water component to raise or lower it, etc. This lead to a large function with a lot of conditions, that would just call a single function on each component of the environment. Each time I wanted to add a new component, or a new transition, I had to update the EnvironmentManager. This is exactly the kind of thing I wanted to avoid! If I did the same for the note animations, I would have an even larger method with more conditions. This wouldn't be sustainable. So instead, I made environment components more independent by subscribing them directly to the events. They are now listening to the "Lead note" or "Player note" event, and each one individually decide how they react. The only condition they have is if they are visible or not. And even better: I wrote an abstraction of this logic directly on MaterialTween, which is used in a lot of places! For adding a new animation, now I just have to add it from the inspector, select the Material to use for the "peak" state of the animation, and configure on which layer it plays, and how long its fade in and fade out should be. Now you might understand why it was so quick: I barely had to code anything!
This doesn't mean that there wasn't any obstacle. Animating the material instance on several components required a bit of engineering, and animating particles, although very simple, was quite a challenge mostly because it is poorly documented. Also with all those elements on screen, mixing light, particles, and shaders, the game runs now less smoothly. Which is a real issue for a rhythm game! Shaders run on the GPU, so I suspect the main culprit to be either the particles (there can be a lot of them sometimes), or the mountains. Remember: these are drawn and updated by CPU! And now that I animate them more frequently (their movement give so much impact), I suspect that they're costing a lot. I might have to re-implement them, this time with a vertex shader!
Anyway, this is a great milestone that we passed! Now the environment is no longer a passive background, but really feels like it's part of the game.
The way forward
Finally after making the music and the art, I can move back to working on the game itself. There is one big feature that is yet missing: the end of the level. I have a special challenge in mind, that will alter a bit how the game works so far. But I need to implement it in a modular way, so that the game is still able to have several levels. Perhaps each with their own special ending challenge? It will be an interesting coding and design subject to face.
Also, as announced last year, I've started a video devlog to promote the game on Youtube! I published a first entry, where I present the game and explain its musical system. I've already cover some of this in the devlog on itch.io, but the video illustrates a bit better how the music works both in One Colorful Grid and Sound Horizons. Don't hesitate to subscribe to the channel if you find it interesting, I'd very much appreciate it!
Keeping both this channel active, as well as this devlog, while still working on the game, is unsurprisingly quite time consuming. Oh, and I also have another blog that I haven't updated in a while? The joy of having projects… I can't promise when the next update will be, but things are going very smoothly, and I'm making a lot of progress lately. So I hope I'll keep this momentum!
Get Sound Horizons
Sound Horizons
A procedural rhythm game with interactive music
Status | In development |
Author | Itooh |
Genre | Rhythm |
Tags | 3D, Atmospheric, Low-poly, Procedural Generation |
More posts
- Devlog #13 - One Colorful Shader7 days ago
- Colorful Grid Update22 days ago
- Accessibility Update75 days ago
- Sound Horizons is out today!87 days ago
- Devlog #12 - Score in a procedural worldJul 08, 2024
- Devlog #11 - Menus Part 2Jun 17, 2024
- Announce trailer and official store pagesJun 06, 2024
- Sound Horizons Beta is available for play-testApr 29, 2024
- Devlog #10 - Loops and circlesApr 03, 2024
- Devlog #9 - Shader recipe for low-poly mountains in UnityMar 15, 2024
Leave a comment
Log in with itch.io to leave a comment.