I have my main stage, and I have two objects (blocks), these two objects both extend from the "Block" class. The "Block" class is NOT extended from the Main Class.
I would LIKE to call a function, in either the "Block" class or in it's subclasses, from the Main Stage Class. The functions will do slightly different things depending which object you are calling the function (Added different things, and different number of things to an array). What is the best way to implement this?
I am sorry I have no code to show right now, I am just attempting to sit down and do it now but feel quite lost.
Not quite sure I follow so I'm going to assume you mean this.
You have a class called Block
You create two of these Block's and store them, possibly in an array from your base class.
//stage base class
var blockArray:Array = new Array()
private function createBlocks():void{
var blockOne:Block = new Block(1); //passing in an int to block, could be anything but this
// will be used to do slightly different things
var blockTwo:Block = new Block(2);
blockArray.push(blockOne...blockTwo)
}
Now in your block class
//block class
class Block{
var somethingDifferent:int; //this is where we will store the int you pass in when the blocks are made
public function Block(aInt:int){
somethingDifferent = aInt //grabbing the int
}
public function doSomething():void{
trace(somethingDifferent); //will trace out the number passed
}
}
Now back in your main class
//stage base class
private function doSomethingToBlocks():void{
//lets call doSomething on each block
Block(blockArray[0]).doSomething() //this will trace 1 because we passed that into the block in our array slot 0
Block(blockArray[1]).doSomething() //this will trace 2
}
Hopefully this is what you're after
The general idea is to define the function in the parent class and then to override the function in the subclass to do different things. Then, you can call the function on the various subclasses and it will do different things depending on the block.
A brief example:
Block class:
public function getBlockType():String
{
return "I am a plain block";
}
First block subclass
public override function getBlockType():String
{
return "I am a cool block";
}
Second block subclass:
public override function getBlockType():String
{
return "I am an even cooler block";
}
Stage:
//add the first block
var coolBlock:CoolBlock = new CoolBlock();
addChild(coolBlock);
//add the second block
var coolerBlock:EvenCoolerBlock = new EvenCoolerBlock();
addChild(coolerBlock);
//call the functions
trace(coolBlock.getBlockType());//outputs "I am a cool block"
trace(coolerBlock.getBlockType());//outputs "I am an even cooler block"
Related
Hi guys,
I have two objects on stage so I presume they are in the Display list as well (Progress_mc, Ship_mc). I have Calculator class which doesn't represent any visual shape or anything but as3 code so it isn't in the display list.
What is the best way to work with the properties of Progress_mc?
Example: Calculator_as has to receive Progress_mc.width any time width has been changed and after some calculation Calculator has to send some calculated results to Ship_mc.x.
I was thinking if I have to addChild(Calculator) on stage so I can have access to those MCs in Calculator.as but this class isn't a visual object so I am not sure this is the right way.
Or I have to do this (code below) in Calculator class and then try to access the properties but I this way wont work either because the properties wont be of the instances on stage:
private var prg:Progress_mc = new Progress_mc;
private var ship:Ship_mc = new Ship_mc;
Or I have to add them as children of Calculator and add Calculator on stage?
The other problem is that I can't just use setter and getter as static functions in Calculator because "width" property is a read-only and cannot be used in static function (error:?)
What is the best way to access those properties and manipulate them?
Thank you so much good people!
I'm assuming Calculator instance is sort of globally accessible. In that case, I think you have
public function setProgressMcWidth(width:Number):void {...}
in Calculator class. This function needs to be called whenever progressMc's width is updated. Later when calculator needs to pass some width to shipMc, it can dispatch an event such as
package {
public class CalculatorEvent extends Event {
private var _width:Number = width;
public function CalculatorEvent(type:String, width:Number)
{
super(type);
_width = width;
}
override public function clone():Event {
var ret:CalculatorEvent = new CalculatorEvent(type, _width);
return ret;
}
public function getWidth():Number {return _width;}
}
}
and have dispatch code in Calculator like:
dispatch(new CalculatorEvent("shipWidthCalculated", calculatedShipWidth));
Ship mc, in turn, would listen to calculator's event like:
calculator.addEventListener("shipWidthCalculated", handleShipWidthCalculated);
private function handleShipWidthCalculated(event:CalculatorEvent):void {
trace('calculator calculated my width to be: ' + event.getWidth);
}
But if the calculator instance isn't in the display list, it won't receive any events.
I have been struggling with the following for a couple of hours now, how do you call a custom class from another class if you do not extend that class for example.
I have on my main Base class a timer event, Base.myTimer.addEventListener(TimerEvent.TIMER, processTime) - Base class
Then I remove the method later in the code Base.mytimer.removeEventListener(TimerEvent.TIMER, processTime. - Base class
I have a button (Btn class) that when its done processing I want to call that method again, but I can't get it to work because the method does not exist in the button class but on the Base class so flash obviously gives me the error processTime is not defined.
For example now I want to re-instantiate the event listener from within the button, so I have
Base.myTimer.addEventListener(TimerEvent.TIMER, processTime);
or this.parent.parent["myTimer"].addEventListener()
myTimer is a static Timer in Base class.
I can make a normal dispatchEvent if its not a custom method for example Base.myTimer.dispatchEvent(new TimerEvent(TimerEvent.TIMER)).
The examples I have seen so far have not resolved my issue. Any help would be appreciated.
Looks like the button class is part of the child tree of the Base class. In this case, you can just do a dispatchEvent from the button class when it is clicked
dispatchEvent(new Event("AddListenerAgain", true));
In the Base class, you must be having access to the button class already, hence you can say:
button.addEventListener("AddListenerAgain", addListener);
Then in the Base class
private function addListener(e:Event) : void {
myTimer.addEventListener(TimerEvent.TIMER, processTime);
}
In this example, I have dispatched and listened for raw strings. This is not a recommended practice. You must read on how to dispatch custom events to do it correctly.
You could pass a reference to an instance of Base class into your Button instance.
// Button class
package {
import Base;
// Other imports...
public class Button {
public function Button(base:Base):void {
// processTime and myTimer must be public.
// I put this line in the constructor for brevity, but if you stored base
// in an instance variable, you could put this anywhere in the button
// class.
Base.myTimer.addEventListener(TimerEvent.TIMER, base.processTime)
}
}
}
// Create button like this.
var button:Button = new Button(base);
// Or if button is created inside of Base
var button:Button = new Button(this);
Even better would be to create two methods in the Base class, for adding and removing the listeners, and make myTimer and processTime private:
public class Base {
public function addTimerListeners():void {
myTimer.addEventListener(TimerEvent.TIMER, processTime)
}
public function removeTimerListeners():void {
myTimer.removeEventListener(TimerEvent.TIMER, processTime)
}
}
Then you can call these two methods from outside of the class. This keeps the inner workings of your class more hidden. If you decided you wanted to change myTimer to a instance variable instead of static, you wouldn't have to make any changes to code outside of your Base class. This is called encapsulation and is a good practice.
Is there a way to pass an object reference to a component directly from the property/component parameter window? Using the [Inspectible] tag only allows me to input strings and not actual object references.
For example, I have a custom component called "knob" which should hold a reference to a door on the stage which it opens. I know this can be easily done in code with "knob.door = someDoor;" but since there are many objects in the scene I would prefer if I could do it visually trough the properties window.
I don't think you can do this. Your best bet is to pass in a string identifier (perhaps a whole dot-separated path if your clips are deeply nested), and then implement code inside your custom component to find that item by name.
I've got a custom component which lays itself out relative to horizontal and vertical predecessor components, so I do this:
protected var horizontalPredecessor:String = "";
[Inspectable(name = "HorizontalPredecessor", type = String, defaultValue="")]
public function set HorizontalPredecessor($value:String):void
{
horizontalPredecessor = $value;
drawNow();
}
override protected function draw():void
{
if (parent)
{
if (horizontalPredecessor != "")
{
var hp:DisplayObject = parent.getChildByName(horizontalPredecessor);
if (hp)
{
x = hp.y + hp.height + horizontalSpacing;
}
}
}
}
... which is made easy because all these components share the same parent.
Alternatively, if there's only one door, you could make it a singleton, and give it a static reference, like this:
public class Door
{
private static var _singleton:Door;
public static function get Singleton():Door
{
if(!_door) _door = new Door();
return _door;
}
}
Then your handle can just refer to Door.Singleton and you don't have to worry about passing anything in. Alternatively, you could have a static array of Doors in the Door class, and give your handle an index number to link it to a specific Door.
I have a movie clip with an external class attached.
here is the MC code (I've shorten it only for the relevant part...)
package {
//all the imports here...
public class mc_masterChapter extends MovieClip {
public function mc_masterChapter() {
trace (picFile,strChapTitle);
}
//Properties
public var picFile:String;
public var strChapTitle:String;
}
}
In the main class file I'm adding this object to stage using addChild:
var masterChapter:mc_masterChapter = new mc_masterChapter;
masterChapter.picFile = "pic_Chap1.jpg";
masterChapter.strChapTitle = "ABCD:
addChildAt(masterChapter,1);
now, the trace in the MC class code gives nulls to both parametes but if i put a trace inside the MC timeline (instead of the attached class code), it gives the right value!
how can I access the values from the MC class itself without getting nuls?
Thank you.
It works! Let me explain:
var masterChapter:mc_masterChapter = new mc_masterChapter; // Calls class constuctor
// so calls trace() too!
// You will get null null
masterChapter.picFile = "pic_Chap1.jpg"; // Assign the variables
masterChapter.strChapTitle = "ABCD"; // so they can be read
trace(masterChapter.picFile, masterChapter.strChapTitle); // Should trace pic_Chap1.jpg ABCD
If you add the following method to your class:
public function test():void {
trace(picFile, strChapTitle);
}
Then call masterChapter.test() it will successfully trace those two properties. So yes, the class can read its properties.
Make the var you use in your main class public static vars.
OK!
I solved the mystery.
I put two traces. one in the main MC class saying "hey, I'm inside the MC - the picFile="
and one in the put Function saying "I'm putting this file into picFile:"
well this is what I've got:
hey, I'm inside the MC - the picFile=null
I'm putting this file into picFile:image.jpg
got it!?! at the moment I asked him to give birth to an instance of the MC (even before putting it on stage - just defining the object (with this line:)
var masterChapter:mc_masterChapter = new mc_masterChapter;
it allready run the class, so of course that in this stage the parameters were not defined allready and were null.
the definition code came right after that line (in the main.as)
masterChapter.pic="pic_Chap1.jpg";
so what I did, was to move all the code from the main class of the MC object to a public function inside the same package called init(). Then I called this function manually from the parent main class.
By that I can decide when to call it (after I declare all the parameters of course).
That's it.
god is hiding in the small details : )
tnx for all the helpers.
Possibly a better solution would be to use a getter/setter pair, so you can know at the exact moment the properties are set:
protected var _picFile:String:
public function get picFile():String {
return _picFile;
}
public function set picFile(value:String):void {
if (value != _picFile) {
_picFile=value;
trace('picFile set to', _picFile);
}
}
I've got a AS3 program with a Main.as custom class.
In this class I load an instance of a 'menu' movieclip which has simpleButton instances inside... How do I access the Main class public functions by the menu movieclip buttons?
I.e. Menu button -> gotoPage(5); (which is a Main public function)
If I try to access the Main function with the above statement, it gives
"1180: Call to a possibly undefined method gotoPage.
Create a static method called GetMain() on the Main class that would return the instance of Main (Main should be a singleton).
package whatever
{
public class Main
{
private static var _instance:Main = null;
public static function getMain():Main
{
return _instance;
}
// Main constructor
function Main(..):void
{
_instance = this;
}
}
}
To refer to the instance of Main() from your Menu class, you could use:
Main.getMain().gotoPage(5);
You want to do this with events. If your menu movieclip is a child of Main.as as you say, name the instance buttons inside of the menu movieclip, and set up the listeners in Main.as:
1) Put the below code in the constructor: public function Main(){...
menu.button_a.addEventListener(MouseEvent.CLICK, onButtonClick);
menu.button_b.addEventListener(MouseEvent.CLICK, onButtonClick);
2) and then write the onButtonClick function in Main.as
private function onButtonClick(e:MouseEvent):void{
switch(e.currentTarget.name){
case "button_a":
//call the Main.as function you want here
break;
case "button_b":
//call a different Main.as function
break;
}
ruedaminute's answer on dispatching events from the buttons and having main process those events is by far the best way to handle this, but there are many ways to do this in as3 - but try to use the aforementioned technique. Some of the other techniques.
Make a function in Main such as public function GotoPage(iPageNum:int):void{}
from a button - try this._parent.GotoPage(1);
but this._parent might not be main, do a trace(this._parent), and keep trying
it might end up being
this._parent._parent._parent.GotoPage(1) depending on your display tree hierachry.
Again, this is REALLY bad OOP practices, but well, it will work.
Another tecnique - use a singleton for main- looks like u already are - add that same public method, then from the button click, you could do Main.getMain().GotoPage(1);
That is a bit better, in that you can change the display tree and not have to figure out where the heck Main is in the display tree, but singletons also are discouraged for a variety of reasons, but in this case I would say it makes since.
Good Luck!
~ JT