Tuesday 5 June 2012

Custom Events

After a while I return to a subject that you certainly come over, again and again... at least I do.

Almost a year ago I made an article on how to make functions callbacks. You can read the article here.

Although I took too long to make a new article on this issue, I prefer this method to the callbacks. The reasons: efficiency and simplicity.

A big difference from normal events in AS3 like Events or MouseEvents is that you have several types of events in these two classes, but you cannot send anything else than... the event itself.

When you make a custom event, you can make it send any type of event defined by you... and as an extra, you can send data too.

So to start, define a new class. I name it CustomEvent (you can make a new folder to separate the classes in your application, just don't forget about the package), and it will extend the Event class in AS3:

package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
        }
    }
}

This is the base skeleton for the class. This will have the same behaviour as the base class Event. The 'type' of event will be determined  by just a unique string constant. You notice that I have included a 'data' parameter in the main constructor, and that this parameter is type '*' which means that it can hold any type of data.
So, the next is the same class with a bit more information:


package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
             super(type, bubbles, cancelable);
             this.data=data;
        }
    }
}

To make this class fully usable by Flash you need to override the clone method. This makes this listener to be forwarded to another listener. The clone method makes a direct copy of the object and returns it.
So, the class with the clone method:


package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
             super(type, bubbles, cancelable);
             this.data=data;
        }


        public override function clone():Event {
return new CustomEvent(type, data, bubbles, cancelable);
}
    }
}

The only thing missing is defining the events names. This can be any name, and are defined as public static strings, like this:


package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public static const EVENT_FIRED:String="Event_Fired";


        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
             super(type, bubbles, cancelable);
             this.data=data;
        }


        public override function clone():Event {
return new CustomEvent(type, data, bubbles, cancelable);
}
    }
}


That's it. Our Custom Event class is done. Now, how do I fire this?

As an example the next class will add a button to the display list. Once the user clicks in it, it will fire the 'EVENT_FIRED' event.


package{
    import flash.display.MovieClip;
    import flash.events.MouseEvents;
    import CustomEvent;
 
    public class AddButton extends MovieClip{
        private var myButton:MovieClip=new MovieClip();


        public function AddButton():void{
             this.addChild(myButton);
             myButton.addEventListener(MouseEvent.CLICK, onClick);
        }


        private function onClick(evt:MouseEvent):void {
dispatchEvent(new CustomEvent(CustomEvent.EVENT_FIRED);
}
    }
}


To caught this event you just listen this event as you normally would with any event.

One that is missing explanation is 'how do I send data with this, and how do I get it?'.

Glad you asked.

From the previous example imagine that when you click the button you want to send the string "custom event dispatched".

Replace the dispatchEvent to include this string, like this:
dispatchEvent(new CustomEvent(CustomEvent.EVENT_FIRED, "custom event dispatched");

When you listen to this listener you have to process the event for any data, like this:
...
public var anotherButton:AddButton=new AddButton();
...
anotherButton.addEventListener(CustomEvent.EVENT_FIRED, onAnotherClick);
...
private function onAnotherClick(evt:CustomEvent):void{
     trace(evt.data); //This will trace the string
}

It mihght feel confusing at the beggining but once you get the hang of this you'll throw the function callbacks... your back :)

Cheers.

Tuesday 17 January 2012

How to Format Text in Actionscript III

In the last article I've shown you a way to embed fonts in Actionscript. That process implies that you will have to embed the font on your compiled and final SWF file. This means that you final SWF will increase, and in some cases dramatically, because you are making the fonts you want to use available in your compiled code.

At this project that I'm working on, this is something we can't do, due to limitation on the hardware we're using. And beacuse the skinning of the application can change, so the fonts can be changed also.

For this purpose we use font embedding but, the fonts will be stored in external, and dedicated SWF files.

To start this process, a first step is to make a SWF file just for the font:
- Open a new FLA file in Flash;
- Place the following code in the first and empty frame of the timeline:

[Embed(source='ARIAL.TTF', fontName = 'Arial', mimeType="application/x-font", unicodeRange="U+0020-U+007E")]
var arial:Class;


Font.registerFont(arial);

This code is explained in the previous article. So if you came here directly and don't understand what's in here, just go there and see what this means.

This SWF will only have the embed characters you tell on the unicodeRange. So if you use any other characters with this font, they won't appear. So make sure your character range is correct.

Compile the file and place it on your local folder or in a "fonts" folder. In this case I will call it arial.swf.

To use this in your code just to simply something like this:
- In your AS3 class define a new Loader variable to keep to load the font:

private var fontLoader:Loader = new Loader();

- Load the font in the main constructor, or wherever it may suit your needs like this:

fontLoader.load(new URLRequest("sections/swfs/fonts/arial.swf"));

- After this, whenever you want to use the font in a textField you need to use the TextFormat to assign this font and change text appearance, like this:

var myText:TextField=new TextField();

myText.defaultTextFormat = new TextFormat("Arial", 38, 0x2DAAFD, true);
myText.selectable = false;
myText.text = "Hello World!";

NOTE: In the TextFormat, "Arial" is the name you gave the font in the Embed in the font SWF file.


This method makes easier to use and change fonts dynamically, for example defining a font to be used in a textField through an XML file.

Happy coding!


How to Format Text in Actionscript II

Some time ago I posted a way to format text using the fonts available in your system that you should, in the first place, import to your library and then use it on your code.

Meanwhile I had a new project where I was asked to come up with a way to use fonts. This project is to be embeded in a set top box, so there's a limitation about the fonts you can use. That's if the box has any available for you to use.

In this case there's no font I can use, so I have to "install" my fonts on the box in order to Flash to recognize them.
Another limitation is that the software can use a font, and I mean any font, that the Design department comes up with. This means that at some point I can have more or less fonts installed on the system. If we can't install fonts on the box, how can I use fonts as I please?

There's two possible answers for this:

One is using a Flex approach using the Embed tag. In you Actionscipt class, where you define your global variables put something like this:


[Embed(source='ARIAL.TTF', fontName = 'Arial', mimeType="application/x-font", unicodeRange="U+0020-U+007E")]
var arial:Class;

As a brief explanation:
- The source must be a font file already in your local folder;
- The fontName is the name you  will call in your code when you want to use the font;
- The mimeType is just something you have to write in order for the compiler to know that this is a font file;
- The unicodeRange is very important because it gives you the possibility of embedding just the characters you want in unicode. In this case "U+0020-U+007E" means a-Z (a to z in lower and uppercase).


For more details about the characters code to use, visit http://unicode.org/charts/ or http://www.rishida.net/tools/conversion/ that will make the conversion for you.


The var arial:Class must come after the Embed tag so that this font instantiated and can be used in the code you make.

For this you'll have to make a final step, which is: In the constructor of you class, register the font using this line of code
Font.registerFont(arial);

After this whenever you want to use this font just to something like this:

var myTextBox:TextField = new TextField();

myTextBox.defaultTextFormat = new TextFormat("Arial", 38, 0x2DAAFD, true);
myTextBox.selectable = false;
myTextBox.text = "My text in Arial";
addChild(challenge);


The "Arial" in new TextFormat("Arial", 38, 0x2DAAFD, true); is the name you gave to the font in the Embed tag, the rest is size, color and whether is bold or not.

The downside of this method is that if you want to use several fonts, you will have to embed them in the code, which mean that you will have to compile each time you change, add or delete a font from the code.

In my case this has to be more dynamic.

The next article will show how you can embed the font through a separate SWF file with the font in it. Just click here to go there.

Happy coding!