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:

var bar:tile = new tile("pathToImageOrBitmapDataObject", 100, 150);
     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:

bar.resize(20, 40);

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: , , , , ,

18 Responses to “Simple Tiling Sprite Class in AS3”

  1. Nice work, and very handy.

  2. Great! Gave me some ideas about creating a background tile class…

    package {

    /**
     * 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);
     */
  3. [...] Class is an extension of this class; http://blog.efnx.com/?p=25 [...]

  4. 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!

  5. 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);

    package nz.co.binarydesign.loaders{
        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);
  6. Thanks Michael!

  7. stage.setChildIndex(bkg,0); helped me

  8. Absolutely fantastic. Very useful abstraction.

  9. 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.

    package {

    /**
    * 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" );
  10. Great! Thanks.

  11. 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

  12. >>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.

  13. 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!!

  14. > 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.

  15. 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!

  16. 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

  17. 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.

  18. 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);

    }

    }

    }

Leave a Reply


Follow me on GitHub
Follow me on Google+
Follow me on Twitter
Thrilling.
EFNX is proudly powered by WordPress
Entries (RSS) and Comments (RSS).