Custom Event Listener- un able to understand reasoning behind constance variable - actionscript-3

I was following a tutorial online to create a custom event listener. i have some of an understanding of how it works, but its still somewhat confusing. i know that public static Constance DEAD:String = "dead" is a variable (a string) that equals the value "dead", however i do not understand why you need to create this variable just so (type:String) can turn into (DEAD:String). for instance, if you get the value "dead" is that just a default value since it could literally be anything? thanks.
package
{
import flash.events.Event;
public class AvatarEvent extends Event
{
public static const DEAD:String = "dead";
public function AvatarEvent( type:String )
{
super( type );
}
}
}

The value of the string is used by the EventDispatcher to identify the listeners to be notified when the event is dispatched.
The constant is for you, developer, to help you to write clean code, and avoid to create some silly bugs. When writing
dispatchEvent(new AvatarEvent(AvatarEvent.DEAD))
you avoid the typo that could occur in
dispatchEvent(new AvatarEvent(“dead”))
and allow the compiler to check the parameter you give to your event's constructor.
To go further, you could use Robert Penner's AS3Signals, which was written as a replacement for AS3 custom events. It solves many of the drawbacks of the custom events. By example, it does not use strings to identify events, so you can't have any conflict created by two events with the same type value. And it avoids creating a new object each time you want to dispatch a new event, so it is better for performances.

Related

How to pass object, MouseEvent.CLICK and function to trigger

