AS3: overriding protected var in subclass - actionscript-3

I'm having a blackout here. I thought I understood these principles, but I can't seem to get it working anymore. I want to let a DeleteButton inherit from a general Button class. This DeleteButton should alter the protected padding values and have a static label. This is what I have:
public class Button
{
private var _labelText:String;
protected var _paddingX:Number = 10;
protected var _paddingY:Number = 5;
public function Button( labelText:String ):void
{
_labelText = labelText;
}
}
public class DeleteButton extends Button
{
public function DeleteButton():void
{
_paddingX = 5;
_paddingY = 2;
super( 'x' );
}
}
Now, I thought the altered _paddingX and _paddingY values in the inherited class would bubble up to the super class. But they don't. The DeleteButton is still constructed with the default values of the super class. I can't figure out how to do it anymore. What am I missing here?
Thanks in advance.
Edit:
I guess I had AS3's implementation mixed up with PHP's. This 'equivalent' example in PHP is perfectly legal:
class Button
{
protected $_paddingX = 10;
protected $_paddingY = 5;
public function __construct( $label = '' )
{
var_dump( $label . ':' );
var_dump( $this->_paddingX );
var_dump( $this->_paddingY );
echo '<br>';
}
}
class DeleteButton extends Button
{
public function __construct()
{
$this->_paddingX = 5;
$this->_paddingY = 2;
parent::__construct( 'x' );
}
}
$button = new Button( 'browse' );
$deleteButton = new DeleteButton();
// this outputs:
string(7) "browse:" int(10) int(5)
string(2) "x:" int(5) int(2)

when you call the super() function you also initialise all of the super classes variables. So in your example when you call..
_paddingX = 5;
_paddingY = 2;
..before calling super(), you are actually creating arbitrary values inside that function. So you're getting it right its just that those variables dont exist until the super() function has been called.
public class Button
{
private var _labelText:String;
protected var _paddingX:Number;
protected var _paddingY:Number;
public function Button( labelText:String, paddingX:Number=10, paddingY:Number=5 ):void
{
_paddingX = paddingX;
_paddingY = paddingY;
_labelText = labelText;
}
public function traceVars():void {
trace(_labelText);
trace(_paddingX);
trace(_paddingY);
}
}
public class DeleteButton extends Button
{
public function DeleteButton():void
{
super( 'x', 5, 2 );
}
}
Do this instead, this way you can keep the default values, as 10 and 5, but change them if needed. Now if you call this on the main timeline you it should work for you.
var but:DeleteButton = new DeleteButton();
but.traceVars();
Hope this explains it :)
George

I think calling super('x') before setting the _paddingX and _paddingY could make a difference:
public function DeleteButton():void
{
super( 'x' );
_paddingX = 5;
_paddingY = 2;
}

What you could do is to override getters:
public class Button
{
private var _labelText:String;
protected var _paddingX:Number = 10;
protected var _paddingY:Number = 5;
public function Button( labelText:String ):void
{
_labelText = labelText;
}
protected function get paddingX():Number
{
return _paddingX;
}
// get paddingY ommited for brevity
}
public class DeleteButton extends Button
{
public function DeleteButton():void
{
super( 'x' );
}
override protected function get paddingX():Number
{
return 42;
}
}
The parent Button constructor will now use the overridden getter from child DeleteButton class.
You could also set _paddingX/Y to private to hide them from the implementation, and add new _paddingX/Y in DeleteButton. This however, seems like a dirty practice, because the properties in DeleteButton aren't enforced by API.

Related

ActionScript 3.0 How to call SoundManager to all classes

