Archive for the ‘actionscript’ Category

Nested Functions

Monday, January 11th, 2010

As most Flash developers are aware Actionscript 3 supports nested functions. This essentially allows you to have functions within functions… within functions etc. This gives rise to an interesting set of opportunities and pitfalls.

This post won’t go into the pitfalls which are basically variable scope and garbage collection, there are plenty of posts on the net that focus on these two topics, google can help you find them. The purpose of this post is to show how clever use of nested functions can simplify your code.

To illustrate appropriate use of nested functions I am going to use the following example. We have the following data structure:


var data:Array = [
{
image:"img01.png",
link:"http://site1.com"
},
{
image:"img02.png",
link:"http://site2.com"
},
{
image:"img03.png",
link:"http://site3.com"
},
{
image:"img04.png",
link:"http://site4.com"
}
];

Our objective is to load the images, place them on the stage and when the user clicks on them to navigate to the url related to that image. We are also going to assume that we have a nice Image.as class that we have written. This Image.as class extends sprite and takes a single “url” parameter to its constructor to tell it what to load.

Using nested functions this can be done in a few tidy lines of code.


package {

import com.roddeh.media.Image;

import flash.display.Sprite;
import flash.display.MouseEvent;
import flash.net.*;

public class NestDemo extends Sprite{

public function NestDemo(){
var data:Array = [
{
image:"img01.png",
link:"http://site1.com"
},
{
image:"img02.png",
link:"http://site2.com"
},
{
image:"img03.png",
link:"http://site3.com"
},
{
image:"img04.png",
link:"http://site4.com"
}
]
drawImages(data);
}

private function drawImages(data:Array):void{
data.forEach(drawImage);

function drawImage(imgData:*, index:int, arr:Array):void{
var img:Image = new Image(imgData.image);
img.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void{
navigateToURL(new URLRequest(imgData.link), “_blank”);
});
addChild(img);
}
}
}
}

Ok, so you might be thinking “Yeah, that is one way of doing it, but what is the advantage?”. So, here are the advantages IMO:

1. It creates a more concise interface within your classes. When somebody scans over my code they will see a constructor and a single private function named “drawImages”. How the “drawImages” method works may well be irrelevant to them. All, they need to know is that it somehow draws the images based on a data structure. If I had built the same functionality without nested functions then the reader of my code would have had three methods to deal with “drawImages”, “drawImage” and “handleImageClick”.

2. The code does not jump around as much. Something that often irritates me when reading other people’s code is having to scroll up and down a class to work out what is going on. Very often you will see events being handled in a separately declared private function within which there is only a single line of code. Nested functions allow you to neatly package the result of the event with the code that adds the listener.

3. But most importantly, the alternative would have been really ugly. To illustrate how ugly I am going to pseudo-implement the alternative.


package {

import com.roddeh.media.Image;

import flash.display.Sprite;
import flash.display.MouseEvent;
import flash.net.*;

public class NestDemo extends Sprite{

public function NestDemo(){
var data:Array = [
{
image:"img01.png",
link:"http://site1.com"
},
{
image:"img02.png",
link:"http://site2.com"
},
{
image:"img03.png",
link:"http://site3.com"
},
{
image:"img04.png",
link:"http://site4.com"
}
]
drawImages(data);
}

private function drawImages(data:Array):void{
data.forEach(drawImage);
}

private function drawImage(imgData:*, index:int, arr:Array):void{
var img:Image = new Image(imgData.image);
img.addEventListener(MouseEvent.CLICK, handleImageClick);
addChild(img);
}

private function handleImageClick(event:MouseEvent):void{
navigateToURL(new URLRequest(
// Oh s***, what was that link again…
), “_blank”);
}
}
}

So, you may notice that I am actually kinda screwed with the above implementation because I have lost the reference to “imgData” which is what held the relationship between the image I have clicked on and the link to navigate to.

There are of course a number of ways to solve this.

