AS3 OOP common practices examples? - actionscript-3

I am trying to better understand the AS3 OOP structure and organization, but I am having some problems wrapping my head around it. I want to create multiple class files and it seems that best practice is not to and to put all classes in one file? I have searched for hours on the web and came up with little for good examples. Maybe seperate files is not the way to go while using AS3, but to me it only makes sense for modularzation. The files I have been playing with are:
Main.fla
Main.as (document class)
TestOne.as
TestTwo.as
TestThree.as
TestFour.as
TestFive.as
I have created a folder called classes to house all class files except the Main.as which resides with the FLA.
All five Test classes are the same code except the file name and class name.
Here is how I am importing the files:
Main.as
package classes
{
import flash.display.MovieClip;
import classes.TestOne;
import classes.TestTwo;
import classes.TestThree;
import classes.TestFour;
import classes.TestFive;
public class Init extends MovieClip
{
trace("This is Main Class");
var testOne : TestOne = new TestOne;
}
}
TestOne.as
package classes
{
import flash.display.MovieClip;
public class TestOne extends MovieClip
{
trace("This is TestOne");
public function testing():String
{
return "This is the testing method";
}
}
}
Are the above examples I created good AS3 OOP practices? I understand these are real basic classes, but I think it should get the point arossed.
I am using CS3

Might be good to look at the Flex SDK coding conventions and best practices. It is a point by point rundown of how you should be using ActionScript 3. There is quite a bit of OOP stuff scattered throughout, so take a good skim through it. I think it is worth any new or experienced AS3 devs to have a read, because there is a lot of useful information there.

OOP is a big subject but here is a good primer.

ActionScript 3 design patterns will be also useful for you.

As Nathan said, big subject.
The thing about having all classes in one file is related to the topic "visibility of a class" and "access modifiers".
The modifier is that what is written before the class keyword. It can be public or internal. Internal means, that only code that is placed in the same directory (package) of the internal class can create an object of it. Public means, any code can create an instance of the class. Random link via google: http://flexmaster.blog.co.in/2010/05/20/action-script-use-access-modifiers-with-classes-and-class-members/
You are allowed to have multiple classes in one file. But then only one can have the modifier public. All others need to be internal. If you leave out the modifier, a class is by default internally visible. An internal class in a multiple classes file can be accessed only from within this file.
There are two more modifiers: protected and private. Both are applicable only to properties or methods. As an advanced developer you can even define you own modifier by using namespaces.

The rules of OOP still apply to AS3
1) Encapsulation.
2) Inheritance.
3) Abstraction.
4) Polymorphism.
Apply them or not is your choice but it is good practice.
And don't forget the most important rule "KISS" (keep it simple stupid)
I also want to point out your code has an error
package classes
{
import flash.display.MovieClip;
public class TestOne extends MovieClip
{
trace("This is TestOne");// this line is not inside a function and will most undoubtly error out your app.
public function testing():String
{
return "This is the testing method";
}
}
}

I think you either did something wrong when you copied the code into SO or you're not placing the trace statements correctly. You need to place the trace("This is TestOne"); inside a constructor in TestOne.as, like this:
public function TestOne() {
trace("This is TestOne");
}
The same goes for the code inside the Init class, which now reads:
trace("This is Main Class");
var testOne : TestOne = new TestOne;
but should be(note the bracers after new TestOne):
public function Init() {
trace("This is Main Class");
var testOne : TestOne = new TestOne();
}
What happens when you run your SWF, is that the constructor of the class Init will:
1) Trace "This is Main Class" to your console.
2) It will construct a new object(thus the name constructor) by calling the constructor of the class TestOne.
If you were to add this line to the end of the constructor in the class Init:
testOne.testing();
you should see this in the console: "This is the testing method".
If you would now comment out the line: var testOne : TestOne = new TestOne(); and run the SWF again, you'll get an error telling you something is null. This is because you attempt to call the method testing on an object that does not exist.
I do realize this is primarily fixing some coding errors of yours, and not so much helping you understand OOP. But hopefully you can pick up some help regarding object construction. I see some answers already mention key OOP principle that you really should look into.
Edit:
Remember that duplicating code is never a good thing, so if you find that all of the classes TestOne - TestFive contain the same code, except for some minor detail. You should probably change them into one class.
In your case you could for example change TestOne so that the constructor accepts a String, and then in your testing function you could just trace that String. By changing your TestOne class into the following you effectively get rid of 4 other classes. You also encapsulate a String inside of the class TestOne.
package classes {
import flash.display.MovieClip;
public class TestOne extends MovieClip {
private var message : String;
public function TestOne(myMessage:String) {
message = myMessage;
trace("This is TestOne");
}
public function testing() : String {
return message;
}
}
}

