Author Topic: Some Cool Filter Effects (from notsoftgames)  (Read 2403 times)

xhunterko

  • Contributor
  • ****
  • Posts: 449
  • Karma: +0/-0
    • View Profile
Some Cool Filter Effects (from notsoftgames)
« on: Sun, Jun 17, 2012 »
Hey guys!

In most of my games, I want to be able to help the player figure out what to do by having an item or object that they can interact with glow. Now flash can do this. Flixel doesn't seem to play nicely with flash's filters. However, a conversation was going on on twitter and I noticed another game's screen shot. Now, I don't know if the game was a one shot deal or not, but I assumed that it was and asked the guy if he was going to open source it. He said no at first. But then not only provided the classes, but went the extra mile and provided a working code example in a playstate. How cool is that? He also said it was okay to post these here as well.

A brief explanation is that these classes extend flxsprite and flxtilemap. This also means that you can have them extend photonstorm's FlxExtendedSprite as well. How cool is that? Anyways, here's a playstated example with a registry source file thing going on.

There's only one or two small issues. When he sent me the example swf, it didn't work. When I compiled the code into flash develop, it ran fine. I also noticed that the sprites seemed to be cut off at the top and bottom. There's probably an easy fix for this and I'll or someone smarter will figure it out later. Other then that. Enjoy!

Quick link:
http://t.co/4o6lUxjE

Filter Sprite:
Code: [Select]
package
{
import flash.filters.BevelFilter;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.GlowFilter;
import flash.geom.Point;
import org.flixel.FlxSprite;

import org.flixel.plugin.photonstorm.*;
/**
* ...
* @author bignobody
*/
public class FilterSprite extends FlxExtendedSprite
{
//Static filters, so we use the same filters for every FilterSprite
public static var FILTERS:Array;
public static var FILTERPOINTS:Array;
// Some named indexes to make this a little more human friendly
public static var FILTER_COLOR:int = 0;
public static var FILTER_GLOW:int = 1;
public static var FILTER_BLUR:int = 2;
public static var FILTER_BEVEL:int = 3;

// the filters currently affecting this sprite.
protected var activeFilters:Array;
protected var activeFilterPoints:Array;


public function FilterSprite()
{
if (FilterSprite.FILTERS == null)
{
// if the filters don't exist yet, make 'em!
FilterSprite.initializeFilters();
}

// initialize the arrays
resetFilters();

super();
}

public static function initializeFilters():void
{
FILTERS = new Array();
FILTERPOINTS = new Array();

// For the colour filter, I'm just turning the brightness down 50%, but you can do lots of crazy cool stuff with this filter.
var bright:Number = 0.5;
var matrix:Array = new Array();
matrix = matrix.concat([bright, 0, 0, 0, 0]); // red
matrix = matrix.concat([0, bright, 0, 0, 0]); // green
matrix = matrix.concat([0, 0, bright, 0, 0]); // blue
matrix = matrix.concat([0, 0, 0, 1, 0]); // alpha

FILTERS[FILTER_COLOR] = new ColorMatrixFilter(matrix);
FILTERPOINTS[FILTER_COLOR] = new Point( 0, 0);

// make the rest of our filters
FILTERS[FILTER_GLOW] = new GlowFilter(0xffffff, 1.0, 16, 16, 2, 1, false, false);
FILTERPOINTS[FILTER_GLOW] = new Point( -8, -8);
FILTERS[FILTER_BLUR] = new BlurFilter(4, 4, 1);
FILTERPOINTS[FILTER_BLUR] = new Point( -2, -2);
FILTERS[FILTER_BEVEL] = new BevelFilter(4, 45, 0xffffff, 1, 0, 0.75, 4, 4, 1, 1, "inner", false);
FILTERPOINTS[FILTER_BEVEL] = new Point( 0, 0);

}

public function resetFilters():void
{
// dump any references to existing filters
activeFilters = new Array();
activeFilterPoints = new Array();
}

public function activateFilter(filterType:int):void
{
if (filterType > -1 && filterType < FilterSprite.FILTERS.length)
{
// add the requested filter to this sprites active filters
activeFilters[activeFilters.length] = FilterSprite.FILTERS[filterType];
activeFilterPoints[activeFilterPoints.length] = FilterSprite.FILTERPOINTS[filterType];
}
}

// here's the Flixel integration!
// framePixels is the Bitmapdata that we can apply flash filters to.
// framePixels gets updated whenever the FlxSprite changes frames, so it seems like the best time to apply our filters
override protected function calcFrame():void
{
super.calcFrame();
if (activeFilters.length > 0)
{
// loop through all filters active on this sprite and apply them to the frame.
for (var i:int = 0; i < activeFilters.length; i ++)
{
if (framePixels != null)
{
// Apparently this is the inefficient way (internal copying), but if you want to add a seperate bitmap and handle it yourself, be my guest :D
framePixels.applyFilter( framePixels, framePixels.generateFilterRect(framePixels.rect, activeFilters[i]), activeFilterPoints[i], activeFilters[i]);
}
}
}
}

}

}