i have 3 classes. the SoundManager.as, MainMenu.as, and OnGame.as.
How can I call SoundManager on MainMenu.as and OnGame.as properly?
I tried:
MainMenu.as:
var sound:SoundManager = new SoundManager();
OnGame.as:
var sound:SoundManager = new SoundManager();
but when i turn off the bgmusic on OnGame.as, the bgmusic on MainMenu doesn't turn off.
Sorry for my bad english and explanation. please help me.
//edited
When i call function 'MUTE' from the SoundManager in onGame.as and go back to mainmenu, the bgmusic in MainManu.as is not muted. help please me.
SoundManager.as
public static var mVolume:SoundTransform = new SoundTransform();
public static var mChannel:SoundChannel = new SoundChannel();
public static var mPosition:Number;
public static var music:Sound = new Sound();
public static var Music:Boolean = true;
public function LOADMUSIC():void {
if(Music){
UNMUTE();
}else {
MUTE();
}
music.addEventListener(Event.COMPLETE, LOADMUSIC);
mChannel = music.play();
mChannel.addEventListener(Event.SOUND_COMPLETE, ONCOMPLETE);
}
public function ONCOMPLETE(e:Event):void {
if(DataBase.music){
UNMUTE();
}else{
MUTE();
}
e.currentTarget.removeEventListener(Event.SOUND_COMPLETE, ONCOMPLETE);
LOADMUSIC();
}
public function REMOVE_MUSIC():void{
try{
mChannel.stop();
music = null;
}catch(e:Error) {}
}
public function MUTE():void {
mVolume.volume = 0;
mChannel.soundTransform = mVolume;
}
public function UNMUTE():void {
mVolume.volume = 1;
mChannel.soundTransform = mVolume;
}
MainMenu.as
var sound:SoundManager;
btn_music.addEventListener(TouchEvent:TOUCH_END, MUSIC);
public MainMenu(sound:SoundManager){
this.sound = sound;
sound.REMOVE_MUSIC();
SoundManager.music = new BackgroundMusic01();
sound.LOADMUSIC();
}
private function MUSIC(e:TouchEvent):void {
if(SoundManager.Music){
SoundManager.music = false;
sound.MUTE();
}else {
SoundManager.Music = true;
sound.UNMUTE();
}
}
OnGame.as
var sound:SoundManager;
btn_music.addEventListener(TouchEvent:TOUCH_END, MUSIC);
public OnGame(sound:SoundManager){
this.sound = sound;
sound.REMOVE_MUSIC();
SoundManager.music = new BackgroundMusic02();
sound.LOADMUSIC();
}
private function MUSIC(e:TouchEvent):void {
if(SoundManager.Music){
SoundManager.music = false;
sound.MUTE();
}else {
SoundManager.Music = true;
sound.UNMUTE();
}
}
There's no problem in changing the background music. When i mute the bgmusic in MainMenu using MainMenu btn_music it works, it works also in OnGame. But if it is from OnGame to MainMenu or MainMenu to Ongame, the bgmusic is not muted . I don't see what's wrong. please help me. sorry for my bad english.
Singleton or some other static (global) access is one easy way to do it. But just to add an alternative solution, according to some a "better way" is to use dependency injection. A simple example of this for your situation could look like this:
First, in your MainMenu and OnGame class you add a constructor argument (effectively declaring a dependency) of a SoundManager instance:
public class MainMenu {
private var sound:SoundManager;
public function MainMenu(sound:SoundManager){
this.sound = sound;
}
}
public class OnGame {
private var sound:SoundManager;
public function OnGame(sound:SoundManager){
this.sound = sound;
}
}
Then in a higher level class, you can create a single SoundManager and pass it into the classes that need it:
public class Main {
private var sound:SoundManager;
public function Main(){
sound = new SoundManager();
}
private function showMenu():void {
var menu:MainMenu = new MainMenu(sound);
addChild(menu);
}
private function showGame():void {
var game:OnGame = new OnGame(sound);
addChild(game);
}
}
The end result is that you have a single SoundManager instance being re-used between various classes.
There are several ways to do it, one of them is to use a Singleton class.
Follow an example:
package
{
public class CustomSoundManager
{
private static var _instance:CustomSoundManager;
public function CustomSoundManager()
{
if (_instance)
{
throw new Error('CustomSoundManager... use getInstance()');
}
_instance = this;
}
public static function getInstance():CustomSoundManager
{
if (!_instance)
{
new CustomSoundManager();
}
return _instance;
}
public function soundOn():void
{
// your logic to turn the sound on
}
public function soundOff():void
{
// your logic to turn the sound off
}
}
}
So, doesn't matter where (e.g. MainMenu.as, OnGame.as), you can use just these methods:
CustomSoundManager.getInstance().soundOn();
CustomSoundManager.getInstance().soundOff();
Because i can't see what's wrong in my code. Since I only got 1 channel in my game, i used SoundMixer to mute and unmute the music background.
import flash.media.SoundMixer;
...
...
public function MUTE():void {
mVolume.volume = 0;
SoundMixer.soundTransform = mVolume;
}
public function UNMUTE():void {
mVolume.volume = 1;
SoundMixer.soundTransform = mVolume;
}
thanks.

