Simple Tiling Sprite Class in AS3
Also known as “Developing a Pure AS3 GUI – Part 1.5 (tile)
Jump to Source
After writing last night’s class, scalingBars, I decided to make it a little easier on myself to tile bitmaps across the screen. I wrote a simple class that when given either a BitmapData object or a path to an image file (as a String), class will tile the image x pixels in width and y pixels in height. This is great for backgrounds or window bars or box sides, etc. Here’s the usage:
addChild(bar);
The previous code will grab an image from “pathToImage” [either relative or absolute, but remember security!] and then tile it 100 pixels wide by 150 pixels tall. Simple. Now let’s say you wanted to resize it:
That code will re-tile the image to 20 pixels by 40 pixels. Next on my list of upgrades is to allow reloading of different images. Shouldn’t be too hard.
Example
Source
tile Class Source Code
Tags: AS3, background, class, simple tile, tile, tiling background
November 22nd, 2007 at 7:32 pm
Nice work, and very handy.
December 23rd, 2007 at 12:50 pm
Great! Gave me some ideas about creating a background tile class…
/**
* Import required packages.
*/
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.events.*;
import flash.net.URLRequest;
/**
* Class definition.
*/
public class TileBG extends Sprite {
/**
* Class variables.
*/
public static var identifier:int;
public var bitmap:Bitmap = new Bitmap();
public var stageInstance:Stage;
/**
* Class constructor.
*/
public function TileBG(obj:*, stage):void {
identifier++;
name = 'bgSprite-' + identifier;
stageInstance = stage;
if(obj is BitmapData) {
bitmap.bitmapData = obj;
resize();
} else if (obj is String) {
var url:URLRequest = new URLRequest(obj);
var loader:Loader = new Loader();
configureListeners(loader.contentLoaderInfo);
loader.load(url);
} else {
throw new Error("Problem : First parameter obj must be a string \"path_to_image\" or bitmapData.");
}
stageInstance.addEventListener(Event.RESIZE, resize);
}
/**
* Configure the loader object events.
*/
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.COMPLETE, loaderComplete);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, loaderError);
}
/**
* Loader object complete event.
*/
private function loaderComplete(event:Event):void {
bitmap.bitmapData = Bitmap(event.target.content).bitmapData;
resize();
}
/**
* Loader object error event.
*/
private function loaderError(event:Event):void {
throw new Error("Problem : There was an error accessing the image file.");
}
/**
* Resize the background sprite to the stage size.
*/
private function resize(event:Event = null) {
graphics.beginBitmapFill(bitmap.bitmapData);
graphics.drawRect(0, 0, stageInstance.stageWidth, stageInstance.stageHeight);
graphics.endFill();
stageInstance.align = StageAlign.TOP_LEFT;
stageInstance.addChild(this);
}
}
}
/**
* Usage :
* var bg:TileBG = new TileBG(new tileBitmap(0, 0), stage);
* OR
* var bg:TileBG = new TileBG("http://localhost/images/tile.gif", stage);
*/
June 26th, 2008 at 9:22 am
[...] Class is an extension of this class; http://blog.efnx.com/?p=25 [...]
November 26th, 2008 at 12:43 am
Thank you for this class. Quick question…how do I prevent the tiled bitmap from being placed on top of my other objects on the stage? It seems to automatically go on top of everything…
Thanks!
February 19th, 2009 at 4:07 am
Here is a simple image class which can be used fairly modularly allowing tiling, stretching, smoothing
In reply to Alex’s question, try:
setChildIndex(bg, 0);
import flash.display.*;
import flash.events.*;
import flash.net.*;
public class Image extends MovieClip {
var filename:String;
var image_mc:MovieClip;
var image_loader:Loader = new Loader();
var tile_image:Boolean;
var image_smoothing:Boolean;
var image_width:Number;
var image_height:Number;
//Constructor to initate the object
public function Image(width:Number, height:Number, repeat:Boolean = true, smoothing:Boolean = true):void {
this.tile_image = repeat;
this.image_width = width;
this.image_height = height;
this.image_smoothing = smoothing;
image_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, finish_loading);
}
//method called to load a file from local or URL
//@param filename file to be loaded
public function load(filename):void {
image_loader.load(new URLRequest(filename));
}
//method to return an instance of the contentLoaderInfo for use with progress indicators outside the class.
//@return contentLoaderInfo
public function get_loader_info():LoaderInfo {
return image_loader.contentLoaderInfo;
}
//method called the image loading is complete.
//sets up the tiling if that flag is set in thne constructor
//@param e LoaderEvent
private function finish_loading(e:Event):void {
if (tile_image) {
//if the tiling flag is set, insert multiple instances of the image
//create mc to house tiles
var tiles:MovieClip = new MovieClip();
var tile:Bitmap = get_image_instance();
//calculate how many tiles required horiz / vert
var vert_required:Number = image_width / tile.width
var horiz_required:Number = image_height / tile.height
//increment through both horizontal and vertical repitions until area is filled/overflowed
for(var vert_inc=0; vert_inc < vert_required; vert_inc++){
for(var horiz_inc=0; horiz_inc < horiz_required; horiz_inc++){
//get_image_instance creates a new instance of the image
tile = get_image_instance();
tile.x = tile.width * horiz_inc;
tile.y = tile.height * vert_inc;
tiles.addChild(tile);
}
}
//create mask to hide unwanted overlap of tiles if nuimber of tiles required is not an exact multiple
var mask_mc = new MovieClip();
mask_mc.graphics.beginFill(0);
mask_mc.graphics.drawRect(0,0,image_width,image_height);
mask_mc.graphics.endFill();
//apply the mask to the tiles
tiles.mask = mask_mc;
addChild(tiles);
} else {
//if no tiling, just add one instance of the loaded image
var im:Bitmap = get_image_instance();
im.width = image_width;
im.height = image_height;
addChild(im);
}
}
//method to return an instance of the loaded image for use within the class.
//this is required mainly dfor the tiling option as there are no simple ways to duplicate a display object
//@return bitmap object
private function get_image_instance():Bitmap {
//create a bitmap data object to house the image
var bmd = new BitmapData (image_loader.width, image_loader.height, true, 0);
//create a bitmap render of the loaded image
bmd.draw(image_loader);
return new Bitmap(bmd, "auto", image_smoothing);
}
}
}
// usage:
// import nz.co.binarydesign.loaders.Image;
// var tiled_bg:Image = new Image(400, 500, true)
// stripe_bar.load("stripes.png");
// addChild(stripe_bar);
February 19th, 2009 at 12:38 pm
Thanks Michael!
March 2nd, 2009 at 7:45 pm
stage.setChildIndex(bkg,0); helped me
June 4th, 2009 at 2:53 pm
Absolutely fantastic. Very useful abstraction.
November 2nd, 2009 at 6:19 am
Found a bug with Ringo’s class, when it resized, it litterally was stacking backgrounds ontop.
Also added a blendmode option. for more complex and layered backgrounds. nothing too advanced but possibly useful.
/**
* Import required packages.
*/
import flash.display.Bitmap;
import flash.display.Shape;
import flash.display.BlendMode;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.events.*;
import flash.net.URLRequest;
/**
* Class definition.
*/
public class TileBG extends Sprite {
/**
* Class variables.
*/
public static var identifier:int;
public var bitmap:Bitmap = new Bitmap();
public var stageInstance:Stage;
public var _blendMode:String;
public var child:Shape;
/**
* Class constructor.
*/
public function TileBG(obj:*, stage, blend:String):void {
identifier++;
_blendMode = blend;
name = 'bgSprite-' + identifier;
stageInstance = stage;
if(obj is BitmapData) {
bitmap.bitmapData = obj;
resize();
} else if (obj is String) {
var url:URLRequest = new URLRequest(obj);
var loader:Loader = new Loader();
configureListeners(loader.contentLoaderInfo);
loader.load(url);
} else {
throw new Error("Problem : First parameter obj must be a string \"path_to_image\" or bitmapData.");
}
stageInstance.addEventListener(Event.RESIZE, resize);
}
/**
* Configure the loader object events.
*/
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.COMPLETE, loaderComplete);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, loaderError);
}
/**
* Loader object complete event.
*/
private function loaderComplete(event:Event):void {
bitmap.bitmapData = Bitmap(event.target.content).bitmapData;
resize();
}
/**
* Loader object error event.
*/
private function loaderError(event:Event):void {
throw new Error("Problem : There was an error accessing the image file.");
}
/**
* Resize the background sprite to the stage size.
*/
private function resize(event:Event = null) {
if(child != null){
stageInstance.removeChild(child);
}
child = new Shape();
child.graphics.beginBitmapFill(bitmap.bitmapData);
child.graphics.drawRect(0, 0, stageInstance.stageWidth, stageInstance.stageHeight);
child.graphics.endFill();
stageInstance.align = StageAlign.TOP_LEFT;
stageInstance.addChild(child);
child.blendMode = _blendMode;
}
}
}
var bg:TileBG = new TileBG("pattern1.png", stage, "difference" );
November 2nd, 2009 at 9:12 am
Great! Thanks.
December 18th, 2009 at 6:39 am
Thanks for this class.
I have gotten brndn’s version working but am still having trouble getting the tiled image not to go on top of everything.
I tried various versions of setChildIndex(bg, 0); and I can get it to go behind everything, but I cann’t seem to get it to layer in the middle of several movie clips.
I’ve tried the setChildIndex(bg,numChildren – 1); technique doing the same to the other movie clips to control the order but it doesn’t work. Any ideas? cheers
December 18th, 2009 at 10:36 am
>>pixteur
Well, it’s been a very long time since I first wrote the class, but, you should be able to treat it just like any other Sprite (though I’m not sure about the other classes in the comments). I’m sorry if this sounds trite: when you are adding your DisplayObjects to the Stage, just make sure you add them in a way that you can keep track of the order. It’s easiest just to keep all of your calls to addChild() in a block. Put the addChild() call for the tile in the middle, then you’ll know the tiling is in the middle of the display list. You must also be aware that if you’re tiling a completely opaque tile and stretching the tile to the full stageWidth and stageHeight of the flash window, you won’t see anything that might be behind the tile.
February 24th, 2010 at 4:44 am
Hi I am a newbie in action script and Im glad I found this class that really helped much. I had encountered some problems using this class, I tried to preload the background before the next image appears resulting to an error
“Access of possible undefined property contentLoaderInfo through a reference with static type com.efnx.GUI:tile.”
here is my code
stop();
import flash.display.*;
import flash.geom.Rectangle;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.net.URLRequest;
import flash.display.Loader;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.display.BitmapData;
import gs.plugins.*;
import gs.TweenLite;
import gs.easing.*;
import gs.*;
import com.efnx.GUI.*
var BlackPattern:tile = new tile(“images/blackpattern.png”, 1955, 1024);
addChildAt(BlackPattern,0);
var BlackPatternXPos:Number = swfWidth – 1955;
var BlackPatternYPos:Number = swfHeight – 1024;
BlackPattern.x = BlackPatternXPos / 2 ;
BlackPattern.y = 0;
var BlackPattern2:tile = new tile(“images/blackpattern.png”, 1955, 1024);
addChildAt(BlackPattern2,2);
BlackPattern2.alpha = .7;
var BlackPattern2XPos:Number = swfWidth – 1955;
var BlackPattern2YPos:Number = swfHeight – 1024;
BlackPattern2.x = BlackPattern2XPos / 2 ;
BlackPattern2.y = 0;
BlackPattern2.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
var beam:tile = new tile(“images/beam.png”, 1280, 1150);
function onComplete(ev:Event):void
{
addChildAt(beam,1);
}
beam.alpha = .8
var beamXPos:Number = swfWidth – 1280;
var beamYPos:Number = swfHeight – 1150;
beam.x = beamXPos/2;
beam.y = 0;
Honestly Im not sure if im doing it correctly, is there other way where i could load the “blackpattern1″ and “blackpattern2″ before loading the “beam”
thank you so much.
Great AS3 Class!! very helpful!!
February 24th, 2010 at 6:14 pm
> Miggy
Your problem is that my class doesn’t expose a member named ‘contentLoaderInfo’ – which is definitely a design flaw, as the class is loading an image. You could change line 54 to read ‘public var loader:Loader = new Loader();’ and then in your code use ‘BlackPattern2.loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);’ or you could just do ‘addChild(beam, 1);’ without the onComplete event. The image does not have to be loaded to add the tile to the stage.
February 25th, 2010 at 12:30 am
Thanks so much Schell, i will try that tonight.
by the way may i ask whats the use of “public” in ‘public var loader:Loader = new Loader();’ i know its kinda off topic and im very sorry for the dumb/noob question. I have so much to learn in AS3, it cool to learn new things.
thanks a lot!
February 25th, 2010 at 9:10 am
The public, protected, private and internal keywords denote variable access. Here’s a quick article describing each: http://greenethumb.com/article/27/public-private-protected-internal-access-modifiers-in-as
December 7th, 2010 at 2:35 am
If you struggling with the bg tile image appeared on top of your other movieclips add this to brndn’s class:
stageInstance.setChildIndex(child,0);
add to line 79, after
stageInstance.addChild(child);
Hope that helps.
February 17th, 2011 at 12:18 pm
hi………… I just want to make a class which draw line whenever i called Line() function . Here is the code I hv written…… but it gives blank screen Please Help me………….. (It works if I directly paste the code of Line () function on Frame i.e without using class)
/*Action Frame code……..*/
new Line();
/*class script………..*/
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.*
import flash.geom.Point;
import flash.events.*;
import flash.utils.*;
public class Line extends Sprite {
public var canvas:Sprite = new Sprite();
public function Line ():void{
canvas.graphics.lineStyle(5, 0xFF0000, 1);
canvas.graphics.moveTo( 10 , 10 );
canvas.graphics.lineTo( 300 , 300 )
addChild(canvas);
}
}
}