Sometimes you want to be able to keep your fonts in a seperate swf file, a “font library” if you will, that you can load dynamically on runtime. Here’s how to do that in AS3:
The first thing you have to do is create a new flash file to store the font(s). Then, right click the library and select “New Font…”.
Choose the font you want to embed and give it a name. Any name will do here, as this is only the library name and will not affect our code in any way. I prefer to name the font with the same name as the linkage name I plan to give it.
Click ok, and then right click the font in the library and select “Linkage…”. Check the “Export for ActionScript” and “Export in first frame” options, give your font the linkage name of your own liking and click OK.
And now you’re ready. Export the file to swf and there’s your font resource file.
If you want to use that font, you first have to load it into the application domain, and then register it on the global font list using the Font.registerFont function. The textfield can’t display it until it has the embedFonts property set to true and the font name in its textformat.
You can see an example in the following code, ready to be pasted into your frame:
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
l.load(new URLRequest("MyFont.swf"), new LoaderContext(false, ApplicationDomain.currentDomain));
function onLoaded(e:Event):void {
// Register the font to the global font list
Font.registerFont( Class( ApplicationDomain.currentDomain.getDefinition("MyFont")));
myTextField.embedFonts = true;
// instantiate the font just to get the real font name, or if you know the name before hand you can just hard-code it in here
var fontName:String = new (ApplicationDomain.currentDomain.getDefinition("MyFont"))().fontName;
var tf:TextFormat = new TextFormat(fontName);
// Set the text format for the text already in the text field
myTextField.setTextFormat(tf);
// and for future changes
myTextField.defaultTextFormat = tf;
}
function intersection(p1:Point, p2:Point, p3:Point, p4:Point):Point {
var x1:Number = p1.x, x2:Number = p2.x, x3:Number = p3.x, x4:Number = p4.x;
var y1:Number = p1.y, y2:Number = p2.y, y3:Number = p3.y, y4:Number = p4.y;
var z1:Number= (x1 -x2), z2:Number = (x3 - x4), z3:Number = (y1 - y2), z4:Number = (y3 - y4);
var denominator:Number = z1 * z4 - z3 * z2;
// If denominator is zero, there is no intersection
if (denominator == 0) return null;
// Get the x and y
var pre:Number = (x1*y2 - y1*x2), post:Number = (x3*y4 - y3*x4);
var x:Number = ( pre * z2 - z1 * post ) / denominator;
var y:Number = ( pre * z4 - z3 * post ) / denominator;
// Check if the x and y coordinates are within both lines
if ( x < Math.min(x1, x2) || x > Math.max(x1, x2) ||
x < Math.min(x3, x4) || x > Math.max(x3, x4) ) return null;
if ( y < Math.min(y1, y2) || y > Math.max(y1, y2) ||
y < Math.min(y3, y4) || y > Math.max(y3, y4) ) return null;
// Return the point of intersection
return new Point(x, y);
}
There are alot of ways to shuffle an array in AS3, ranging from swapping repeatedly the elements to using the sort function with a random sorter, but the most convenient (and the fastest*) way I’ve found was to simply splice a random element from the former array to the new shuffled array while the former array has elements.
var arr2:Array = [];
while (arr.length > 0) {
arr2.push(arr.splice(Math.round(Math.random() * (arr.length - 1)), 1)[0]);
}
*Edit: Did a speed test with other methods found online, so far this is the fastest method (by far) I can find. Please comment if you find a faster one.
When creating pure AS3 projects a metadata is required to define how the swf functions. This metadata is inserted after your import statements and before the main class definiton.
Here are the parameters you can use with the swf metadata tag:
I’ve just been tasked with creating a function to get the intersection of two lines.
With the help of equations from Wolfram Mathworld I created this nifty function:
Point* intersection(Point p1, Point p2, Point p3, Point p4) {
// Store the values for fast access and easy
// equations-to-code conversion
float x1 = p1.x, x2 = p2.x, x3 = p3.x, x4 = p4.x;
float y1 = p1.y, y2 = p2.y, y3 = p3.y, y4 = p4.y;
// Get the denominator
float denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
// If denominator is zero, there is no intersection
if (denominator == 0) return NULL;
// Get the x and y
float pre = (x1*y2 - y1*x2), post = (x3*y4 - y3*x4);
float x = ( pre * (x3 - x4) - (x1 - x2) * post ) / denominator;
float y = ( pre * (y3 - y4) - (y1 - y2) * post ) / denominator;
// Check if the x and y coordinates are within both lines
if ( x < min(x1, x2) || x > max(x1, x2) ||
x < min(x3, x4) || x > max(x3, x4) ) return NULL;
if ( y < min(y1, y2) || y > max(y1, y2) ||
y < min(y3, y4) || y > max(y3, y4) ) return NULL;
// Return the point of intersection
Point* ret = new Point();
ret->x = x;
ret->y = y;
return ret;
}
Hope it will be to as good use to you as it is to me.
[Edit 28. May '09] I removed a bug in the function that was causing false negatives, it works perfectly now.
The ApplicationDomain class in Actionscript 3 is a really handy class. It allows you to get any class from a loaded (or the current) swf and instantiate it.
ApplicationDomain currently has two public methods, hasDefinition(name:String):Boolean and getDefinition(name:String):Object. The simplicity of using these classes is a real treat, instantiating a class is as easy as
var myInstance:DisplayObject = new
(ApplicationDomain.currentDomain. getDefinition("com.flassari.MyClass"));
The biggest pain about the ApplicationDomain class is however its lack of a function for displaying all of the classes in a particular ApplicationDomain.
ApplicationDomain.getAllDefinitions():Array would be great! But unfortunately we must find our own way of getting around this flaw… so here it is!
I give you, the SwfClassExplorer class. Its usage is simple, as it has only one static function, getClasses(bytes:ByteArray):Array. To use it you must provide it with the bytes of the swf clip you want to explore. Here is an example of basic usage:
public function init():void {
// Load the swf
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onSwfLoaded);
urlLoader.load(new URLRequest("pathToSwf"));
}
private function onSwfLoaded(e:Event):void {
// Get the bytes from the swf
var bytes:ByteArray = ByteArray(URLLoader(e.currentTarget).data);
// And feed it to the SwfClassExplorer
var traits:Array = SwfClassExplorer.getClasses(bytes);
for each (var trait:Traits in traits) {
trace(trait.toString()); // The full class name
}
}
I’ve prepared an example to demonstrate how it works.
First we have the Primitives.swf file. It will act as our “MovieClip library”. Its library consists of four movieclips, Box, Circle, Polystar and Triangle, each with its linkage class set to its library name:
Next we have the Example.swf file. It loads any swf file (Primitives.swf is in the path box by default) and lists all of the classes found in it. If the user clicks any of the classes, it will try to instantiate the class using no parameters (exceptions will be caught and displayed to the user) and if is or extends DisplayObject it will display it in the preview area.
I wanted to share with you some takes that didn’t make it into the final version of Iceland Socks. When you mix the good people of Gogogic with beverages and sock puppets you’ll end up with more outtakes than usable footage.
Enjoy