Override parent class instance variable in subclass

In PHP it's trivial to override properties of a class in a subclass. For instance:
class Generic_Enemy {
protected $hp = 100;
protected $str = 5;
//...
}
class Boss_Enemy extends Generic Enemy {
protected $hp = 1000;
protected $str = 25;
}
Which is extremely convenient because at-a-glance you can see in what ways the subclass differs from the parent class.
In AS3 the only way I've found is through getters, which really isn't elegant at all:
public class GenericEnemy {
private var _hp:uint = 100;
private var _str:uint = 25;
public function get hp():uint {
return _hp;
}
public function get str():uint {
return _str;
}
}
public class BossEnemy extends GenericEnemy {
override public function get hp():uint {
return 1000;
}
override public function get str():uint {
return 25;
}
}
Is there a nicer way of doing this that aligns with the PHP approach?
Specifically: let's say I'm writing an API that will let a developer easily spin off his own Enemies. I would rather document that you just have to override hp and str properties rather than explain that they have to create a new getter for each property they wish to override. It's a matter of trying to create the cleanest API and the easiest to document and maintain.
Sometimes ya just have to write the SO question in order to see the (obvious) answer:
public class GenericEnemy {
protected var _hp:uint = 100;
protected var _str:uint = 25;
public function GenericEnemy(){
//...
}
}
public class BossEnemy extends GenericEnemy {
public function BossEnemy(){
_hp = 1000;
_str = 50;
super();
}
}

Calling methods from another class Action Script 3

I have two classes called 'main' and 'TimerCountDown'. I was try to call a single function 'reset' from 'TimerCountDown' in 'main' class.
This is my TimerCountDown class:
public class TimerCountDown extends MovieClip
{
public function TimerCountDown(t:TextField, timeType:String, timeValue:Number, es:String, _documentclass):void
{
this.documentclass = _documentclass;
this.tfTimeDisplay = t;
if (timeType == "seconds")
{
this.timeInSeconds = timeValue;
}
if (timeType == "minutes")
{
this.timeInSeconds = timeValue * 60;
}
this.tfEndDisplayString = es;
this.startTimer();
}
public function reset():void{
clockCounter.reset();
}
}
How can I create a reference in main class use the reset function in functions of main class? I can only do sth like
var myTimerObject:TimerCountDown = new TimerCountDown(timer, "seconds", 40, "0!", this);
but have no idea on calling reset function.
You can call it like this :
myTimerObject.reset();
You may keep a reference of myTimerObject in main class
public class Main {
private var _targetTimerObject:TimerCountDown;
public function set targetTimerObject(value:TimerCountDown):void {
_targetTimerObject = value;
}
public function someFunction():void {
if (_targetTimerObject) {
_targetTimerObject.reset();
}
}
}

Haxe: Return value of field

For some reason, I can't modify the value of a field in Haxe. Of course, this doesn't seem to be affecting all of my fields, just this one. Here's (what I'm pretty sure is) the applicable code. First, in the parent class:
class TopMenu extends Sprite
{
public function new()
{
super();
init();
}
private function init()
{
var tempField:BitmappedTextField = new BitmappedTextField( "File", 100, false );
trace( tempField.textWidth );
}
}
Then, in the child class:
class BitmappedTextField extends Sprite
{
private var _fieldText:String;
private var _fieldWidth:Int;
private var _addToStage:Bool;
public var textWidth:Int;
public function new( thisText:String, thisWidth:Int = 100, adTStg:Bool = true )
{
super();
_fieldText = thisText;
_fieldWidth = thisWidth;
_addToStage = adTStg;
textWidth = 55;
init();
}
public function init()
{
textWidth = 777;
}
}
I would expect the trace statement to return 777, but instead it will always return 55. In fact, no matter what I do, I can't seem to modify a field outside of the constructor class and then retrieve that value via the parent class. There's something horribly simple I must be missing, but I just can't figure it out. Maybe it has to do with the way Haxe uses getters and setters? Any help is appreciated, thank you.
I cant reproduce your problem however and you are missing a ; and a super call.
Try this code.
package;
import nme.display.Sprite;
import nme.display.MovieClip;
class HelloWorld extends MovieClip
{
public function new( )
{
super();
var tempField:BitmappedTextField = new BitmappedTextField();
trace( tempField.textWidth );
}
}
class BitmappedTextField extends Sprite
{
public var textWidth:Int;
public function new( )
{
super();
textWidth = 55;
init( );
}
public function init( )
{
textWidth = 777;
}
}