If I can assume that the “Image” class has a “url” property then I could use the “event.target” (which would reference the image), then loop through the “data” array until I found the image that matched. However, I would then also need to store the “data” array in a private variable. Furthermore, I would be assuming that the same image is not being used twice with different links. Assumptions when coding will f*** you up before long :)

Alternatively I could have written a wrapper class around “Image” or perhaps extended “Image” and called my new class something like “LinkableImage” which takes two parameters: “url” and “link”. But personally I find superfluous classes even more offensive than superfluous functions within a class. Instead of scrolling up and down a class I now have to jump between classes just to work out something really simple.

—–

In conclusion, nested functions when used carefully can really make your life easier. Be aware of garbage collection when using them in conjunction with event listeners but do not be afraid of them.

AS * Factory

Sunday, November 1st, 2009

Too often do I find myself writing code that looks something like the following.

var spr:Sprite = new Sprite();
spr.x = 20;
spr.y = 100;
spr.alpha = 0.5;
spr.rotation = 15;


Some programming languages like Python support “named parameters”. This can be emulated in Actionscript using the following technique. Ruby often uses a similar technique by having a single hash as a parameter to a constructor.

package com.roddeh.utils{

public class Factory{

public static function create(clazz:Class, properties:Object):*{
try{
var object:* = new clazz();
}
catch(e:Error){}
for(var ind:String in properties){
try{
object[ind] = properties[ind];
}
catch(e:Error){}
}
return object;
}
}
}


Which would then turn the first set of code into a nice one liner like so.

var spr:Sprite = Factory.create(Sprite, {x:20, y:100, alpha:0.5, rotation:15});

Roddeh CMS Released

Tuesday, September 8th, 2009

After months of development I am finally ready to release version 0.0.0 of Roddeh CMS.

WTF is Roddeh CMS?

It is a CMS that is built purely for use with Flash websites.

Why does the internet need another CMS?

Because there are no decent CMS solutions for flash websites and I am fed up with adapting other CMS solutions to service a flash website.

Tell me more…

Go here!

Actionscript Syntax Highlighter

Monday, March 9th, 2009

A syntax highlighter written in actionscript for actionscript.

Seeing I will be posting code snippets on this blog I thought it might be fun to write a syntax highlighter. I have never written anything like this before and I am sure there are be better ways to do it. However, for my purposes it is good enough :)

You can download the AS class here.

Or here it is highlighted below

Note: Care must be taken with the following characters > <

//
// CodeFormatter
//
// Created by Simon Rodwell on 2008-11-19.
//

