Posted March 13, 2021 by bulboka
#graphics
This is a little dive into technical aspects of how I've made the visuals in I'm Safe jam game. Most of these approaches can be called tricks and quite hacky ones. I'm sure there are more effective and optimized ways to achieve effects like this and make them better. Nevertheless!
Another game developer from Brackeys Game Jam CinemaLeo called it "feedback/delay", which sounds pretty great to me. I first tried this effect some time ago for a different project. Originally it was an attempt to mimic the particular style of animation, when previous frames aren't disappearing immediately but are like erased gradually leaving some kind of dirt in the path of moving objects. It didn't quite work, yet the effect itself seemed good to me.
This is, how I do it:
It all works for meshes too, yet of course with some peculiarities. The 4-th point about "white" background sprites is inapplicable to meshes. And you have to place the "eraser" sprite far from the camera if you want it to be rendered behind meshes or vise versa very close to the camera if you want it in front. In the last case it'll also add an animated overlay to meshes only.
There is a large space for experimentation. For example with eraser's color or with animation of any component of the system.
I think there are more advanced approaches to this effect, using render textures for example. It could give more control and possibilities to deform trails.
Also is quite messy. For it I wrote a component which I add to every mesh, I want to have this effect. On start the component is saving a copy of the array of mesh's UV coordinates. Later on every random period of time it runs through all the mesh's vertices and sets their UV coordinates as original plus some random shift. That's all! It's quite unoptimized and probably will add a visible lag in the scene with lots of complex meshes. Stopping the effect for meshes far from the camera could be an option. But surely the best way is to write a shader which will mutate UV coordinates on a timer using a noise texture.
I also made a component which wobbles not only UV coordinates but also the positions of vertices. Later I turned it off. And of course it also can be done better with a shader.
I've made a simple animation of tree swinging. Just some rotations back and forth around the pivot near the tree's root.
In Start method each tree is choosing a random sprite, scale and speed of animation, which is set in the Animator component as a flow parameter. This way, while designing a level I can make all the trees the same and have only one swinging animation, yet in runtime it looks pretty diverse.
Each tree has a small sphere collider near its root which serves as an obstacle for the player and the birds.
It also has a big collider set up as a trigger. In OnTriggerEnter it adds a constant value to the Animator's animation speed float parameter. In Update method animation speed is slowly reduced until it reaches the value chosen on start. This way, when the player or a bird is moving near a tree it starts swinging faster. If several birds pass by, a tree's swinging speed rises more and more, until it reaches the maximum value. Then it slowly calms down. The animation itself is never changed, so everything is smooth, without abrupt transitions. Also a random tinkle sound is played with slightly random volume and pitch.
I've made a Forest component to generate forests. It has a single tree template object and a BoxCollider2D component to define its bounds. Collider is disabled on start, it's just a way to define a rectangle in the world space from the editor. The generation algorithm is simple: trees are instanced on a regular grid inside defined bounds and every tree position is randomly adjusted a little.