For last weekend’s game jam, I needed to create a CRT-style glitch effect. The proper way to do this would be to use shaders — Unity, SpriteKit & all let you add custom shaders to game objects — but my engine does not (at the moment) support shaders, because the current version uses SDL to draw to the screen. I found a way around that may not look as good as it would have with shaders, but still works.
The code examples in the article use Meteor’s API (C++), but they are simple enough that they could be translated for SpriteKit, Cocos2D or other 2D engines with very little work.
The idea is to mix a colour overlay with fast screen shake to give the illusion that pixels are being drawn off-colour and slightly offset from their correct position. Most engines that I know of allow you to blend a scene’s texture with a colour, which is overlaid on the scene’s content.
So let’s set up a simple scene to work with. The
MyScene.hpp interface is quite simple, only a few method declarations there:
The implementation in
MyScene.cpp isn’t that much more complicated: each frame when the scene is glitching, we’ll change its position randomly and change its overlay a random colour from a list.
If we go through each function in the scene class:
We set up the scene. Nothing fancy here, we create a sprite from an image and add it to the scene tree, so that we have some content to show. Once we’ve done that, we reset the effect’s frame counter to
stepGlitch()is where the magic happens: we give the scene a random horizontal position (here, capped between
1), a random horizontal scale to simulate tearing, and overlay a colour picked at random from a pre-made list — ours contains a light red and a light green.
Once this is done, we decrement the frame counter, and if it reached
0, put the scene back in its normal place and scale and remove the overlay.
Here we listen for key presses. When the player presses the space bar, we set the effect’s frame counter to a value greater than zero to start the effect. Five frames seems to work well: longer and the effects would bother the player, shorter and it might be missed.
Before each frame is rendered (when
update(double)is called), we checked that the effect’s frame counter is positive, and if yes we call
stepGlitch()to render the effect.
Here’s the result once again, slowed down to show what’s going on a bit better:
In a real game, you would probably trigger the glitch some other way than by user input: random time interval, when the player dies — whatever suits your game. The result is not perfect, but it’s good enough to give the illusion that the game is glitchy. And now I’ll get back to learning OpenGL so I can avoid dirty hacks like this one.