package com.roddeh.text{

public class CodeFormatter{

//==================================================================
// PUBLIC PROPERTIES

public static var defaultColour:String = "#EEEEEE";
public static var keywordColour:String = "#FBDE2C";
public static var commentColour:String = "#AEAEA9";
public static var quoteColour:String = "#5BB231";
public static var typeColour:String = "#779ECE";
public static var constantColour:String = "#D14DEE";

//==================================================================
// PROTECTED PROPERTIES

//==================================================================
// PRIVATE PROPERTIES

private static const KEYWORDS:Array = [
"dynamic",
"final",
"internal",
"native",
"override",
"private",
"protected",
"public",
"static",
"class",
"const",
"extends",
"function",
"get",
"implements",
"interface",
"namespace",
"package",
"set",
"var",
"include",
"import",
"false",
"null",
"this",
"true",
"break",
"case",
"continue",
"do",
"while",
"else",
"for",
"each",
"in",
"if",
"label",
"return",
"super",
"switch",
"try",
"catch",
"finally",
"throw",
"with",
":",
"="
];

private static const TYPES:Array = [
"Number",
"String",
"Boolean",
"int",
]

private static const BREAK_CHARS:Array = [
" ",
" ",
"(",
")",
":",
";",
"+",
"-",
"*",
"/",
"%",
"n"
]

//==================================================================
// CONSTRUCTOR

public function CodeFormatter(){

}

//==================================================================
// PUBLIC METHODS

public static function format(code:String, colours:Object = null):String{
if(colours){
for(var i:String in colours){
try{
CodeFormatter[i] = colours[i];
}
catch(e:Error){};
}
}

var coloured:String = “”;
var counter:int = 0;
var quoting:Boolean = false;
var openQuoteChar:String;
var commenting:Boolean = false;
var lineCommenting:Boolean = false;
var c:String;
var chunk:String = “”;
while(counter < code.length){
c = code.charAt(counter);

// Check to see if we are quoting.
if(quoting){
chunk += c;
if((c == “"” || c == “‘”) && c == openQuoteChar){
quoting = false;
coloured += setTextColour(chunk, quoteColour, false);
chunk = “”;
}
counter++;
continue;
}

// Check to see if we are commenting
if(commenting){
chunk += c;
if(c == “*” && code.charAt(counter + 1) == “/”){
commenting = false;
chunk += “/”;
coloured += setTextColour(chunk, commentColour, false);
chunk = “”;
counter++; // Increment a second time to allow for the closing comment
}
counter++;
continue;
}

// Check to see if we are line commenting.
if(lineCommenting){
chunk += c;
if(c.charCodeAt(0) == 13){
lineCommenting = false;
coloured += setTextColour(chunk, commentColour, false);
chunk = “”;
}
counter ++
continue;
}

// Check to see if we need to start quoting.
if(c == “"” || c == “‘”){
if(!commenting && !lineCommenting){
quoting = true;
openQuoteChar = c;
coloured += colourText(chunk);
chunk = c;
counter++;
continue;
}
}

// Check to see if we need to start commenting.
if(c == “/”){
if(code.charAt(counter + 1) == “/”){
lineCommenting = true;
coloured += colourText(chunk);
chunk += c;
counter++
continue;
}
if(code.charAt(counter + 1) == “*”){
commenting = true;
coloured += colourText(chunk);
chunk = c + “*”;
counter += 2;
continue;
}
}

// Otherwise we are writing normal code.
if(BREAK_CHARS.indexOf(c) != - 1){
coloured += colourText(chunk);
coloured += colourText(c);
chunk = “”;
counter++;
continue;
}

chunk += c;
counter++;
}

if(chunk != “”){
coloured += colourText(chunk);
}

function colourText(text:String):String{
if(KEYWORDS.indexOf(text) != - 1){
return setTextColour(text, keywordColour, false);
}
if(TYPES.indexOf(text) != - 1){
return setTextColour(text, typeColour, false);
}
if(isConstant(text)){
return setTextColour(text, constantColour, false);
}
return text;
}

// TODO: I am sure this could be rewritten more robustly as a RegExp
function isConstant(t:String):Boolean{
var i:int = 0;
while(i < t.length){
var charCode:int = t.charCodeAt(i);
if(!((charCode &gts 47 && charCode < 58) || (charCode > 64 && charCode < 91) || charCode == 46 || charCode == 95)){
return false;
}
i++
}
return true;
}

// Colour everything else to the default text colour.
coloured = setTextColour(coloured, defaultColour, false);
// Replace tabs with 4 spaces.
return coloured.replace(/t/g, ” “);
}

//==================================================================
// PROTECTED METHODS

//==================================================================
// PRIVATE METHODS

private static function setTextColour(text:String, colour:int, stripInner:Boolean = true):String{
if(stripInner){
text = stripInnerColour(text);
}
return “<font color="” + getHTMLColour(colour) + “">” + text + “</font>”;
}

private static function stripInnerColour(text:String):String{
var reg:RegExp
reg = /<fontb[^>]*>/g
text = text.replace(reg, “”);
reg = /</font>/g;
text = text.replace(reg, “”);
return text;
}

private static function stripWhite(text:String):String{
var reg:RegExp = /^[ t]+|[t]+$/
return text.replace(reg, “”);
}

private function getHTMLColour(color:int):String{
var col:Colour = new Colour(color);

function getHexString(hex:int):String{
return getHexChar(Math.floor(hex / 0×10)) + getHexChar(hex % 0×10);
}

function getHexChar(hex:int):String{
if(hex < 10){
return String(hex);
}
else{
switch(hex){
case 10: return “A”;
case 11: return “B”;
case 12: return “C”;
case 13: return “D”;
case 14: return “E”;
case 15: return “F”;
}
}
return String(hex);
}

return “#” + getHexString(col.red) + getHexString(col.green) + getHexString(col.blue);
}

//==================================================================
// SET METHODS

//==================================================================
// GET METHODS

}
}

Flash SEO and Wordpress

Sunday, March 8th, 2009

SEO for “All Flash Websites” using Wordpress.

Having worked almost exclusively as a flash developer for the past 5 years I determined that my own site should have a strong flash flavour to it. I considered combining standard HTML with flash elements for navigation, headers etc but I was never really at peace with any of the concepts I came up with. At the same time I didn’t want to suffer not being indexed by search engines because I elected to build my site as an all flash website. So after much research and experimentation I have come to the current implementation that uses the following technologies to achieve an all flash website that will still be indexed by search engines.

  • Flash/Actionscript 3 for the body of the site.
  • SWFObject to embed the flash content.
  • Wordpress to manage the content.
  • SWFAddress to manage deep linking.

Hiding the HTML

When a user such as yourself navigates to my site what you see is an all flash website. However if you view the source of the page you will notice there is a lot of HTML that never gets displayed. This is achieved with the following CSS.


html {
height: 100%;
overflow: hidden;
}
#flashContent {
height: 100%;
font-family:arial;
font-size:12px;
}
body {
height: 100%;
margin: 0;
padding: 0;
background-color: #ffffff;
}


