How to use images in ActionScript 3 with FlashDevelop (and some other AS3 tips)

update: I’ve created a new and updated tutorial on embedding images in FlashDevelop. I suggest you check out that tutorial instead of the one below. The new tutorial is cleaner, clearer and more up-to-date.

One of the main bumps you will run into when coding Sandy3D, or basically any kind of graphical applet is loading resources, such as images. If you are working inside Adobe’s Flash environment, this all comes pretty naturally. But open source tools such as FlashDevelop do not have a graphical component, so you have to create your multimedia assets in other applications (Paint.NET is nice).

Before you get started, have a look at this MovieClip vs Sprite comparison and this tutorial on starting with AS3 to understand why our base class extends Sprite and how events are handled. And if you want to know where all this is going, the idea is to recreate something similar to this in ActionScript 3 and FlashDevelop and then afterwards add some 3D goodness to it (3D objects, maybe 3D camera).

One important thing to know about event handlers is: don’t attach them to your main Sprite. This won’t work:

public class Test extends Sprite {
  public function Test() {
    graphics.lineStyle(1);
    graphics.beginFill(0xFF8000);
    graphics.drawCircle(50, 50, 10);
    addEventListener(MouseEvent.MOUSE_DOWN, down);
  }
  private function down(evt:MouseEvent):void {
    trace("down");
  }
}

My intuition was that it would attach mouse down events to the circle. But it does not. In most cases you would want to capture the whole sprite anyway. The solution is to add your listeners to the “stage” object. See the the examples below for a demonstration of this.

In Flash, images come in 2 types. Vector drawings or bitmaps. Pretty much all graphics you see on the Internet are bitmaps, every pixel in the bitmap is defined. A program such as Paint.NET will create those for you. Vector images are a different beast. Those images define the lines and forms that are used. In the example above, a circle is drawn, not a collection of points. The advantage is that the image quality will be a lot higher and it is possible to zoom in on the Flash applet without loosing quality. But (there always is a but) you can only draw those in the Adobe Flash editor. You can use existing .fla files with vector drawings in them, but you can’t make your own, unless you pay for the program. Either that or you would have to handcode everything. A future post will probably deal with that.

But this post deals with bitmaps. We will start from the following simple mouse-follow applet and replace the circle with a bitmap:

package  {
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.ui.Mouse;

  public class Test extends Sprite {

    private var circle:Sprite = new Sprite();

    public function Test() {
      Mouse.hide();

      circle.graphics.lineStyle(1);
      circle.graphics.beginFill(0xFF8000);
      circle.graphics.drawCircle(0, 0, 10);
      addChild(circle);

      stage.addEventListener(Event.ENTER_FRAME, mouseMove);
    }
    private function mouseMove(evt:Event):void {
      circle.x = mouseX;
      circle.y = mouseY;
    }
  }
}

This is the result:

I like to store all my resources in a separate directory, called “library“. It’s not a the “real” library that you have in the Flash IDE, but it’s close enough. I’m using this crosshair bitmap:

Once we have an image, it’s time to embed it. ActionScript 3 has an “Embed” tag that will allow you to put images in an applet. See this link for the complete explanation. Basically, you define a private Class variable, put the cursor just above it and double click on your image. FlashDevelop will automatically insert the correct “Embed” tag in your code. A little tweaking to get the correct size and there you are:

package  {

	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.ui.Mouse;

	public class Test extends Sprite {

		[Embed(source='library/crosshair.png')]
		private var crosshairClass:Class;
		private var crosshair:Bitmap = new crosshairClass ();

		public function Test() {
			Mouse.hide();

			crosshair.height = 30;
			crosshair.width = 30;
			addChild(crosshair);

			stage.addEventListener(Event.ENTER_FRAME, mouseMove);
		}

		private function mouseMove(evt:Event):void {
			crosshair.x = mouseX - 15;
			crosshair.y = mouseY - 15;
		}

	}

}

As you will notice, the quality of the scaled down image is not that good, but using a larger sprite allows you to zoom in with little quality loss. Next time, I’ll show you how to fix this.