AS3 override public function both are called? - actionscript-3

I am a little confused by this concept.
If I override a public function in a base class, I would have thought that this override function is called and the original is ignored? though this doesn't seem to be the case...
public class AbstractScreen extends Sprite
{
public function AbstractScreen()
{
}
public function updateLanguage():void
{
trace("WARNING: need to override public function updateLanguage()");
}
}
public class Start extends AbstractScreen
{
override public function updateLanguage():void
{
title.text = _model.language.start
title.setTextFormat(titleFormat);
}
}
public class ViewManager extends Sprite
{
private var _model:Model;
private var _screens:Array;
public function ViewManager(model:Model)
{
_model = model;
_model.addEventListener(AppEvent.INIT_VIEW, initViews);
_model.addEventListener(AppEvent.UPDATE_VIEW, updateView);
_model.addEventListener(AppEvent.CHANGED_LANGUAGE, changeLanguage);
}
private function initViews(e:AppEvent):void
{
trace("View Manager: initViews");
_screens = new Array(new Start(_model), new TakePhoto(_model));
dispatchEvent(new ViewEvent(ViewEvent.VIEW_READY));
}
private function changeLanguage(e:AppEvent):void
{
for each (var screen:AbstractScreen in _screens)
{
screen.updateLanguage();
}
}
}
If my model dispatches a CHANGED_LANGUAGE event, the text in the views gets updated, But I also get a trace of "WARNING: need to override public function updateLanguage()" What could I be doing wrong?

You are right, this should not call the base class function. Are you sure there is no call to
super.initLanguage()
within your override?
Most IDE's add this call in the function body automatically, if they create an override for you.
EDIT
From your edit I see your are iterating over two objects of the types Start and TakePhoto. I assume TakePhoto is also derived from AbstractScreen and the trace may be comming from this one.
Also I suggest to use the abstract base class in your iteration.
for each (var screen:AbstractScreen in _screens)
{
screen.updateLanguage();
}

Related

AS3 How to add event listener in Class A by using Class B and remove the same event using Class C?

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();
}
}

AS3: Type was not found or was not a compile-time constant

I'm having an issue with a little app I'm trying to create at the moment, it's my first try and dealing with classes but for some reason I can't create any instances of the class even if it's imported into the document. Here's the code for the class (named "Players"):
package
{
public class Player
{
public function Player(name_:String)
{
}
public var name_:String;
private var alignment:int;
public var healed:Boolean = false;
public var revealed:Boolean = false;
public var attacked:Boolean = false;
public var dead:Boolean = false;
public function action(target:Player)
{
}
public function describe():String
{
}
}
public class Citizen extends Player
{
public function Citizen(name_:String)
{
alignment = 1;
}
override public function action(target:Player)
{
}
override public function describe():String
{
return "Citizen";
}
}
public class Investigator extends Player
{
public function Investigator(name_:String)
{
alignment = 1;
}
override public function action(target:Player)
{
target.revealed = true;
}
override public function describe():String
{
return "Cop";
}
}
public class Doctor extends Player
{
public function Doctor(name_:String)
{
alignment = 1;
}
override public function action(target:Player)
{
target.healed = true;
}
override public function describe():String
{
return "Doctor";
}
}
public class Mafioso extends Player
{
public function Mafioso(name_:String)
{
alignment = -1;
}
override public function action(target:Player)
{
target.attacked = true;
}
override public function describe():String
{
return "Mafia";
}
}
}
And the code which creates the instance:
import Players;
stop();
var totalplayers:Number;
var playerArray:Array = new Array();
var playerType:Array = ["Citizen","Cop","Doctor","Mafia"];
var test:Citizen = new Citizen("James");
Both are in the same folder. I get the error code 1046 described in the title but I honestly have no idea why, flash picks it up in the code hints yet it comes up with that! Any help would be appreciated.
Also secondary question, I'll never initiate the Player class (except through inheritance with the other classes), so can I make it private?
Thanks
I'm assuming all that code is in a file called Players.as.
This is wrong. Each file should contain one class and the class should be the same name as the .as file.
You currently have two classes (Player and Citizen) within one file.
What you need to do is take the Player class you've defined and place it in its own .as. file with the same name (Player). Do the same for Citizen.
Then you can use:
import Player;
import Citizen;
Though this won't be necessary because you don't need to import classes that are in the same directory that you're trying to access it from.
As for the error, you're getting that because Flash is trying to find the class Players and you don't have a class with that name (just a file with that name).
Per your secondary question regarding whether ActionScript supports private classes, if you have a class that would not otherwise be accessed except internally by a public class you may define it as internal.
Internal classes are visible to references inside the current package.
If you do not want a class to be publicly visible outside a package, place the class inside a package and mark the class with the internal attribute. Alternatively, you can omit both the internal and public attributes, and the compiler automatically adds the internal attribute for you. You can also define a class to only be visible inside the source file in which it is defined. Place the class at the bottom of your source file, below the closing curly bracket of the package definition.
In the following example, both X and Y classes are defined in a single file (X.as). X may be referenced and instantiated as normal; however, Y is internal to X and only visible from from the scope of X.
package
{
import flash.display.Sprite;
public class X extends Sprite
{
public function X()
{
super();
var y:Y = new Y();
}
}
}
internal class Y
{
public function Y()
{
trace("internal Y ctor.");
}
}
This pattern is helpful when a class requires small data models that would not otherwise be accessed outside of a class.
Agree with others here should be as shown below (note filenames match class names, file names are denoted in brackets above code blocks). Also you wrote import Players instead of import Player, regardless as the other poster wrote if all classes are currently in the default package the import is unnecessary.
[Player.as]
package
{
public class Player
{
public function Player(name_:String)
{
}
public var name_:String;
private var alignment:int;
public var healed:Boolean = false;
public var revealed:Boolean = false;
public var attacked:Boolean = false;
public var dead:Boolean = false;
public function action(target:Player)
{
}
public function describe():String
{
}
}
}
[Citizen.as]
package
{
public class Citizen extends Player
{
public function Citizen(name_:String)
{
alignment = 1;
}
override public function action(target:Player)
{
}
override public function describe():String
{
return "Citizen";
}
}
}
[Investigator.as]
package
{
public class Investigator extends Player
{
public function Investigator(name_:String)
{
alignment = 1;
}
override public function action(target:Player)
{
target.revealed = true;
}
override public function describe():String
{
return "Cop";
}
}
}
[Doctor.as]
package
{
public class Doctor extends Player
{
public function Doctor(name_:String)
{
alignment = 1;
}
override public function action(target:Player)
{
target.healed = true;
}
override public function describe():String
{
return "Doctor";
}
}
}
[Mafioso.as]
package
{
public class Mafioso extends Player
{
public function Mafioso(name_:String)
{
alignment = -1;
}
override public function action(target:Player)
{
target.attacked = true;
}
override public function describe():String
{
return "Mafia";
}
}
}
It's unfortunate there's no abstract classes as this would be an ideal situation for an abstract class and abstract methods.

