Today, you will learn how to remove the background color from a sprite sheet using AS3, and blit the result to a bitmap canvas. Read on to learn more!
Final Result Preview
Let's take a look at the final result we will be working towards:
Step 1: Drawing the Spritesheet
So, it is time to draw your spritesheet. Open up your favourite 'pixel-art' program and create an image of 128x128 and give it a background colour of '#e731f2' which is a nice purple colour!
This is my amazing artwork:
Save your image somewhere organised and let us continue!
Step 2: Importing the Sprite Sheet
Now, I'm call this a sprite sheet even though it is just one image. A 'sprite sheet' usually consists of more than one sprite but we can imagine we have more, right?
Anyway, if you are using Flash CS4 or higher, simply import your image via File | Import | Import to Library:
If you are using any other AS3 IDE, I have included the SWC file so you should probably skip this step. If you wish to embed your own images, I'm sure that your IDE of choice will have this feature.
Step 3: Exporting the Sprite Sheet
We have now got our sprite sheet in the Library; we should really make it into a Class
.
Right-click the image in the library and select 'Properties'. Give the image the following properties:
Hit OK. If you get a warning, just ignore it; it does not matter here.
Step 4: Creating the Document Class
If you're not familiar with the concept of a document class, check out this Quick Tip before reading further.
Create a new 'ActionScript 3.0 Class' and give it the name 'Main'. When the file has been created, save it as 'Main.as'.
This code should be placed in our new Class:
package { import flash.display.MovieClip; public class Main extends MovieClip { public function Main() { // constructor code } } }
We are not done yet, however! If you are using the Flash IDE, navigate to the 'Properties Panel' and set the 'Document Class' to 'Main'. If you are wondering what that does, it means that when your application/game is run by the Flash Player, Main.as
will be the class that's linked to the SWF itself. Cool, huh?
Run the program; if you get no errors then you should be good to go!
Step 5: Creating the Canvas
Before we do any blitting, we will first need to make a canvas to blit onto. If you are unsure of the term Blitting or would like to learn more about it, please take a look at this tutorial.
Now, we will declare a new Bitmap variable, to which we will blit (copy) the image.
private var canvas:Bitmap;
After we have done this, we will add a function
called Initialize()
which will allow us to set everything up neatly:
public function Main() { Initialize(); }
Let us create the function now:
private function Initialize():void { canvas = new Bitmap( new BitmapData( 550, 400, false, 0x000000 ) ); //Sets the Canvas to Black. stage.addChild( canvas ); //Adds the canvas to the stage. }
We are still not finished however, as we still have to add the imports
:
import flash.display.MovieClip; import flash.display.Bitmap; import flash.display.BitmapData;
Run the program; if it has a black background, it worked!
Step 6: Initializing the SpriteSheet
Firstly, we will need to make a new variable of type SpriteSheet
- which was the Class for the image we imported earlier, remember?
private var canvas:Bitmap; private var spriteSheet:SpriteSheet;
We shall then initialize it:
private function Initialize():void { canvas = new Bitmap( new BitmapData( 550, 400, false, 0x000000 ) ); //Sets the Canvas to Black. spriteSheet = new SpriteSheet(); //Sets spriteSheet to hold an instance of the image that we made. stage.addChild( canvas ); //Adds the canvas to the stage. }
Run the program and you should see nothing; let's fix that right away!
Step 7: Updating the Program
Now we need to add an ENTER_FRAME
event. This will allow the program to update 24 times a second (24 FPS) in our case.
In the Main()
function, add the following line:
public function Main() { Initialize(); stage.addEventListener( Event.ENTER_FRAME, Update ); }
Now we need to make the Update()
function. Add this function after the other functions:
private function Update(e:Event):void { }
Don't forget the imports
:
import flash.display.MovieClip; import flash.display.Bitmap; import flash.display.BitmapData; import flash.events.Event;
Now we are ready to do some blitting!
Step 8: Blitting
Here comes the interesting part!
Alright, so what we want to do is:
- Clear the canvas.
- Blit the image and remove the background colour.
In the update function, type the following code:
private function Update(e:Event):void { canvas.bitmapData.lock(); canvas.bitmapData.fillRect( new Rectangle( 0,0,stage.width, stage.height ), 0x000000 ); canvas.bitmapData.copyPixels( spriteSheet, new Rectangle( 0,0,128,128 ), new Point( 100, 100 ) ); canvas.bitmapData.unlock(); }
If you run this, you will get your image on the canvas! However, this is not just what we are aiming for as we wish to remove that background colour from the image.
I shall explain some of the code above first:
-
canvas.bitmapData.lock();
- This line optimizes the blitting and it is a good habit to type it most of the time! -
canvas.bitmapData.fillRect();
- This line clears the canvas by filling it with a Black colour. -
canvas.bitmapData.copyPixels();
- Not very useful in our situation but copies all the pixels from part of an image. -
canvas.bitmapData.unlock();
- This works withlock()
to optimize the process.
Now you should have this on the screen...
Yes, I know, you are probably right. I think we should get rid of the purple too...
Step 9: Removing the Colour
Finally, it's time to remove the purple colour!
What we want to do is check through every pixel; if the pixel is purple, we simply do not copy it to the canvas. To do this, we will make our own function.
Change Update()
to the following:
private function Update(e:Event):void { canvas.bitmapData.lock(); canvas.bitmapData.fillRect( new Rectangle( 0,0,stage.width, stage.height ), 0x000000 ); CustomBlitting( spriteSheet, new Rectangle( 0,0,128,128 ), new Point( 100, 100 ), 0xE730F2 ); canvas.bitmapData.unlock(); }
Our new function (CustomBlitting()
, which we have not written yet) takes most of the parameters that copyPixels does, along with an extra one: the colour we wish to remove.
Time to write the function. This code may look complicated if you have never done a nested for-loop
before. The way this loop works is basically:
- For every row we have...
- Check every pixel in that row...
- Move to next row down...
private function CustomBlitting( src:BitmapData, srcRect:Rectangle, destPoint:Point, color:uint ):void { for( var i:int = 0; i < srcRect.height; i++ ) { for( var j:int = 0; j < srcRect.width; j++ ) { var currentPixel:uint = src.getPixel( srcRect.x + j, srcRect.y + i ); if( currentPixel != color ) { canvas.bitmapData.setPixel( destPoint.x + j, destPoint.y + i, currentPixel ); } } } }
Let me explain the getPixel and setPixel, although they should probably be self-explanatory:
-
getPixel( x, y );
- This returns the colour of a pixel at the X,Y location. -
setPixel( x, y, color );
- This sets the colour of a pixel tocolor
at the X,Y location of the canvas.
Now if you run the program, it works!
Step 10: Challenges
I only have one challenge for you to do for this tutorial:
Accept an Array of colours as a parameter and remove any colours from the image that are in the array.
Good luck!
Conclusion
I hope you have enjoyed this tutorial and have learnt something new today. If you'd like to show me your SWF with the completed challenges, leave a comment below!
Comments