So, when a user in a browser visits the site they will see the flash content. But a search engine crawling my site will see the flash and the HTML and index my site accordingly. Who knows how long this will work before search engines ignore HTML that “overflows” but for now, it works ;)

Wordpress as a CMS (Content Management System)

Functionally I wanted my site to behave pretty much like a blog. After a bit of research I settled on Wordpress as a blogging engine as it offered all the features I needed. I then created a WP theme that would allow the flash content to take over the page (using CSS as described above). I also needed to create a way for flash to retrieve the content from wordpress. This was achieved with a fairly simple script that accessed the WP database, retrieved the specified content and returned it as JSON (Javascript Object Notation) though you could just as easily return it as XML.

You can download the Wordpress to JSON script here. Be sure to change the variables on lines 132-135.

Papervision Shaders

Tuesday, December 16th, 2008

An example using papervision shaders with all source code provided.

I was recently required to investigate the shaders now supported in Papervision 2.0. Usually I would start with the documentation when trying out something new but it seems the folk at PV are so flat out with new features, stringent documentation is on the backburner. I ain’t complaining though, if it was a choice between improvements and thorough documentation gimme improvements all the way.

So, when documentation doesn’t paint the full picture google is the next stop for me. Googling “papervision shaders” produced no shortage of hits, surprise surprise. Unfortunately most hits were sweet demos of what I needed to achieve but no code :( Those hits that promised to be tutorials all pointed back to a single tutorial posted on brighthub. The content of the tutorial looked promising and the demo swf showed exactly what I needed to achieve. The author of the tutorial was also kind enough to share all the code and related media files required to produce the demo.

I downloaded the sample files and was able to get it all compiling without much trouble at all. Sweet, I was making progress. However, upon looking at the code my progress came to a halt, wow was the code obtuse. Sure, once I understood what was going on I admired the elegant solution that was provided but the purpose of downloading the code was to learn how to use shaders, not how to write a beautifully OO demo.

Now, having never provided any demos of my own I feel rather hypocritical dissing the hard and contributive work of others in the flash community. It is not my intention to discredit the work of others but rather encourage those pioneers who are able to consume the latest in tech advances faster than us noobs to feed it back to us in as palatable format as possible.

That, said I have written my own demo on using shaders in Papervision and tried to keep it as plain and stupid as possible. So, without further adieu here is the code and you can click the image below to launch the demo.

I have decided that instead of providing a lengthy explanation of how it works I would just comment the code and hope that it explains itself.

Being my first demo post I am eager for feedback, please keep it constructive :)