Overriding a public variable with set

I have a base class like this
class Base {
public var space:Number;
}
which gets extended by
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
This doesn't compile. Say, you don't have control of the base class, what ways is there implement the same thing?
The obvious is create a function setSpace(), but this object is being embedded in an already existing system that use the public space.
Thanks in advance.
Your base class should be defined that way:
class Base {
// Don't use public variables. Make them private and define setters and getters
private var space_:Number;
public function get space():Number {
return space_;
}
public function set space(v:Number):void {
if (space_ === v) return;
space_ = v;
}
}
And then it can be overriden that way:
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
Edit:
I missed the part where you say you don't have control over the base class. In that case, hope that space is defined as a getter/setter (it should be if the class is implemented properly). If not, you'll indeed have to use a function such as getSpace and setSpace.
From Adobe:
Class member variables that are declared using the var keyword cannot
be overridden in a subclass.
Using a setter is not an option in your case. If you need to preserve the interface, use composition instead of inheritance:
class Desc {
private var _base:Base;
public function set space(space:Number):void {
//code
this._base.space = space;
}
}

Can Objects not on display-list access root or any object that is added on displaylist?

Suppose in document class
public class Test extends MovieClip
{
public function Test()
{
var object1:ClassA = new ClassA();
//addChild(object1);
object1.accessRoot();
}
}
public class A extends MovieClip
{
public function accessRoot()
{
var mc : MovieClip = root as MovieClip;
mc.box.visible = false;
}
}
Now box is placed at stage. but when Class A is added to Test Class, it works and when object of Class A is not added in Test constructor, root becomes in-accessible. Is there any way that objects not on display-list can access root or display-list objects??
I would not recommend having your classes fiddle around with root or stage, it's way better to dispatch events and have the proper encapsulation.
Hacky way:
public class A extends MovieClip
{
private var _root:MovieClip;
public function A(root:MovieClip)
{
_root = root;
}
public function accessRoot()
{
_root.box.visible = false;
}
}
Proper way:
public class A extends MovieClip
{
public static const ACCESS_ROOT:String = "access_root";
public function accessRoot()
{
dispatchEvent(new Event(ACCESS_ROOT));
}
}
// in your document class
var myA:A = new A();
myA.addEventListener(A.ACCESS_ROOT, handleAccessRoot);
public function handleAccessRoot(e:Event):void{
box.visible = false;
}
I normally create a sort of base class that holds a reference to the document class - or "main" class. Anything that I create from here that should need reference to anything defined in Main would extend Element. Example:
The Main class (or document class):
public class Main extends MovieClip
{
/**
* Constructor
*/
public function Main()
{
var obj:MyElement = new MyElement();
obj.main = this;
// stage will be outputted
}
}
Element - which stores reference to the main class.
It also contains an init() function which I generally use in place of a constructor by overriding it.
public class Element extends MovieClip
{
private var _main:Test;
public function set main(m:Main):void
{
_main = m;
init();
}
/**
* Called when _main is defined
*/
protected function init():void
{
// override me
}
public function get main():Main{ return _main; }
}
And here's how you would use Element as a base class for your classes:
public class ClassA extends Element
{
/**
* Override init rather than using a constructor
*/
override protected function init():void
{
trace(main.stage);
}
}
The only thing really to note is that you of course have to set the _main property whenever you create an object. (as shown on line 9 of Main).

referencing variable in document class from another class

I need to increment an integer variable in a function within the document class upon transpiring event in another class. I can't seem to figure out how to call the function and reference the variable.
as3 newbie, please help!
The proper scope needs to be in place and the proper packaging.
Declare a static variable to handle your access to the Main Document Class
private static var _instance:Main;
public static function get instance():Main { return _instance; }
public function Main() { // constructor
_instance = this;
}
Declare some getters and setters in the Main Document Class
private var _foo:int = 0;
public function get foo():int{
return _foo;
}
public function set foo(value:int):void {
_foo= value;
}
And then in any class you need you can change to something as follows,
public class O {
public function O() {
Main.instance.set(Main.instance.get() + 1);
}
}
simple example, defining a variable 'test' in the document class:
package {
public class DocumentClass extends Sprite {
public static var test:Number = 3;
public function DocumentClass() {
test = 4;
}
}
}
now access the 'test' variable in another class:
package {
public class OtherClass extends Sprite {
public function OtherClass() {
DocumentClass.test = 5;
}
}
}
does this apply to your code?