Hey! I usually write ~techy 🤖 stuff~ on how I did effects and so on in my LD games (see here and here), like for these games:
LD39: SPACEJAMMED | LD38: Blomst 🌻 | LD37: Lock and reload
- | -
|
| 
This time around I made Mallio Cart. There wasn't that much focus on that kind of stuff, as the focus was mainly on the gameplay idea and content actually ended up somewhat lacking and empty in the end, altho this game too had its visual flair:
Of course this GIF has been heavily shrunk and optimised to fit this website's minuscule limit of 4MB, but you get the idea.

There's also a video if you just want to watch it:
https://www.youtube.com/watch?v=OsZ4hs6MYEQ
Crying BABBY visual and auditory effects
While I did at least make modifications to it, I didn't write the toon shader from scratch this time but found one. Perhaps the most elaborate graphical (and auditory) effect this time around was the one activated when too close to a crying 👶 bab(b)y:

To also hear the audio distortion that goes along with it, watch this video:
https://www.youtube.com/watch?v=iBBdr6mlmMM
Therefore, I thought we'd talk about that this time around! Since the audio stuff was sort of new to me, as someone who has mostly been focusing on having fun with graphics, I thought I might cover both this time, to see how the effects tie together and how they were done! c:
Visuals
This was made in Unity. I applied a post-effect, which is something I've written about before under getting depths in the second post on my LD39 game, SPACEJAMMED. This means a shader that is getting applied to the entire rendered image as a 2D effect after the whole scene has been rendered by the camera. Since all I needed to do was add some tinting, distortions and noise, I could do all of the relevant work in this shader.
If you're totally new to shaders, what it basically means in this particular case is some code where I can modify the colours of (or completely discard) the pixels (or "fragments") that are about to be drawn before they are drawn. I can basically "hook in" and modify them before they go to the screen. This way, for example, I can apply a tint. I can also accept input data which I can control through regular non-shader code, which is how I passed a noise texture into the shader as well as a number representing the level of distortion, so that I could fade it in instead of just toggling it on and off.
Tinting
Simplifying a bit, thus the tinting was no more complicated than something like this:
```
// Gets the colour from the image about to be rendered
// to screen at the current pixel/fragment as specified
// by the UV (texture coördinate) value passed to us.
// The 'fixed4' means a vector of four values, one for
// each colour channel (red, green, blue and alpha).
fixed4 col = tex2D(_MainTex, UV.xy);
// Increases the red channel by the distortion factor.
col.r *= 1.0 + _Factor;
// Pass the new colour of the picture on for rendering!
return col;
```
In reality the exact maths for tinting the right way looked a bit different and I also decreased the green and blue channels, but it's just something one has to play around with until it looks right!
Noise
Then there's what looks a bit like television static fading in as the effect increases. This is just a texture passed into the shader and added on top of the image, with a little bit of animation going on to make it appear all erratic and constantly changing, like real static. The technique was essentially the exact same as I used on the actual television set in my LD37 game, Lock and reload, as described here, so I won't really go over it again.
The only new thing was alpha compositing on top of the original image, which was done using the same old blending algorithm I've also described before under interpolation when talking about my LD38 game, Blomst 🌻!
Vignette
The edges around the screen also get darker (and redder) when this happens altho it can be hard to see with everything else that's going on. When a thief approaches, this is also the only effect that gets activated. This is simply done by tinting the pixels based on their distance from the middle of the image. We can get the position of the current pixel the same way we did when sampling the original texture in the code example under tinting, by reading the UV value, which is a pair of positions (x and y) between 0.0 and 1.0 and so the middle is at (0.5, 0.5). The function I use to calculate the "vignette factor" looks like this:
```
// Takes in two values (xy) and returns a single one.
fixed vignette(fixed2 pos)
{
// Just for clarity.
fixed2 middle = fixed2(0.5, 0.5);
// length() gives distance between two points.
return length(fixed2(pos.x, pos.y) - middle);
}
```
To calculate the vignette for any given pixel, which like anything else is also influenced by the distortion factor, I simply use it like so:
fixed v = vignette(UV.xy) * _Factor;
Then I simply combine this resulting value with the original pixel's colour channels in various ways to get the result I want, like increasing red and decreasing overall colour.
Di̶śto͝r̴t҉io̡n
Here's the big one! See how everything wobbles and waves around? It all comes back to those texture coördinates (UV's). By offsetting them a little bit, we can sample pixels further away from those that we are actually "supposed" to sample to get the original image and depending on how we offset them we can get the pixels to move around the way we want to.
I simply used sine waves for this. The function sin() returns a value between -1.0 and 1.0 depending on the value that is given to it, and just repeats the pattern over and over, creating a nice waveform:

Just by looking at the wave, I think it's already possible to see what we're getting at here. We can also use cosine, cos(), which does the same thing, but slightly offset.
So what we want to do is replace our old code for sampling the original texture, tex2D(_MainTex, UV.xy) with something a little more fancy, where UV.xy gets offset by some kind of value returned by the wave functions. For each pixel, we need to supply a different value to the function or else they will all get offset by the same amount and there won't really be any distortion, just the whole image shifted to the left or the right, up or down. So what easier value to use than the position of the pixel itself?
```
// x and y for the offset will be stored here.
fixed2 offset;
// Start by offsetting according to position.
offset.x = sin(UV.x);
offset.y = cos(UV.y);
// We also want to multiply by the factor to fade it in.
// This modifies x and y at the same time.
offset *= _Factor;
tex2D(_MainTex, UV.xy + offset.xy)
```
If you try this, you'll notice that the results are a bit wacky. Remember that UV's range from 0.0 to 1.0 and the wave functions from -1.0 to 1.0. This means the waves used here will ripple by the size of the entire image and create enormous distortions. So we'll have to tune that number down a lot:
offset *= 0.02;
Play with the number for desired results. You can also use different factors for x and y respectively.
Animating the distortion
Of course, this is completely static. The waves aren't moving, because the only input variable is the position of each pixel, and that never changes. So we need to introduce something that does. The easiest thing to do is use the runtime of the game, which is constantly updating. Unity gives us the built-in variable _Time which is actually four values (read details in the manual). The second value, y, is the actual time, so we'll use that. We'll have to stick it in the wave functions so we need to update those:
offset.x = sin(UV.x + _Time.y);
offset.y = cos(UV.y + _Time.y);
The time as is might move the waves too slowly (or fast!) for your tastes (it did for mine) so you may want to multiply the time by some factor for desired results. I multiplied by ten. Finally, you may find that the steps between each pixel passed into the wave functions are too small, since they'll only range from 0.0 to 1.0, so you may want to multiply those UV values by something quite large. My final code looked like this:
offset.x = sin(UV.x * 50.0 + _Time.y * 10.0);
offset.y = cos(UV.y * 40.0 + _Time.y * 10.0);
Audio
I'll cover this in the next post, not to make it too lengthy! Won't post that today since I don't want to be spammy, but if you're interested, look out for that! Have fun playing and rating more amazing LD games; I know I will! <3