Related

Interfacing and Game Architecture in Actionscript 3

I am in the midst of creating the architecture for my new Point and Click game in the Starling framework. It is set to be big in size, so I am trying to make sure to use best Object Oriented practises to ensure I do not A) Repeat the same methods. B) Keep it sustainable and clean.
I was unaware of Interfacing as a way to contract all classes. To keep everything consistent and to ensure that sub classes have the methods to function correctly. Let us look at an example of a player class i have created.
public interface IPlayer {
function changeDirection():void;
function walkToPosition():void;
function pickUpItem():void;
}
class AbstractPlayer extends Sprite implements IPlayer {
public function changeDirection():void {}
protected function walkToPosition():void {}
protected function pickUpItem():void {}
}
class Player extends AbstractPlayer {
override protected function walkToPosition():void {}
override protected function pickUpItem():void {}
}
I am aware that AS3 Does not support Abstract Classes natively. But I choose to have it in this form as it makes sense to. What I do not understand is why the interfaces only support public methods. Doesn't that defeat the whole purpose of having an interface; so you know what methods are needed for a player. Declaring only the public functions of the player class seems like a half job.
A verbose explanation of this concept and perhaps a more advanced solution to how this could be structured would be of great benefit.
Many Thanks,
Shaun
An interface is a collection of method declarations that allows unrelated objects to communicate with one another.Hence public access control identifiers for implemented methods.In a typical interactive context often a need arises to modify or control behavior of an object in question externally.In such a case, behavior-control may ideally be accomplished through an interface.Obliviously only methods put into a public namespace are accessible externally.Bearing in mind that attributes of an object should not be be directly modified by external code but only through an interface is good practice of Object Oriented Design. Assuming that a need arises of an object to have more than one point of access control(behavior control); one for external purposes and the other for internal purposes respectively, then putting all behavior in one interface defeats the objective.The following may help to achieve the objective(because you said it's big in size).
Put behavior in an interface you think should be accessible externally.
Define Mediator to encapsulate view-code-mediation:-listen for user triggered events, update view send notifications to other tiers of the application.
Define Model for data purposes.
Define executable commands to be called within your application.
See if you can promote as much lose coupling as possible among the tiers.The goal is to write as much less code as possible and not boiler-plate in nature.I recommend that you use a framework such as robotlegs if really your project is that big.The framework will take care of dependency injection and along the way lift off the burden of writing boiler-plate code.
I Hope the foregoing helps. Thanks.
The interface is acting as an outline of required members to be implemented in the classes using said interface. Therefore the interface methods never being called directly and only being used in the classes implementing them require no access modifiers.
Now you're correct AS3 does not support abstract classes, BUT there is a way to implement an "abstract" class AS3 as per the design. So here is what that might look like with your code:
public interface IPlayer
{
function init():void;
function changeDirection():void;
function walkToPosition():void;
function pickUpItem():void;
}
public class AbstractPlayer extends Sprite implements IPlayer
{
public function AbstractPlayer() {
init();
}
protected function init():void {
throw new IllegalOperationError( "Abstract method, must be overridden in subclass" );
}
public function changeDirection():void {}
protected function walkToPosition():void {}
protected function pickUpItem():void {}
}
public class Player extends AbstractPlayer
{
public function Player() {
super();
}
override protected function init():void {
//implementation
}
}
Abstract classes having method implementation by default will require subclasses to override these methods ( see init() and error thrown ) keeping strict usage of the parent class method and members.
This is the basic abstract class design for AS3. This is also the begining to a Factory Method pattern which you can read more on here: http://www.adobe.com/devnet/actionscript/articles/ora_as3_design_patterns.html
Now the more reusable design for this might be to generalize your class names a bit more, perhaps something more like this:
public interface IEntity
{
function init():void;
function changeDirection():void;
function walkToPosition():void;
}
This would be assuming that more game objects other than your Player class will have use of the methods in the IEntity interface.
Now your Player class can become a new object of type Entity:
public class Entity extends Sprite implements IEntity
{
public function Entity() {
init();
}
protected function init():void {
throw new IllegalOperationError( "Abstract method, must be overridden in subclass" );
}
public function changeDirection():void {}
protected function walkToPosition():void {}
protected function pickUpItem():void {}
}
Now in regards to the design, since abstract classes are just a tool like any other there are many different designs to take using it and it really depends on your project. I would recommend sifting through the aforementioned link to the "Factory Method" pattern and some of the other designs to see what fits your needs.
An interface defines the way other classes interact with a specific implementation of that interface. Other classes cannot call implementation's private methods directly - there's no need for the interface to define them.
Let's say we have two subclasses of AbstractPlayer: Player and AIPlayer. The Player class would probably include methods to listen for specific input events and to respond to them accordingly, like onKeyUp or onMouseClick, which should be private: there's no need to external classes to know how the player is controlled. The AIPlayer on the other hand is controlled by some strategies you define in your code, therefore instead of listening to user's input, it should keep track of Player's actions and react accordingly. This class does not need onKeyUp or onMouseClick methods, so why put them in interface?

Collecting Information From a Variable with An EventListener

This may be quite a complicated question, but I am making a hack for a game which I have hacked many times before and I have had a request, but I do not know how to work around it.
I am not that advanced at AS3 so please be kind if I fail xD
The request is to make a chat catcher for the game, where all chat is saved. I have been told that I can use an EventListener to do this. I also discovered that
Game.chatM
Is the linkage (I think that's the correct word for this) for where all of the chat can be found.
I know that it's a far stretched question, but is there a function which would do something such as this? Like gathering information from this variable?
Any advice would be much appreciated!
What I tried before:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
public Class ChatCatcher extends Sprite
{
private var Game.chatM:Model;
public function ChatCatcher():void
{
Game.chatM = new Model();
Game.chatM.addEventListener(Model.VALUE_CHANGED, onModelChanged);
}
private function onModelChanged(e:Event):void
{
trace('New Chat Message');
//This is where hopefully chat will be saved
}
}
}
Your code looks a little suspicious.
You incorrectly declare a variable on this line:
private var Game.chatM:Model;
You shouldn't be declaring variables that have a dot in their name. That should generate an error when you try to compile your code.
I imagine that Game is a class, and that in that class you have defined a static property named chatM (which is of type Model). If this is the case, then you should do something like this to declare a local instance of the chat model in your class:
private var chatModel:Model = Game.chatM;
Next, you add an event listener for the event "onModelChanged". If the chat model class dispatches such an event when a new chat message is added, then your event listener will get executed.
But all of my guessing here seems to lead me to the conclusion that this is all unnecessary. I'm sure I've misunderstood something... but your intent was to get a list of all the chat messages. And it seems you already have that list (the chat model itself).
If this doesn't help, you should also add the relevant code for your Model class and if it exists, the Game class... and of course, tell me where my guesses were wrong!

Public Function Allegedly Doesn't Exist?

Okay, I am at the end of my rope.
I have a Flash Professional CS5.5, Adobe AIR, Actionscript 3 project. So far, I've never had this problem before...
I have a custom class called Prefs, that I wrote myself. This class has a number of functions. The ones I wrote a couple weeks ago, I can call in my code with no problem. But the ones in the SAME CLASS that I wrote today are throwing an error.
This one works:
public function UserFetch(ID:String):*
{
This one doesn't:
public function Set(setting:String, val:*):void
{
I call both the same way. In the document class "base":
package {
import flash.display.MovieClip;
import trailcrest.prefs.prefs;
public class base extends MovieClip {
public static var Prefs:prefs = new prefs();
}
}
In my timeline code.
base.Prefs.UserFetch("musictoggle");
base.Prefs.Set("musictoggle", true);
The first fires fine. The second gives this error:
Scene 1, Layer 'Layer 1', Frame 1, Line 4 1061: Call to a possibly
undefined method Set through a reference with static type
prefs.
What is going on? I can find absolutely no legitimate reason why this should be happening. Like I said, it has never happened before, and it not happening on any other class or function.
After a bit of discussion in the chat, we found that flash was not picking up on the changes made in the prefs.as-file. Changing the name of the class fixed the issue (It may have been a weird compiler cache problem).

AS3 - Global classes?

I know global variables are supposed to be bad but is it possible to create global classes? I am creating an application and I want to have one class that handles sound. From any class I would like to be able to say soundhandler.playSound(); without having to pass references all over the place. It should just know it is there.
Any help greatly appreciated.
You're referring to static members.
Your class SoundHandler would have a static method called playSound(), which can be implemented like so:
package
{
public class SoundHandler
{
public static function playSound():void
{
// #todo Logic
}
}
}
Your playSound() method is now accessible via:
SoundHandler.playSound();
Note: You mentioned global methods being bad, however this is a perfect candidate for these and something I would actually recommend (as much as I hate using static).
Additional: ActionScript 3's Math class contains mostly static members e.g. Math.round()
Your question (comment): Do I need to initiate SoundHandler in the document class?
No, in fact you shouldn't make an instance of SoundHandler at all. The only requirement is that you must have SoundHandler imported in your current class to access it:
import yourpackage.SoundHandler;

Accessing Variables in another class?

First off I don't understand classes, how to "call" or "initiate" them. I'm class ignorant.
I have two .fla files. One of my .fla files consist of 15+ .as files; we'll call this one XML editor. The other .fla file consists of 10+ .as files; we'll call it the interface.
The xmleditor.swf loads the interface.swf.
Within the xmleditor.swf, a login screen appears and the enduser logs in as either a "user" or an "admin". The "user" or "admin" is stored in a public variable called "userType". The userType variable is created in one of the many xmleditor.fla .as files called Login.as.
Once logged in, xmleditor loads the interface.swf. interface.fla uses 10+ .as files. one is called nodeNames.as I need an if statement in nodeNames.as that is something like this:
if (Login.userType == "user"){
trace("do something");
}
I have the following FlashVars.as file but I have no idea what the steps are to make it work.
package extras.utils {
import flash.display.Sprite;
import flash.display.LoaderInfo;
/* In AS3, we need to have a display object on the stage to access FlashVars
* this class can be used once, and then referenced from anywhere as
* FlashVars.data.variableName
*/
public class FlashVars extends Sprite {
public static var data:Object;
public function FlashVars() { }
public function load():void { //Only needs to be called once
data = this.root.loaderInfo.parameters;
}
}
}
Should I use this FlashVars? and if so, how?
Or is there an easier way to access the variable?
well, from what i understand, you Login.as is a class. Then you have two ways of accessing the Login.userType variable : if you want to be able to call it with
Login.userType, you'll need it to be static in your class
public static var userType:String
it is then accessible using Login.userType from anywhere in your application, as long as you import Login.
But it is often considered bad practice to have too many static vars in your app, especially from different classes. so you may want to have an instance of your login class stored in a variable somewhere in your app, along with anything you need
var myLogin = new Login();
myLogin.userType = 'value';
But be aware that this way, every new Login() will carry it's own different userType, so you will want to pass along myLogin to any object needing it.
Object programming can be confusing, but is very powerful, i suggest you read about it (in books or on the web) since the whole thing can't be explained here.
Have fun!