FilterTileMap:
Code: [Select]
package
{
import org.flixel.FlxTilemap;

/**
* ...
* @author bignobody
*/
public class FilterTileMap extends FlxTilemap
{
//Static filters, so we use the same filters for every FilterTileMap
// Alternatively, you could make a static Filters class that held a bunch of filter instances and use them everywhere...
public static var FILTERS:Array;
public static var FILTERPOINTS:Array;
// Some named indexes to make this a little more human friendly
public static var FILTER_COLOR:int = 0;
public static var FILTER_GLOW:int = 1;
public static var FILTER_BLUR:int = 2;
public static var FILTER_BEVEL:int = 3;

// active filters for this tilemap
protected var activeFilters:Array;
protected var activeFilterPoints:Array;

public function FilterTileMap()
{
if (FilterTileMap.FILTERS == null)
{
FilterTileMap.initializeFilters();
}
super();
resetFilters();
}

public static function initializeFilters():void
{
FILTERS = new Array();
FILTERPOINTS = new Array();

// For the colour filter, I'm just turning the brightness down 50%, but you can do lots of crazy cool stuff with this filter.
var bright:Number = 0.5;
var matrix:Array = new Array();
matrix = matrix.concat([bright, 0, 0, 0, 0]); // red
matrix = matrix.concat([0, bright, 0, 0, 0]); // green
matrix = matrix.concat([0, 0, bright, 0, 0]); // blue
matrix = matrix.concat([0, 0, 0, 1, 0]); // alpha

FILTERS[FILTER_COLOR] = new ColorMatrixFilter(matrix);
FILTERPOINTS[FILTER_COLOR] = new Point( 0, 0);

// make the rest of our filters
FILTERS[FILTER_GLOW] = new GlowFilter(0xffffff, 1.0, 16, 16, 2, 1, false, false);
FILTERPOINTS[FILTER_GLOW] = new Point( -8, -8);
FILTERS[FILTER_BLUR] = new BlurFilter(4, 4, 1);
FILTERPOINTS[FILTER_BLUR] = new Point( -2, -2);
FILTERS[FILTER_BEVEL] = new BevelFilter(4, 45, 0xffffff, 1, 0, 0.75, 4, 4, 1, 1, "inner", false);
FILTERPOINTS[FILTER_BEVEL] = new Point( 0, 0);

}

public function resetFilters():void
{
// dump any references to existing filters
activeFilters = new Array();
activeFilterPoints = new Array();
}

public function activateFilter(filterType:int):void
{
if (filterType > -1 && filterType < FilterTileMap.FILTERS.length)
{
// add the requested filter to this sprites active filters
activeFilters[activeFilters.length] = FilterTileMap.FILTERS[filterType];
activeFilterPoints[activeFilterPoints.length] = FilterTileMap.FILTERPOINTS[filterType];
}
}

// Here's the Flixel integration!
// drawTileMap stamps the visible section of the tilemap to the buffer, so we want to apply our filters right after that happens.
override protected function drawTilemap(Buffer:FlxTilemapBuffer, Camera:FlxCamera):void
{

super.drawTilemap(Buffer, Camera);

applyActiveFilters();
}

protected function applyActiveFilters():void
{
// _buffers is an internal array of FlxTilemapBuffer objects, which has the pixels we're filtering
for (var i:int = 0; i < _buffers.length; i ++)
{
if (_buffers[i] != null)
{
for (var f:int = 0; f < activeFilters.length; f ++)
{
_buffers[i].pixels.applyFilter(_buffers[i].pixels, _buffers[i].pixels.generateFilterRect(_buffers[i].pixels.rect, activeFilters[f]), activeFilterPoints[f], activeFilters[f]);
}
}
}
}
}

}

Filter State:
Code: [Select]
package
{
import org.flixel.FlxState;

/**
* ...
* @author bignobody
*/
public class FilterTestState extends FlxState
{

private var coins:Array;

public function FilterTestState()
{
coins = new Array();

for (var i:int = 0; i < 6; i ++)
{
coins[i] = new FilterCoin();
coins[i].y = 100;
coins[i].x = 20 + (i * 128);
add(coins[i]);
coins[i].play("spin");
}

coins[1].activateFilter(FilterSprite.FILTER_GLOW);
coins[2].activateFilter(FilterSprite.FILTER_BEVEL);
coins[3].activateFilter(FilterSprite.FILTER_BLUR);
coins[4].activateFilter(FilterSprite.FILTER_COLOR);
coins[5].activateFilter(FilterSprite.FILTER_BLUR);
coins[5].activateFilter(FilterSprite.FILTER_BEVEL);
coins[5].activateFilter(FilterSprite.FILTER_GLOW);
}

}

}

The resource file, coin file, and it's main file are easily understandable. But there are those in a nutshell. Also be sure and thank notsoftgames when you use them. I'd sure he'd appreciate it. Here's where you can do that:

Notsoftgames site:
http://www.notsoftgames.com/

Notsoftgames twitter:
https://twitter.com/notsoftgames
Now on twitter: http://twitter.com/xhunterko I made a game that's in alpha you can buy here: http://xhunterko.itch.io/wave-miner-alpha