I wonder which one of these methods is the best when trying get a variable from anotherClass to the Main-document-class, and why? Are there any more, even better ways?
In example no 1, and the Main-function, can the if-else statement be triggered before the checkLogin function was completely done? Thanks!
My no 1. way
public class Main extends MovieClip {
// Declaring other classes.
private var checkLogin:CheckLogin;
public function Main() {
checkLogin = new CheckLogin();
if(checkLogin.isLoggedIn == true) {
trace("Is logged in");
} else {
trace("Not logged in");
}
}
}
and
public class CheckLogin {
public var isLoggedIn:Boolean;
public function CheckLogin() {
isLoggedIn = false;
}
}
Or is it a lot better to do it this way,
(Way no 2):
public class Main extends MovieClip {
// Declaring other classes.
private var checkLogin:CheckLogin;
public function Main() {
checkLogin = new CheckLogin();
checkLogin.addEventListener("checkLogin.go.ready", checkLoginReady);
checkLogin.go();
}
public function checkLoginReady(event = null) {
if(checkLogin.isLoggedIn == true) {
trace("Is logged in");
} else {
trace("Not logged in");
}
}
}
and
public class CheckLogin extends EventDispatcher {
public var isLoggedIn:Boolean;
public function CheckLogin() {
isLoggedIn = true;
}
public function go() {
this.dispatchEvent(new Event("checkLogin.go.ready"));
}
}
Generally, using events will make your code easier to maintain.
The login check you describe seems to be instant, so approach number 1 would be ok for such a simple case.
Often the login check (or whatever process) may not be instant, for example if the CheckLogin class sent a server request and waited for the response. In this case using events is better. The Main class can listen for a LOGIN_SUCCESS or LOGIN_FAIL event and handle it when the event occurs. All the login logic stays within CheckLogin.
Also, using events will allow multiple interested classes to react, without them knowing any of the inside login process.
Related
This is AS3 question.
I have Class "addadd", "Symbol1"(Button1), "Symbol2"(Button2).
In "addadd" I have 3 functions. Function "StanishevFadd" creates object and add Event Listener, function "stanishevFremove" removes Event Listener and function "frameDOstanishev" that will be triggered when the event is added.
So, I obviously want to trigger the event from Symbol1 and stop the same event from Symbol2. Unfortunately doesn't work this way. I am totally confuzed. For example if I want to add and remove the event listener from Symbol1 only - YES works, but I am not able to create event from Symbol1 and remove the same event from Symbol2 in class addadd. Please help guys, please!
public class addadd
{
var stanishev:stanishev_line = new stanishev_line;
public function addadd()
{
}
public function stanishevFadd()
{
Main.display.addChild(stanishev);
stanishev.gotoAndPlay("start");
stanishev.addEventListener(Event.ENTER_FRAME, frameDOstanishev);
}
public function stanishevFremove()
{
stanishev.removeEventListener(Event.ENTER_FRAME, frameDOstanishev);
}
public function frameDOstanishev(e:Event)
{
trace (stanishev.currentFrame);
}
}
//------------------------------
public class Symbol1 extends SimpleButton
{
var call_creator:addadd = new addadd;
public function Symbol1()
{
// constructor code
addEventListener(MouseEvent.MOUSE_OVER, eventResponse);
}
function eventResponse(e:MouseEvent)
{
call_creator.stanishevFadd();
}
}
//----------------------
public class Symbol2 extends SimpleButton
{
var call_creator:addadd = new addadd;
public function Symbol2()
{
// constructor code
addEventListener(MouseEvent.MOUSE_DOWN, eventResponse2);
}
function eventResponse2(e:MouseEvent)
{
call_creator.stanishevFremove();
}
}
OK, I am not sure what the overall purpose of this whole thing, so I am going to call this thing OddView. I'm going to try to get close to what it looks like you are trying to do in a more OO way.
I believe it should be possible for you to encapsulate all of this behavior without involving your Main Class, and there are a lot of reasons not to involve it, especially not with static variables like you're doing.
public class OddView extends Sprite {
protected var _btn1:SimpleButton;
protected var _btn2:SimpleButton;
protected var _stanishev:StanishevLine;//note I changed your Class name to be more in line with AS3 standards
public function OddView() {
super();
}
public function get btn1():SimpleButton {
return _btn1;
}
public function set btn1(value:SimpleButton):void {
if (value != _btn1) {
if (_btn1) {
removeEventListener(MouseEvent.MOUSE_OVER, goToState2);
}
_btn1 = value;
if (_btn1) {
_btn1.addEventListener(MouseEvent.MOUSE_OVER, goToState2);
}
}
}
public function get btn2():SimpleButton {
return _btn2;
}
public function set btn2(value:SimpleButton):void {
if (value != _btn2) {
if (_btn2) {
removeEventListener(MouseEvent.MOUSE_OVER, goToState1);
}
_btn2 = value;
if (_btn2) {
_btn2.addEventListener(MouseEvent.MOUSE_OVER, goToState1);
}
}
}
public function get stanishev():StanishevLine {
return _stanishev;
}
public function set stanishev(value:StanishevLine):void {
if (value != _stanishev) {
if (_stanishev) {
cleanUp(null);
}
_stanishev = value;
initStanishev();
}
}
public function initStanishev():void {
if (_stanishev) {
_stanishev.visible = true;
_stanishev.goToAndPlay('start');
addEventListener(Event.ENTER_FRAME, showStanishevFrame);
addEventListener(Event.REMOVED_FROM_STAGE, cleanUp);
}
}
public function goToState1(e:Event) :void {
goToAndStop(1);
}
public function goToState2(e:Event):void {
goToAndStop('State2');
}
public function showStanishevFrame(e:Event):void {
if (stanishev) {
trace('current frame', stanishev.currentFrame);
}
}
public function cleanUp(e:Event):void {
removeEventListener(Event.ENTER_FRAME, showStanishevFrame);
removeEventListener(Event.REMOVED_FROM_STAGE, cleanUp);
}
}
Note that I'm assuming that you're going to apply OddView as the Base Class of a library symbol. I'm not including any instantiation or positioning logic, since I tend to use the stage for those things.
Note that the reason I check for existence on the stage instances is that it is theoretically possible for someone to assign OddView as the Base Class and not put a btn1, btn2, or stanishev on the stage of that library symbol.
However, this Class is written assuming you're going to handle the visual parts of those 3 items by placing btn1, btn2, and stanishev on the stage where you want them to be.
Also note that I strongly suspect that most of this is completely unnecessary. It's quite possible that you could handle most of this by simply using the over state of btn1. However, that doesn't completely account for why you want to only remove the event listener and take no other action when btn2 is cicked. So I went for "overkill" in the absence of real info about what you're actually trying to accomplish.
Note on the edits
Note what I'm doing there in the setter--if there was already a value stored, we remove the listeners that were on that old, outgoing, listener. Then if the incoming value is not null, we add the new listener.
I still suspect you don't need to do so much, but considering the information you have provided, this should help point you in the right direction.
You could make the variable stanishev in you addadd class a static variable. However I would not recommend doing this, one reason being you can only have one instance of stanishev. Hopefully #Amy Blankenship will tell you how to completely redesign your program, because it needs to be redesigned. This approach will work though, you should also add conditionals to the functions that add and remove eventListeners to stanishev to see if stanishev already has an eventlistener or does not have one.
public class addadd
{
public static var stanishev:stanishev_line = new stanishev_line;
public function addadd()
{
}
public function stanishevFadd()
{
Main.display.addChild(stanishev);
stanishev.gotoAndPlay("start");
stanishev.addEventListener(Event.ENTER_FRAME, frameDOstanishev);
}
public function stanishevFremove()
{
stanishev.removeEventListener(Event.ENTER_FRAME, frameDOstanishev);
}
public function frameDOstanishev(e:Event)
{
trace (stanishev.currentFrame);
}
}
public class Symbol1 extends SimpleButton
{
public function Symbol1()
{
// constructor code
addEventListener(MouseEvent.MOUSE_OVER, eventResponse);
}
function eventResponse(e:MouseEvent)
{
addadd.stanishev.stanishevFadd();
}
}
public class Symbol2 extends SimpleButton
{
public function Symbol2()
{
// constructor code
addEventListener(MouseEvent.MOUSE_DOWN, eventResponse2);
}
function eventResponse2(e:MouseEvent)
{
addadd.stanishev.stanishevFremove();
}
}
I'm new to Action-script OOP and i need to know how to chain methods like this example i have
I.$(button).bind('click',clickButton).bind('rollover',overButton).bind('rollout',outButton)
First i need to remove the I. to use dollar sign only like jQuery :) to select MovieClip and apply any action on it second issue that i have because this way i'm using static Methods Action-script restrict's me to use only static property saving the last one who called the action here is the class code to know what i mean:
package com.MAIN
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class I extends Sprite
{
private static var cSelector:Sprite;
public static function $(selector:Sprite)
{
cSelector = selector
return I;
}
public static function alpha(val:Number)
{
cSelector.alpha = val;
return I;
}
// bind mouse event to the element
public static function bind(EventStr,func:Function)
{
var func1:Function = function(e:MouseEvent){
func(cSelector);
}
// select the event from the list
if(typeof(EventStr) == 'string'){
// map the events in lowercase
var events:Object = {click:'CLICK',rollover:'ROLL_OVER',rollout:'ROLL_OUT',dblclick:'DOUBLE_CLICK',mousedown:'MOUSE_DOWN',mousemove:'MOUSE_MOVE',mouseout:'MOUSE_OUT',mouseover:'MOUSE_OVER',mouseup:'MOUSE_UP',mousewheel:'MOUSE_WHEEL'};
// check if the event exists in the list
if(events[EventStr] && MouseEvent[events[EventStr]]){
cSelector.addEventListener(MouseEvent[events[EventStr]],func1);
}
}else if(typeof(EventStr) == 'object'){
// add the event
cSelector.addEventListener(EventStr,func1);
}
return I;
}
public static function remove()
{
cSelector.parent.removeChild(cSelector);
return I;
}
}
}
Here you go, some steps in the right direction. However, this is a really, really, really crappy idea.
//$.as
package
{
import flash.display.DisplayObject;
//NOTE: there's NO class definition
public function $( selector : DisplayObject ) : IDisplayObject
{
//traverse displaylist to find <code>selector</code>
//and return an instance of IDisplayObject that holds the reference
}
}
//IDisplayObject.as
package
{
public interface IDisplayObject{
function alpha( value : Number ) : IBinding;
}
}
//IBinding.as
package jquery
{
public interface IBinding{
function bind( eventName : String, callback : Function, ...parameters ):void;
}
}
Once you've created concrete implementations of these you can do:
$( someMC ).alpha( .5 ).bind( 'click', function(){ trace( 'what a miraculously crappy idea !!!!' ) } );
You could try it like this:
interface Test {
function doBla(): Test
function moreBla(): Test
}
public class StaticTest {
private static const instance: Test = new InternalTest()
public static doBla() : Test {
return instance.doBla();
}
public static moreBla() : Test {
return instance.moreBla();
}
}
internal class InternalTest implements Test {
function doBla(): Test {
trace("bla");
return this;
}
function moreBla(): Test {
trace("more bla");
return this;
}
}
I have this situation where I declare inside my main class a function that looks like this:
public class Main extends MovieClip
{
public static var instance:Main;
public function Main()
{
// constructor code
welcomeScreen();
instance = this;
}
public final function welcomeScreen():void
{
//some code in here
}
public final function startLevelOne():void
{
//some other code here
}
}
In some other class I use this statement to fire a reset:
restart.addEventListener('click', function() {
Main.instance.welcomeScreen();
});
Somehow in another class I try to use the same statement for 'startLevelOne' but it seems it is not working and gives the fallowing error:
1195: Attempted access of inaccessible method startLevelOne through a reference with static type Main.
Any ideas?
UPDATE #1
The class where I try to access the function is in full this one:
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}
}
UPDATE #2
I have pasted the full code of the main definition here http://pastebin.com/s6hGv7sT
Also the other class could be found here http://pastebin.com/s6h3Pwbp
UPDATE #3
Even though the problem was solved with a workaround, I still cannot understand where was the problem.
I would recommend to leave the static instance (singleton), and work event-based. Now you make all functions public, which is not desirable. It's not that hard to use custom events. See this is how your Main class could look:
public class Main extends MovieClip
{
public function Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
}
public function handleAddedToStage(event:Event)
{
this.removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
this.showWelcomeScreen();
stage.addEventListener(ScreenEvent.SHOW_WELCOME_SCREEN, handleScreenEvent);
stage.addEventListener(ScreenEvent.SHOW_LEVEL, handleScreenEvent);
}
private function handleScreenEvent(event:ScreenEvent):void
{
switch (event.type)
{
case ScreenEvent.SHOW_WELCOME_SCREEN:
{
this.showWelcomeScreen()
break;
}
case ScreenEvent.SHOW_LEVEL:
{
// event.data contains level number
this.startLevel(event.data);
break;
}
default:
{
trace("Main.handleScreenEvent :: Cannot find event.type '" + event.type + "'.");
break;
}
}
}
private function showWelcomeScreen():void
{
trace("show WelcomeScreen")
//some private code in here
}
private function startLevel(level:int):void
{
trace("start level: " + level)
//some other private code here
}
}
This is how the custom event class should look (ScreenEvent.as). Note it has an optional parameter called data. You can pass any value (objects, numbers, strings etc) into this. To the example as clear as possible, I used one event-class for both actions, you can also choose to make more specific custom events for other actions with more detailed parameters, you would have names like ScreenEvent, LevelEvent, PlayerEvent, GameEvent etc etc..
At the top of the class the (static constant) types are defined. An event should only have getters.
package
{
import flash.events.Event;
public class ScreenEvent extends Event
{
public static const SHOW_WELCOME_SCREEN:String = "ScreenEvent.showWelcomeScreen";
// event.data contains level number
public static const SHOW_LEVEL:String = "ScreenEvent.showLevel";
private var _data:String;
public function ScreenEvent(type:String, data:String):void
{
super(type);
this._data = data;
}
public function get data():String
{
return this._data;
}
override public function clone():Event
{
return new ScreenEvent(this.type, this._data);
}
}
}
.. Anywhere in your code you can dispatch the event to the stage.
// dispatch event to Main (stage). Should show welcome screen in our case
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_WELCOME_SCREEN));
// show level 2
stage.dispatchEvent(new ScreenEvent(ScreenEvent.SHOW_LEVEL, 2));
I know, its a bit more code, it looks more difficult at first but if the project grows, it will help a lot. The difference with events is 'this could happen, and when it happens, do this' instead of 'do this here, do that over there'
The advantage is that if you remove the event listener in the Main class, nothing will break (loosely coupled). This makes it easier to maintain, it saves a singleton, and you have the ability to extend the Main class if you want to.
I think you wrote
Main.startLevelOne();
instead of
Main.instance.startLevelOne();
Hmm. Given your code, there is only one serious question - what is PerwollGame? You have there public static var instance:PerwollGame; and you assign it an object of type Main. Perhaps that PerwollGame has a startLevelOne() function with a different signature, that obscures your function in the Main class. Also, the other people who answered you are right as well, you should never use nested functions in your code, really put that listener of yours out from inline declaration.
Judging from your coding style and the error reported, I would assume you did this.
public static function startLevelOne():void
There is a fine line between static methods and instantiated objects.
Also never use nested functions
public class LevelBrief extends MovieClip
{
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', onMyClick )
}
public functiononMyClick (e:Event) {
Main.instance.startLevelOne();
});
}
}
I assume that when you register the listener Main.instance is not already assigned.
Did you try to trace Main instance here?
public function LevelBrief()
{
// constructor code
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
trace(Main.instance); // I assume Main.instance is null
}
what about if you add the listener in another method in LevelBrief like :
public function registerListeners():void{
trace("Main.instance == null? -> " + (Main.instance == null)); //not null here if called later.
startBut.addEventListener('click', function() {
Main.instance.startLevelOne();
});
}
i just know this is a dumb question, so excuse me in advance.
i want to essentially classify a simple function in it's own .as file. the function compares integers. but i don't know how to call the class and receive a boolean return.
here's my class
package
{
public class CompareInts
{
public function CompareInts(small:int, big:int)
{
compare(small, big);
}
private function compare(small:int, big:int):Boolean
{
if (small < big)
return true;
else
return false;
}
}
}
so now i'd like to write something like this:
if (CompareInts(1, 5) == true). or output 'true' by writing trace(CompareInts(1, 5));
You have 2 options:
1) Make your compare function public and static.
static public function compare(small:int,big:int):Boolean {
{
if (small < big)
return true;
else
return false;
}
}
And call it:
CompareInts.compare(1,5);
2) You don't actually need a class. You can just use a function. As long as there's only one public definition per AS file, you'll be fine (by that I mean that at the "top" level you can have a public class, an interface, a public function, a public var or a public namespace. It won't work if you try to have more than one.
package {
public function compare(small:int,big:int):Boolean {
{
if (small < big)
return true;
else
return false;
}
}
Or, you could inline this into a single line and ditch the class / function entirely (parens are not neccesary, I just added them for clarity):
var compare:Boolean = (small < big);
You are creating a Class and then function that are members of that Class so for calling them you have to instanciate the Class and then call the function of the instance created.
Also CompareInts is the constructor of the class it can't return anything
the working code corresponding to your class will be:
package {
public class CompareInts {
public function CompareInts(){}
public function compare(small:int, big:int):Boolean {
if (small < big)
return true;
else
return false;
}
}
}
new CompareInts().compare(1, 2);
But this a litle bit overkill so what you can do is create a static function into your class and then call it directly without the needed to instanciate the class.
package {
public class Compare {
public static function compareInts(small:int, big:int):Boolean {
if (small < big)
return true;
else
return false;
}
}
}
Compare.compareInts(1, 2)
If you don't want to group more functions into a Class you can always declare a single function into a Package:
package {
public function compareInts(small:int, big:int):Boolean {
if (small < big)
return true;
else
return false;
}
}
An AS3 constructor can never have a return value. If you want to keep this method in a class, then have the constructor just call an init() function and have init() return values.
Hope that helps clear up the "why?" that might be swirling in your head.
It's not a matter of life or death but I wonder if this could be possible:
I got a couple of events from one type of custom event (FormEvent) now I got a FormListener that listens to all those events and handles them according to the event type. Instead of adding one eventListener at the time I wish to add all events at once.
so now it looks like this:
private function addListeners():void {
addEventListener(FormEvent.SHOW_FORM, formListener);
addEventListener(FormEvent.SEND_FORM, formListener);
addEventListener(FormEvent.CANCEL_FORM, formListener);
}
private function formListener(event:formEvent):void {
switch(event.type){
case "show.form":
// handle show form stuff
break;
case "send.form":
// handle send form stuff
break;
case "cancel.form":
// handle cancel form stuff
break;
}
}
but instead of adding every event one at the time I would rather be doing something like
private function addListeners():void {
addEventListener(FormEvent.*, formListener);
}
I wonder if something like this is possible, i would love it. I work with loads of events :)
You only really need one event listener in this case anyhow. That listener will be listening for any change with the form and a parameter equal to what the change was becomes available to the event listener function. I will show you, but please remember that this is a pseudo situation and normally I wouldn't dispatch an event off of something as simple as a method call because the dispatch is implied so there is no real need to listen for it.
First the Custom Event
package com.yourDomain.events
{
import flash.events.Event;
public class FormEvent extends Event
{
//Public Properties
public static const CANCEL_FORM:int = "0";
public static const SHOW_FORM:int = "1";
public static const SEND_FORM:int = "2";
public static const STATE_CHANGED:String = "stateChanged";
//Private Properties
private var formState:int;
public function FormEvent(formState:int):void
{
super(STATE_CHANGED);
formState = formState;
}
}
}
So we have just created our custom event class and we have set it up so that we can catch the state through the listener function as I will demonstrate once done with the pseudo form class that will dispatch the for said custom event.
Remember that this is all hypothetical as I have no idea what your code looks like or how your implementing things. What is important is to notice that when I dispatch the event I need to send a parameter with it that reflects what the new state is.
package com.yourDomain.ui
{
import flash.events.Event;
import flash.events.EventDispatcher;
import com.yourDomain.events.FormEvent;
public class Form extends EventDispatcher
{
public function Form():void
{
//Anything you want form to do upon instantiation goes here.
}
public function cancelForm():void
{
dispatchEvent(new Event(FormEvent.CANCEL_FORM);
}
public function showForm():void
{
dispatchEvent(new Event(FormEvent.SHOW_FORM);
}
public function sendForm():void
{
dispatchEvent(new Event(FormEvent.SEND_FORM);
}
}
}
And finally we create the document class that will listen for it. Please know that I realize it isn't logical to create a listener that fires when you call a method of a class because you obviously know you called the method, but for this example it will due.
package com.yourDomain.ui
{
import com.yourDomain.ui.Form;
import com.yourDomain.events.FormEvent;
//Form is in the same package so we need not import it.
public class MainDocumentClass
{
private var _theForm:Form;
public function MainDocumentClass():void
{
_theForm = new Form();
_theForm.addEventListener(FormEvent.STATE_CHANGED, onFormStateChange, false, 0, true);
/*
The following three method calls each cause the
FormEvent.STATE_CHANGE event to be dispatched.
onFormStateChange is notified and checks what
the last change actually was.
*/
_theForm.cancelForm();
_theForm.showForm();
_theForm.sendForm();
}
private function onFormStateChange(e:FormEvent):void
{
switch(e.formState)
{
case CANCEL_FORM:
trace('The form was canceled');
break;
case SHOW_FORM:
trace('The form was revealed');
break;
case SEND_FORM:
trace('The form was sent');
break;
}
}
}
}
I hope that this was helpful, its late and I may have to revise some things later, but this should help get an understanding of how to make your own events and to customize how things work.
I don't know of any routines that let you do that directly, but you could write your own. The syntax here won't be perfect, but here's a first pass:
private function addMultipleEventListeners( evts:Array, callback:function ):void
{
for each( var evt:Event in evts )
{
addEventListener( evt, callback );
}
}
You could then call that routine like so:
var evts:Array = [ FormEvent.SHOW_FORM, FormEvent.SEND_FORM, FormEvent.CANCEL_FORM ];
addMultipleEventListeners( evts, formListener );