Retro CRT distortion effect in Flixel 2.5

A couple of weeks ago I started using the Flixel Framework, a set of class and libraries in ActionScript3 to effectively design videogames in Flash. Flixel is suggested to all the programmers who want to create games with a retro-style flavour. Although there is a huge support community that actively works on Flixel, finding the right effect is not always easy. After looking for few hours desperately trying to find a way to implement a CRT distortion effect, I decided to create it myself! The result is a class called “RetroEffect“.

The inspiration for this work comes from a great article by Cadin Batrack, calledย  “Create a retro CRT distortion effect using RGB shifting“. Although, the version I create is integrated to Flixel 2.5, and has several performance improvements that makes is lighter to execute with a high framerate. In old CRT monitors, the image is composite using three different colour layers. When they are not perfectly synchronised, the result is something like this one:

Retro CRT distortion effect by Cadin Batrack

The way this effect is implemented consists in extracting the red, green and blue channel from the original image and re-drawing them a little bit distorted. The solution proposed by Cadin Batrack uses the Tweener library. Despite its being really effective, is also extremely heavy and its usage is not advisable where performance should be an issue. I used a very light version that simply cause the channel to “oscillate” following a sinusoidal path. The effect does not reach the same yeah-yeah level of awesomeness, but it can be a good base for further versions.

The code that does the trick is;

[sourcecode language=”as3″]
&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
// Red channel ——————————————&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.fillRect(source.rect, 0xFF000000);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.copyChannel&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
( ย  source, source.rect, _zeroPoint,&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
BitmapDataChannel.RED, BitmapDataChannel.RED );&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_bitmap.alpha = randRange(8, 10) / 10;&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;_distortion.a = sinusoid(_counter + 0 / 5, 0.99, 1.00 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_distortion.d = sinusoid(_counter + 2 / 5, 1, 1.01 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_output.draw(_bitmap, _distortion, null, null, null, true);&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;// Green channel ——————————————&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.fillRect(source.rect, 0xFF000000);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.copyChannel&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
( ย ย source, source.rect, _zeroPoint,&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_bitmap.alpha = randRange(8, 10) / 10;&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;_distortion.a = sinusoid(_counter + 1 / 5, 0.99, 1.00 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_distortion.d = sinusoid(_counter + 1 / 5, 1, 1.01 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_output.draw(_bitmap, _distortion, null, BlendMode.SCREEN, null, true);&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;// Blue channel ——————————————&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.fillRect(source.rect, 0xFF000000);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.copyChannel&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
( ย  source, source.rect, _zeroPoint,&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
BitmapDataChannel.BLUE, BitmapDataChannel.BLUE );&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_bitmap.alpha = randRange(8, 10)/10;&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;_distortion.a = sinusoid(_counter + 2 / 5, 0.99, 1.00 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_distortion.d = sinusoid(_counter + 0 / 5, 1, 1.01 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_output.draw(_bitmap, _distortion, null, BlendMode.SCREEN, null, true);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
[/sourcecode]

Colour channels are copied into “_buffer“, and all the drawing operations are made into a temporary “BitmapData” called “_output“. The sinusoid curve is feed with a counter “_counter” that indicates the number of seconds elapsed from the beginning of the game. You can play with the matrix parameters to obtain different types of effects.

The usage of this class is quite easy. It must be added as a normal sprite, specifying the camera that will be rendered with the retro CRT distortion effect. In the example below, the standard camera has been used.

[sourcecode language=”as3″]&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
var retroEffect : RetroEffect = new RetroEffect(FlxG.camera);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
add(retroEffect);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
[/sourcecode]

You can download the “RetroEffect” class compatible with Flixel 2.5 from here.

Comments

6 responses to “Retro CRT distortion effect in Flixel 2.5”

  1. A useful symbol collection should make selection easier, not turn a short bio into a formatting project. Grouping characters by mood and use case helps people compare options quickly, especially when they need a subtle separator, a recognizable marker, or a compact accent. bio symbols work best when they support the words already there and do not make a profile harder to read, copy, or understand at a glance.

  2. A simple online timer can be more useful when it removes the usual distractions: account creation, advertising, and complicated settings. Support for hours, minutes, and seconds makes it suitable for focused work, study sessions, cooking, exercise, or short breaks. Start, pause, resume, and reset controls cover the essential workflow, while an end sound lets people step away from the screen. A clean browser interface also makes the tool easier to use across different devices.

  3. Using an approximation sign well is partly a communication decision. Readers should be able to tell whether a number was rounded, estimated, measured, or derived from a model. A short note about precision can be more informative than adding extra decimal places. In typeset work, LaTeX approximately equal notation is especially useful when the same expression must remain clear in articles, slides, and reproducible source files without depending on manual formatting.

  4. David T. Marchand avatar
    David T. Marchand

    Thanks! I already looked for it when I saw I needed it to run this. It looks good, a very simple project can really improve its looks so much with just a little effect like this.

  5. David T. Marchand avatar
    David T. Marchand

    AWESOME! I’m gonna use this baby for sure. True, Batrack’s looks prettier, more random and broken, while yours is one same pattern over and over again. But I’m using this just for 1 second, every five seconds or so, and it looks GORGEOUS.

    One thing: I had to add the randRange function, is there a reason why you didn’t put it in the class? Not complaining or anything, it’s just this one detail that would make this class really copy-paste-use.

  6. Francesco avatar

    ๐Ÿ˜‰

Leave a Reply

Your email address will not be published. Required fields are marked *