AS3 1120 Error on instantiating

I am trying to create a basic functionality in AS3.
I have a class like this:
package tax
{
public class Calculator
{
public function Calculator()
{
}
private var grwage:Number;
private var taxes:Number;
private var superannuation:Number;
private var insurance:Number;
private var net:Number;
public function getGrwage():Number {
return grwage;
}
public function setGrwage(grwage:Number):void {
this.grwage = grwage;
}
public function getTaxes():Number {
return grwage;
}
public function setTaxes(taxes:Number):void {
this.taxes = grwage * 0.2;
}
public function getSup():Number {
return superannuation;
}
public function setSup(superannuation:Number):void {
this.superannuation = superannuation * 0.05;
}
public function getIns():Number {
return insurance;
}
public function setIns(insurance:Number):void {
this.insurance = insurance * 0.1;
}
public function getNet():Number {
return net;
}
public function setNet(net:Number):void {
this.net = grwage - taxes - superannuation - insurance;
}
}
}
Just some getters and setters.
And in my mxml file:
import tax.Calculator;
public var calculate:Calculator = new Calculator();
calculate.setGrwage(1000);
trace(calculate.getTaxes());
trace(calculate.getSup());
trace(calculate.getIns());
trace(calculate.getNet());
I get an error 1120 Access to undefinded property when I try to access calculate. Do you have any ideas?
Thanks.
I guess you're mixing up things a bit between getters and setters. If a variable depends on another, you have to write the calculation in its getter. This variable shouldn't exist as a private member and the accesses to it must always be done through the appropriate getter.
for example:
public function getNet():Number {
return getGrwage() - getTaxes() - getSup() - getIns();
}
So here, you only need one setter (setGrwage), you can remove the others ones and put the calculation in the getters.
Note that there is a more appropriate syntax for setters and getters in AS3.
class GetSet
{
private var privateProperty:String;
public function get publicAccess():String
{
return privateProperty;
}
public function set publicAccess(setValue:String):void
{
privateProperty = setValue;
}
}
There are multiple issues with your class. So lets redesign it
The main issue you had was you were not initiating the vars before you accessed them as they had a NULL value the flash player was throwing you that error.
As you can see in the constructor I set a default value of 0 so that they will never be NULL.
package tax {
public class Calculator{
private var _grwage:Number;
private var _taxes:Number;
private var _superannuation:Number;
private var _insurance:Number;
public function Calculator() {
this._grwage = 0;
this._taxes = 0;
this._superannuation = 0;
this._insurance = 0;
}
public function get grwage():Number {
return this._grwage;
}
public function set grwage(val:Number):void {
this._grwage = val;
}
public function get taxes():Number {
return this._taxes;
}
public function set taxes(val:Number):void {
this._taxes = val * 0.2;
}
public function get superannuation():Number {
return this._superannuation;
}
public function set superannuation(val:Number):void {
this._superannuation = val * 0.05;
}
public function get insurance():Number {
return this._insurance;
}
public function set insurance(val:Number):void {
this._insurance = val* 0.1;
}
public function get net():Number {
return this._grwage - this._taxes - this._superannuation - this._insurance;
}
}
}
import tax.Calculator;
public var calculate:Calculator = new Calculator();
//Now due to the fact we are using true setter/getter methods.
calculate.grwage = 1000;
trace( calculate.taxes); // should be 0 as we are defaulting to the initial value
trace( calculate.superannuation );// should be 0 as we are defaulting to the initial value
trace( calculate.insurance );// should be 0 as we are defaulting to the initial value
trace( calculate.net );// should be 1000 as we are defaulting to the initial values of everything but grwage
The answers here are all good, but they all miss the primary point:
You're trying to get your variables before you set them.
import tax.Calculator;
public var calculate:Calculator = new Calculator();
calculate.setGrwage(1000);
trace(calculate.getTaxes());
trace(calculate.getSup());
trace(calculate.getIns());
trace(calculate.getNet());
This will throw an error (due to the way you've set up your class), because you never called setSup(), setIns(), and setNet() before trying to use them.
While your class may not be written in the best way, it is syntactically sound.
Try calling each setter before your getter. I think you'll solve your issue.