Look at that, made with a free package so you get the watermark, nothing's too cheap for you dear reader.
This at heart is how I've structured all my games since starting with as2. It only varies in that there are sometimes more classes in there, the actual hierarchy never changes.
Ok lots of code here is never that great to read, but there's no way around it, sorry,
package {
import Classes.Init;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
[SWF(width="600", height="400", frameRate="35", backgroundColor="#000000")]
public class Main extends Sprite{
//---------------------------------------------------------------------------------------
// Properties
//---------------------------------------------------------------------------------------
private static var instance:Main;
private static var __parent:DisplayObject;
private static var stage:Stage;
private static var init:Init;
//---------------------------------------------------------------------------------------
// Static ( Singleton )
//---------------------------------------------------------------------------------------
public function Main(){
if(instance){
throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
} else {
instance=this;
}
instance=this;
//When we are running from our preloader, comment this out
waiting();
}
//---------------------------------------------------------------------------------------
// Public
//---------------------------------------------------------------------------------------
public override function toString():String {
return "Main";
}
//---------------------------------------------------------------------------------------
public function waiting():void{
addEventListener(Event.ADDED_TO_STAGE,mainAddedToStage);
}
//---------------------------------------------------------------------------------------
// Getters
//---------------------------------------------------------------------------------------
public static function getInstance():Main {
return instance;
}
//----------------------------------------------------------------------
public function getMainMovie():DisplayObject{
return __parent;
}
//----------------------------------------------------------------------
public function getStage():Stage{
return stage;
}
//----------------------------------------------------------------------
public function getInit():Init{
return init;
}
//---------------------------------------------------------------------------------------
// Private
//---------------------------------------------------------------------------------------
private function mainAddedToStage(e:Event):void{
stage=this.stage;
stage.showDefaultContextMenu=false;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality=StageQuality.LOW;
stage.stageFocusRect=false;
__parent=this.root;
init=new Init();
}
//---------------------------------------------------------------------------------------
}
}
Hopefully this should be fairly straight forward ( I did actually grab it from somewhere else when looking for an as3 version which matched what I was doing in as2, so sorry original author, I can't tell anymore what's yours and what's mine ). We're basically waiting around until this instance is added to the stage ( If you try and read some properties before it's technically been created then you're going to get errors. ) and then running the mainAddedToStage method. Importantly we have some getter methods set up here, as we need them ( More later ). This is our document class, and as such it has a "direct" link with the swf ( For want of a better term ). From now on throughout every other class, any reference to stage or Main is obtained from this class.
The very last line you'll see we create a new instance of the Init class ( init=new Init(); ), so let's check that class out.
package Classes {
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.Stage;
public class Init {
//---------------------------------------------------------------------------------------
// Properties
//---------------------------------------------------------------------------------------
private var gameController:GameController;
private var attract:Attract;
private var soundHandler:SoundHandler;
//------------------------------------------------
// System
//------------------------------------------------
private var main:Main;
private var mainMovie:DisplayObject;
private var stage:Stage;
//---------------------------------------------------------------------------------------
//Constructor
//---------------------------------------------------------------------------------------
public function Init(){
main=Main.getInstance();
mainMovie=main.getMainMovie();
stage=main.getStage();
soundHandler=new SoundHandler();
gameController=new GameController();
attract=new Attract();
}
//---------------------------------------------------------------------------------------
// Public
//---------------------------------------------------------------------------------------
public function toString():String {
return "Init";
}
//---------------------------------------------------------------------------------------
// Getters
//---------------------------------------------------------------------------------------
public function getAttract():Attract{
return attract;
}
//---------------------------------------------------------------------------------------
public function getGameController():GameController{
return gameController;
}
//---------------------------------------------------------------------------------------
public function getSoundHandler():SoundHandler{
return soundHandler;
}
//---------------------------------------------------------------------------------------
}
}
This again is a bit of a nothingy class. In theory it could be shoved into the Main class with no real harm, the reason I don't is pure lazyness. I like being able to copy the Main class to every new project without having to think about it, i.e aside from the [swf] tag I never have to alter it. It just feels cleaner having that first class do very little.
If you look at our Init class you'll see we just create instances of each class we need ( Refer to our cheapo diagram to help clarify ), and set up some getter methods again ( Just to clarify, a method is exactly the same as a Function, it's just that if you use a function in oop it's called a method instead. I don't know why either ), so other classes can get a reference to these instance's if they need to.
How do I decide which classes sit on which row of the hierarchy ? Main is our document class, so he's at the top and doesn't really do much. Init is Main's love child, and doesn't do much either, he's just creating the actual game classes.
The next row is more interesting. Attract is our front-end. It deals with the title screen, the game over screen, hi-score entry if the game supports it, instructions etc. Basically everything that happens before starting the game and after the game has finished.
Let's jump over to SoundHandler. This is just what it says. It's here because it's used by both Attract and GameController, as both need to have sounds. GameController is a simple class like Init, it handles the creation of all the child classes needed for the game ( Check the diagram ).
Let me try and rationalise why Attract, GameController, SoundHandler are all on the same row, in effect why they're equal to each other. We've already established that Attract and GameController need to be aware of the SoundHandler class as both need sounds. In the grand scheme of things, the Attract class doesn't really need to know about GameController ( Remember Attract is everything
but the actual game ) and conversely the GameController really doesn't give a crap about Attract. If one of these classes is working, then the other isn't doing anything, so it makes sense to me that they're on the same row.
Does that mean they never need to chat to each other ? No, but it's at very key points. For example, when the player presses the "Play Game" button in Attract, we kill off all the Attract mode things and then call startGame() method in GameController.
Now we come to something cool. Quite a few times I've seen people moving over to oop, and it's all going well, until they need a reference to a different class. How the hell do we get the reference we need ? No one wants to pass a reference to a class via a constructor, as that's just messy and nasty and really easy to screw up, and it's not like we can be old school and use _root.myMethod(); when we're oop gods.
Notice all my constructors are the same, eg,
//------------------------------------------------
// System
//------------------------------------------------
private var main:Main;
private var mainMovie:DisplayObject;
private var stage:Stage;
//---------------------------------------------------------------------------------------
//Constructor
//---------------------------------------------------------------------------------------
public function GameController(){
main=Main.getInstance();
mainMovie=main.getMainMovie();
stage=main.getStage();
}
We get a reference to our document class, Main and store it in our local var main. We also store away a reference to our mainMovie ( To be honest I don't think I've used that ref. in as3 yet, it's just a throw back to my as2 code, but I'm a creature of habit so it'll stay there 'til as4 ) and the Stage.
So this is the GameController class, and it's game over, so we want to call the Attract class as he deals with that. This is how we get our reference:
main.getInit().getAttract().gameOver();
Check back with our Main class code up there, see getInit() in the getters section ? It returns a reference to our Init instance. Then look at the Init getters, getAttract() gives us our instance of Attract, and from there we're just calling the method gameOver in the Attract class.
Don't worry if this doesn't make sense straight away, it's quite a bit to get your head around in one go. Basically so long as we have a reference to Main in any class, we can get a reference to any other class no matter how far away from the callee class we are. References aren't a pain in the arse anymore, they're as simple as this.
You may be thinking, how the hell am I going to remember all those getOurInstanceName() method calls. Auto-completion. Flex does all this for you so it's never an issue ( And I'm sure Flash Develop does the same ). I don't know about the Flash IDE, I really don't hold much faith in it doing it, so now may be the time to install Flash Develop and have a play with that.
See we've got the basics of oop hierarchy covered, and I've not had to slip into terms like singleton and composition. Feel free to google both terms, see what they actually mean, and hopefully when you read the flowery descriptions you'll realise that you already get them as we've covered them here.
As always feel free to fire over questions or point out glaring errors in what I've done. Like I said all my games pretty much follow this pattern, which makes sharing code between projects a lot easier plus I'm not having to think about how classes are inter-connected. I'm not suggesting you just blindly copy what I've done, but perhaps plan out your next game using some simple flowchart boxes so you can see where classes should be connected and where it'll be a waste of time to do so.
Squize.