
From the start, I have to warn you that this melodramatic title may not have been terribly well considered. When Shelley asked me what my talk at 2 was going to be, I responded in rather a flustered manner without thinking through the ramifications. I think a sense of rather foolhardy bravado may have seeped into the name of the talk, and I am not ashamed to admit that.
Not wanting to disappoint, I wracked my brain for Actionscript 3 scenarios which could relate to the theme of Dragons. No luck. Cursing the English Literature degree that had seemingly created this intractable situation, I got to work on the talk.
The thing I wanted to convey most is that making things with AS3 is not really hard or indeed Evil. Many people have misconceptions of Flash, and most Rails developers I know don't really like the idea of playing around with it at all. In my experience, Flash is a really great medium for doing loads of different things, though definitely not a replacement for HTML/CSS/JS in most cases. I really enjoy creating stuff in Flash, and intended to get some people to listen to me.
Also worth noting, this talk was not about Flex. I have experimented with Flex, and kind of like the idea behind it for RIAs. Sometimes though you just want to work with the actual language behind the interface, rather rely on a whole bunch of classes that get mysteriously instantiated from your MXML.
I wanted to educate people about the fundamentals of how these interfaces are build from the primary elements. We cover creating sprites on the stage, importing other classes, attaching behaviour and some of the basics of drawing. Sticking with the mythological theme (though not of a dragonesque nature), the examples are set in the depths of time in Ancient Greece. Gods chill out on Mount Olympus, and everything is hunky dory. With that in mind, here is the content of the talk. You can get the files here:
http://blog.nbwd.co.uk/assets/2007/8/7/gods.zip
Zeus
The first example we look at is as simple as you can get. We put this in the file 'Main.as' in the example called 01_zeus. When this is compiled, we include the Sprite class and make a class called Main that is inherited from it. The constructor function is named the same as the class, so when this is compiled and run, the Main function is called when an object of class Main is initialised and added to the stage.
In this Main function is where all the magic happens, we create a new Sprite (not a pun) called zeus, and start drawing his likeness. Now whatever people may claim, no-one has ever seen a greek god, and I don't believe the likenesses of them on pots are right. In my opinion, Greek gods are all square in shape, and covered in colourful hair. This has nothing to do with it being easier to draw sprites like that, so don't even suggest it. We specify that zeus will be black, and 50x50 pixels. We do this by calling methods on the Sprite's built in graphics object. once we have draw him, we add him to the stage for all to admire. For fun, we nudge him into the middle a bit more to demonstrate how Sprites have x and y coords for positioning them.
package {
import flash.display.Sprite;
public class Main extends Sprite {
public function Main():void {
var zeus:Sprite = new Sprite();
zeus.graphics.beginFill(0x000000);
zeus.graphics.drawRect(0, 0, 50, 50);
this.addChild(zeus)
zeus.x = 30
zeus.y = 30
}
}
}
"Wow", I hear thee cry, "surely the talk was over at this point and roses were being cast at your feet?". This was not the case Gentle Reader, greater marvels were to appear shortly.
Athena
Now Zeus is a bit old and cannot move very well. To demonstrate a bit more action we pan to Athena. In this project (02_athena) we have a new directory called "gods". This will contain all our other classes we are going to use. In our Main.as we import "gods.Athena;" which is the class in gods/Athena.as, and add it to the stage like we did with Zeus. Athena has all her internals nicely encapsulated inside her, unlike slovenly Zeus. She can do this because she is created from a class that extends Sprite and can add to it as we want. We have to import all the classses we are interested in inside the package that contains Athena. In this case we want the sprite class, and all the events "flash.events.*;" which we use a wildcard for.
When Athena is instantiated, we draw her as a square (totally correct), but her class has a public variable called hair color:
public var hairColor:Number = 0xe4a406;
this is used to make a nice golden square instead of the black we used on Zeus. She also has event handlers added to her. When someone clicks on her, the method startDrag() is called on her which is inherited from Sprite. She can now move around on the stage with the user's mouse (though the ironic notion of humans being in control of the motor functions of the Gods is a whole debate I am not entering into atm). Interestingly, we attach the mouseup event to the stage object of the Sprite rather than the sprit itself. This prevents the situation where you drag something and inadvertantly move out of the window. The stage can tell if you release outside the window, but if it is on the object, it won't get the hint.
Olympus
Again, a miraculous thing, but the fun doesn't stop there. We now decide to make a home for all these gods, and feel that Olympus is a fiting name. In 03_olympus, we make an olympus object and add it to the stage. Like we did with the gods, we represent Olympus as a square, it is big and grey. Olympus has an event handler on it which takes mouse clicks and creates new instances of RandomGod on the x and y of the event. Clicking on the stage creates a multitude of gods. Unfortunately there is a bit of a bug here which was noticed afterwards and that I haven't fixed, if you click on a random god, the x and y are taken from it rather than Olympus. Not the end of the world, but there ya go.
Naughty Gods
In the final example a bit more goes on. We create olympus as before, and also create zeus with his own special class. The random gods are populated automatically this time, and Olympus takes care of creating them when it is instantiated. Unfortunately these gods have been drinking some rather bad wine. This has the unintended consequence of turning their hair green, and making them rather unruly. Intolerable.
Zeus, not gifted with ample amounts of patience for his immortal responsibilities responds to this chaos by delivering a thunderbolt into the rabble, killing them dead.
Let's analyse what is involved in this catastrophe.
When Zeus was created, he was not created equal. The Zeus class has the following:
public function Zeus(posX:Number, posY:Number):void {
...
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseIsDown);
}
public function mouseIsDown(event:MouseEvent):void {
strikeDownNaughtyGods();
}
public function strikeDownNaughtyGods():void{
var lightning:LightningBolt = new gods.LightningBolt(this, olympus.naughtyGods);
olympus.addChild(lightning)
}
When clicked, Zeus calls the function strikeDownNaughtyGods(). This makes a new ferocious lightningbolt taking Zeus (this), as the thrower, and olympus.naughtyGods as the targets. The variable olympus is just a reference to olympus we set on zeus at the beginning. When our lightnning bolt is made, the fun starts. The graphics object is called, and we say we are going to start drawing with the thickness of boltWidth and a nice blueish colour. the drawing pointer is moved to the center of the srcGod, and we send the bolt off.
package gods{
import flash.display.Sprite;
import flash.events.\*;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.display.Sprite;
public class LightningBolt extends Sprite {
...
public function sendBolt():void{
killCount = 0;
timer = new Timer(500);
timer.addEventListener("timer", timerHandler);
timer.start();
}
public function timerHandler(event:TimerEvent):void {
if (killCount == targetGods.length){
timer.stop();
this.graphics.clear();
}else{
this.graphics.lineStyle(boltWidth*=0.8, 0xb2ebf4);
this.graphics.lineTo(targetGods[killCount].heartX(), targetGods[killCount].heartY());
targetGods[killCount].kill();
killCount++;
}
}
}
}
A Timer object is created, and every 500 miliseconds it will call timerHandler. When we haven't killed all the gods yet, the bolt width diminishes to reflect the principle of Conservation of Energy, and then we draw a line to the next god in the array. This new god has the method kill() called on him, which in itself is scary. This method makes him change colour, shake from side to side and finally expire, turning red in the process. When the naughty gods are dealt with, the timer stops, and Zeus can read a book in peace.
So there you have it, some basic principles explained. I am by no means an expert, I just play around every now and again for fun. Hopefully a few brave souls will have a go and come up with some other neat stuff. I have found that graphing in particular is an area where Flash shines, especially where it is being fed xml from a beautiful Rails app. Maybe I will blog about my recreation of a zoomable graphing for showing tons of data at some point if anyone is interested (a bit like Google Finance, but made by me).