I want to pass to function object, const of type MouseEvent.CLICK and function to trigger. In my case:
my class Assistant:
public static function addEventListenerTo(obj:Object, MouseEventConst:String, functinToTrigger:Function) {
obj.addEventListener(MouseEventConst, functinToTrigger:Function);
}
and my class Engine which invokes
Assistant.addEventListenerTo(deck,"MouseEvent.CLICK",showObject);
Please give me advice how to make it work. Thanks.
In the code you provide there is one compiler error (the one Tahir Ahmed pointed to in his second comment).
Fixing this by removing the second :Function in the first code block:
public static function addEventListenerTo
(obj:Object, MouseEventConst:String, functinToTrigger:Function)
{
obj.addEventListener(MouseEventConst, functinToTrigger);
}
will let the code compile. (I wrapped the Method signature to avoid the scrollbar, this is not required to make it compile.)
The other major problem is a configuration error (or maybe a typo): the one about MouseEvent.CLICK. (the one Tahir Ahmed pointed to in his first comment)
Looking at the documentation it is defined to have the value "click" (a String literal following the AS3 convention of the lowercase constant name). So to pass it to your method you can either put in a reference to the constant by writing MouseEvent.CLICK (without the "s around it) or reach the same goal with passing its value by writing "click".
As using the reference will prevent mistyping because the compiler checks it, the first approach should be preferred.
So calling the Method should look like this:
Assistant.addEventListenerTo(deck, MouseEvent.CLICK, showObject);
If you want to know why your version didn't work you should read a simple introduction to AS3 Events and EventDispatchers. As a short hint: if deck would dispatch an Event that has its type property set to "MouseEvent.CLICK" your listener would get fired.
While you are at it, you could improve the quality of your code by to major things:
the first one is about avoiding getting runtime Errors and prefering compile time errors: Not every instance of type Object has a method called addEventListener. In your current code, when you pass an instance to Assistant.addEventListenerTo as first parameter, that doesn't have this method (e.g. {} or an instance of type Array), the error will get thrown while your swf is displayed and it might stop displaying anything and might show an error message to the user.
If the type of the parameter is IEventDispatcher instead, the compiler will already tell you that you passed an incompatible instance.
The second one is about names and conventions, which helps other developers to read your code (an having more fun helping you).
what you called MouseEventConst is called an event type in AS3, which provides a better name for a parameter, as it being a String nobody stops anybody from passing contants of other event types like Event
the functionToTrigger is what is called a listener (or event listener)
the first letter of parameter names should be lower case
So if I would have written the static method it would look like this:
import flash.events.*;
public class Assistent{
public static function addEventListenerTo
(dispatcher:IEventDispatcher, eventType:String, listener:Function)
{
dispatcher.addEventListener(eventType, listener);
}
}

AS3: inline way to write get and set?

I was reading a tutorial and the user there was starting setters and getters like so
function get f():Number;
function set f(value:Number):void;
inside an interface, then saving it in the main file inside a variable
var testNode:INode;
and referencing them as
testNode.f;
I thought this was really handy, specially for when you have a lot of variables. Instead of having to create two functions for each private value.
However, I tried to do the same without instancing the get and set inside an interface (because I had no need for this) and I get an error saying the function doesn't have a body.
Why is that? Is there any way to write get and set in such a clean, short manner? So far I've been writing these as
public function get someVar():SomeClass {
return _someVar;
}
public function set someVar(newValue:SomeClass):void {
_someVar = newValue;
}
but it's a bit of a hassle when I have several private variables.
An interface is just a model for your class, it does not allows you to skip the definition of a function (or a getter/setter). You must declare the getter and the setter in any class implementing your interface. What you are looking for is an extension (inheritage).
If you define a class Mother.as with a getter and a setter, the class Child.as which extends Mother.as doesn't need to redefine the getter and setter.
Furthermore, if you don't plan on writing anything else inside the getter and setter, you should use a public variable. These are less resource consuming than useless get/set.

Passing Model to View constructor for Stage Instances

I'm looking for an elegant solution to setting the Model argument for a View that is a stage instance.
My View constructor looks like this:
public function View($model:Model, $controller:IController=null){ ... }
My Subclass constructor:
public function ViewSubClass($model:Model, $controller:IController=null){ ... }
The idea is that the subclass will be a UI element that I'd rather just have on stage and not have to position it manually. I've thrown around the possibility of having placeholder elements that get removed and using their positions to attach the real UI elements but it seems a little hackish to me.
I suppose I could always set the default value of the $model argument in View to null, but not all views will be stage instances so I don't exactly want to do that either.
Any thoughts are appreciated.
Flash has no way to populate constructor parameters. This is why I always suggest avoiding constructor parameters for View. If this is your own Class, I'd suggest to go ahead and fix the parent Class so it doesn't need this.
If it is not, you can use
public function VewSubClass() {
super(null, null);
}
I would be concerned here that you actually need the Model and controller, so I would make setters available on the View subclass and then populate those variables once the instance arrives on stage.
public function set model(value:Model):void {
_model = value;
//do whatever the super constructor did based on receiving the model
}
public function set controller(value:IController):void {
_controller = value;
//etc.
}
Note that it probably shouldn't be necessary for the View to know about the controller, and I wouldn't suggest that the entire model be given to the View either--just the few properties it needs. So if the Class is yours, that puts you into a better position to correct these (IMO) architectural problems.
Based on the signature you've provided, I wouldn't be at all surprised to find that the model and controller internal storage are private, rather than protected, which means you're pretty much faced with a rewrite anyway (assuming the model and controller are needed on the View).
I solved the issue by changing the ViewSubClass constructor to:
public function ViewSubClass ($model:Model=null, $controller:IController=null){ ... }
Not sure why I was thinking that the constructor had to match the superclass' constructor perfectly. I'm still open to more elegant solutions if there are any. Thanks for looking.
-Veo

Error #2136: swf contains invalid data

public function starttank(event:MouseEvent):void
{
var Tankdrive:TankDrive = new TankDrive();
Tankdrive.tankstart();
}
It's saying that something in that function contains invalid data.
I have no idea what it is, i checked TankDrive and tankstart(); and both are correct, tankstart() is a public function...
I'm stumped...
EDIT: Error:
Error #2136: The SWF file file:///C|/Users/BigRed/Desktop/TankDrive/TankDrive.swf contains invalid data.
at mainmenu/starttank()
That's the error...
And above the starttank() function is still the same...
Ok, I looked over the files.
I'm puzzled by what you are trying to do.
Your Document class is TankDrive, and it creates an instance of mainmenu, which create ANOTHER instance of TankDrive when you click a button. Which is not what I think you want to do, or you think it's allowing you to access your document class. -- it's not. It's attempting to create a whole new instance of your game.
In short, your design is not making sense, and it's also causing a conflict with the document class resulting in that error.
The quick solution is to NOT have your EventListener & handler for the click in the mainmenu class, and then call the tankstart() method of your document class instead of attempting to create a new instance of TankDrive.
First move that listener into the document class and modify like this :
main.enterTank.addEventListener(MouseEvent.CLICK, starttank);
and then move your handler to the TankDrive class and modify as follows :
public function starttank(event:MouseEvent):void
{
tankstart();
}
This is not the only way to do this, and not really the way that I would do it. But I think that discussion is beyond the scope of this question.
If you want you can contact me at prototype.in.training#gmail.com for more details on that.
The problem is that you have an instance name that's also a class name (and the compiler has assumed that you meant to reference the latter). You probably meant to call your TankDrive variable 'tankDrive', so changing your code snippet to the following will probably help:
public function starttank(event:MouseEvent):void
{
var tankdrive:TankDrive = new TankDrive();
tankdrive.tankstart();
}
It's common and recommended to start all public variable names with a lower case letter, private variables with an underscore, and class names with a capital, though this isn't enforced by the language itself, so this kind of thing can happen.
Here are some guides on conventional variable and function naming that can help you keep track of what each of your vars and functions are supposed to do:
http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/variables.html
http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/functions.html
Good luck!

How much information should one pass through events?

Say, I have a datagrid with checkboxes, and each time a checkbox is marked I store the object in the data property of flex ResultEvent
public class MyItemRenderer extends ItemRenderer{
public static var CLICK:String = "CheckBoxClick";
protected function itemRendererClickListener(data:Object):void{
dispatchEvent(new ResultEvent(MyItemRenderer.CLICK, data))
}
}
I handle the result here.
protected function checkbox_clicked(event:ResultEvent):void{
//Here I do everything I want with the data.
Alert.show(event.result.toString());
}
This is what I've been using for months, but I never wondererd if this was a bad practice.
Or let alone bad practice, what is the optimal way to do this?
it's not really 'bad'. But it does create an additional reference to an object that can potentially keep that object in memory longer (or indefinitely if not managed well).
Generally speaking, you should only store data related to the event itself in the event instance. You can use the event.target and event.currentTarget properties to reference back to the object that dispatched the event and get data that way.
In your case, your event is a check box state change. The event itself (being checked) doesn't need any data associated with it besides the item being checked (which you can get with 'target' or 'currentTarget'). So it would be more appropriate in my opinion to do the following:
Alert.show(MyItemRenderer(event.currentTarget).data.toString());
This keeps your events more reusable
Best practice for Events with data is to use a custom event (see http://cookbooks.adobe.com/post_AS3__Creating_and_dispatching_Custom_Events-17609.html) for explanation
btw, another 'best practice' is to avoid the generic Object class in your code - instead, create a value object class