By Zevan | January 16, 2009
Actionscript:
-
[SWF(width=500, height=500, backgroundColor=0x000000, frameRate=30)]
-
-
// draw an ugly gradient
-
var size:int = 500;
-
var pixNum:int = size * size;
-
var gradient:BitmapData = new BitmapData(size, size, true, 0xFF000000);
-
-
gradient.lock();
-
var xp:int, yp:int;
-
for (var i:int = 0; i<pixNum; i++){
-
xp = i % size;
-
yp = i / size;
-
gradient.setPixel(xp, yp, (yp /= 2) <<16 | (255 - yp) <<8 | (xp / 2) );
-
}
-
gradient.unlock();
-
-
// draw an alphaChannel (radial gradient)
-
var radius:Number = 50;
-
var diameter:Number = radius * 2;
-
-
pixNum = diameter * diameter;
-
-
var brushAlpha = new BitmapData(diameter, diameter, true, 0x00000000);
-
var dx:int, dy:int;
-
var ratio:Number = 255 / radius;
-
var a:int;
-
-
brushAlpha.lock();
-
for (i = 0; i<pixNum; i++){
-
xp = i % diameter;
-
yp = i / diameter;
-
dx = xp - radius;
-
dy = yp - radius;
-
a = int(255 - Math.min(255,Math.sqrt(dx * dx + dy * dy) * ratio));
-
brushAlpha.setPixel32(xp, yp, a <<24);
-
}
-
brushAlpha.unlock();
-
-
// create a black canvas
-
var canvas:BitmapData = new BitmapData(size, size, true, 0xFF000000);
-
addChild(new Bitmap(canvas));
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void {
-
// draw the gradient onto the canvas using the alphaChannel (brushAlpha);
-
xp = mouseX - radius;
-
yp = mouseY - radius;
-
canvas.copyPixels(gradient,
-
new Rectangle(xp, yp, diameter, diameter),
-
new Point(xp, yp), brushAlpha, new Point(0,0), true);
-
}
This demo creates an airbrush that paints one BitmapData onto another. This is achieved by using the alpha related arguments of the BitmapData.copyPixels() function. If your not familiar with these you should take some time to play around with them... they're very powerful.
copyPixels() is the fastest way to draw in flash, so if you need speed, copyPixels() is the way to go. It's much faster than using draw().
Posted in BitmapData, setPixel | Also tagged flash |
By Zevan | January 15, 2009
Actionscript:
-
var currentState:String = "";
-
-
var functionList:Vector.<Function> = new Vector.<Function>();
-
-
function clearFunctions():void{
-
functionList = new Vector.<Function>();
-
}
-
function addFunction(f:Function):Function {
-
functionList.push(f);
-
return addFunction;
-
}
-
-
function removeFunction(f:Function):void {
-
for (var i:int = 0 ; i<functionList.length; i++){
-
if (f == functionList[i]){
-
functionList.splice(i, 1);
-
}
-
}
-
}
-
-
function runProgram():void {
-
-
currentState = "current: ";
-
-
for (var i:int = 0; i<functionList.length; i++){
-
functionList[i]();
-
}
-
-
trace(currentState);
-
}
-
-
function one():void{
-
currentState += " one";
-
}
-
-
function two():void {
-
currentState += " two";
-
}
-
-
function three():void {
-
currentState += " three";
-
}
-
-
function dot():void{
-
currentState += ".";
-
-
}
-
-
// test it:
-
addFunction(one);
-
addFunction(two);
-
addFunction(three);
-
-
runProgram();
-
-
removeFunction(one);
-
-
runProgram();
-
-
addFunction(dot)(dot)(dot);
-
-
runProgram();
-
-
clearFunctions();
-
-
addFunction(dot)(dot)(dot);
-
-
addFunction(three)(two)(one)(dot)(dot)(dot);
-
-
runProgram();
-
-
/* outputs:
-
current: one two three
-
current: two three
-
current: two three...
-
current: ... three two one...
-
*/
This is a very quick implementation of a pattern that I use sometimes. The idea of this pattern is very simple and can easily be implemented in OOP or procedural style programming. The idea is to have a Vector/Array of functions or Class instances. Loop through this Vector/Array and run each function (or a given method of each Class instance). During runtime your client code can alter this list to change what the program does.
I use this technique for games quite often. All enemies get added to an enemy list - this list is looped through and each enemies run() method is called. If an enemy dies it dispatches an event that tells the enemy manager to remove it from the list. Some pseudo code:
Actionscript:
-
function onMainLoop():void{
-
if (!paused){
-
-
runWorld();
-
runKeys();
-
runChar();
-
-
enemyManager.runEnemies();
-
-
runPickups();
-
-
}else{
-
// show pause screen
-
}
-
}
-
-
//... inside EnemyManager class
-
function onRunEnemies():void{
-
for (var i:int = 0; i<enemyList.length; i++){
-
enemyList[i].run(i);
-
}
-
}
I use the same technique for pickups (coins, lives etc....).
I first used this technique in Director with a list of parent scripts.
I'm aware of other more refined patterns that are meant to do similar things, but for small to medium sized apps this has worked very nicely for me.
Posted in Vector, arrays, misc | Also tagged flash |
By Zevan | January 15, 2009
Actionscript:
-
var size:Number = 400;
-
var pixelNum:Number = size * size;
-
var pixels:Vector.<uint> = new Vector.<uint>();
-
var r:uint;
-
var g:uint;
-
var b:uint;
-
-
var canvas:BitmapData = new BitmapData(size,size,false,0x000000);
-
addChild(new Bitmap(canvas));
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void {
-
-
canvas.lock();
-
-
// do any kind of pixel manipulation here:
-
-
for (var i:int = 0; i<pixelNum; i++) {
-
// draw a gradient that changes based on
-
// mouse position
-
r = i % size + mouseX;
-
b = i / size + mouseY;
-
g = (r + b) % mouseX;
-
pixels[i] = r <<16 | g <<8 | b;
-
}
-
canvas.setVector(canvas.rect, pixels);
-
//
-
-
canvas.unlock();
-
}
Using BitmapData.lock() and BitmapData.unlock() can speed up BitmaData drawing operations significantly. Simply lock your BitmapData before you draw to it, and unlock it when your done.
I often forget to do this until I get to the optimize phase of a project... but I think I'd like to get in the habit of doing it all the time....
By Zevan | January 14, 2009
Actionscript:
-
[SWF(width=400, height=400, backgroundColor=0xCCCCCC, frameRate=30)]
-
-
var canvas:BitmapData = new BitmapData(400, 400, true, 0xCCCCCC);
-
var eraser:BitmapData = new BitmapData(400, 400, true, 0x22CCCCCC);
-
addChild(new Bitmap(canvas));
-
-
var circle:Shape = Shape(addChild(new Shape()));
-
with (circle.graphics) beginFill(0x000000), drawCircle(0,0,20);
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
-
function onLoop(evt:Event):void {
-
canvas.copyPixels(eraser, eraser.rect, new Point(0,0), null, null, true);
-
circle.x = mouseX;
-
circle.y = mouseY;
-
-
canvas.draw(circle, circle.transform.matrix);
-
}
Create trails by slowly erasing the background with copyPixels(). The first time I ever saw this technique was back when setpixel.com contained a bunch of great director experiments by Charles Foreman (creator of iminlikewithyou.com).
At some point last semester I showed iminlikewithyou hamster battle to my undergrad students towards the end of class.... probably one of the funniest moments of that class.
Posted in BitmapData, misc | Also tagged flash |