AS3 - Get reference of instance who called a function - actionscript-3

I have two classes, "player" and "Stickman", "player" extends "Stickman".
The class "Stickman" contains functions that all characters will have in the game such as moving and handling animations (all use the same animations) while the "player" class contains player-exclusive actions.
When I call an action from a player instance that is inherited from the "Stickman" base class, how do I correctly point (from the stickman base class) to that player instance that called the function?
For example, to handle running animations
Trigger code in player.as:
moveType("running");
moveType function in Stickman.as:
public function moveType(type:String):void{
this.gotoAndPlay("running");
trace("testing");
}
To start playing frame with frame label "running" inside the player object (which is an extend of Stickman). I know this doesn't work, so I would like to replace this with something that would point to the caller of the function (i.e. the player object).The trace statement still runs so there (should) be no problem with the linkage. Is there a way to do this without passing the childId of the player object?

It's all about so called inheritance. Player IS actually a Stickman. So when you call moveType you are calling it ON Player object. If you don't have such function inside it, it looks up in the inheritance chain, and finds it inside Stickman.
Inheritance is one-directional. Which means that Player knows all methods of Stickman, but the opposite is not true - Stickman works only by itself and does not know who extended it and who not.
That said - you must use the Player class as a starting point and decide what to do from there on.
Long story short - you need to override the function from Stickman into Player and then decide what to do and what not. Example:
Stickman:
public function move(type:String):void {
this.gotoAndPlay(type); // regular workflow for reach Stickman
}
Player:
override public function move(type:String):void {
if (type == 'player_specific') {
this.gotoAndPlay('frameAvailableOnlyForPlayerClip');
// maybe something else, player specific, like play sound or smth else
} else {
super.move(type); // calls whatever is inside Stickman::move
}
}
Remember - this is always the very same object that you are calling the function for. But you can decide if you want something specific (player case) or you want the very usual flow. super.move will call what's in the parent class.
Inheritance is very important and I cheer you for deciding to use it! With a little more practice you will master it!

Related

What happens to a Movieclip when casted as a Sprite?

(Note that there is nothing really 'wrong' here with my code (in the sense that it works), but more wondering on how it is working and what is happening under the hood)
Currently I have two libraries, each with one object. One is set with the class "Apple" and the other is "Pear", They are located in separate external swfs.
Apple's base class is MovieClip as content-wise it is a movieclip: has frames + animation
And here is the code I used to create and display an Apple movieclip object:
function getClip(inputName, spriteLibrary:Loader):MovieClip {
var aClass:Class = spriteLibrary.contentLoaderInfo.applicationDomain.getDefinition(inputName) as Class;
return (MovieClip) (new aClass());
}
this.addChild(getClip("Apple", referenceToTheLoadedSwfThatHasAppleInIt));
The above works just fine and Apple appears on the stage and plays.
However, Pear's base class is a Sprite (has no animation, frames, etc). So the above fails, since the method is supposed to return a MovieClip.
this.addChild(getClip("Pear", referenceToTheLoadedSwfThatHasPearInIt));
I thought for a moment I would have to have two versions of the above method, one for Sprite and one for MovieClip. But just to see, I changed it to Sprite and tried to create Apple:
function getClip(inputName, spriteLibrary:Loader):Sprite {
var aClass:Class = spriteLibrary.contentLoaderInfo.applicationDomain.getDefinition(inputName) as Class;
return (Sprite) (new aClass());
}
this.addChild(getClip("Apple"), referenceToTheLoadedSwfThatHasAppleInIt);
this.addChild(getClip("Pear"), referenceToTheLoadedSwfThatHasPearInIt);
Now both will work, but interestingly, I found that even though the method returns a Sprite, Apple still seems to work fine and plays it's animation on the stage. I can cast this to a MovieClip and access all the MovieClip related properties and so forth.
My question is then, when Apple "existed" as a Sprite, what happened to all of it MovieClip related "stuff" and is this actually a normal thing to do when having to work with MovieClips and Sprites (by pretending you only have Sprites and cast to MovieClip only when you need it?)
A Sprite class provides more basic functionality than a MovieClip, but everything that's a MovieClip can be manipulated by using the functionality of a Sprite class. In fact, your method can return as low a class as DisplayObject if your only intention is to do an addChild(). The typecast will not strip the typecasted object of any functionality, it will instead restrict the available calls for its properties. Say, a DisplayObject has x and y properties, a Sprite can be used to add objects to itself (the addChild() method) which the DisplayObject does not have, and a MovieClip has internal animation and a say gotoAndStop() method which a Sprite does not have. So, if you typecast an Apple to a Sprite, you cannot make a call to the reference's gotoAndStop(), because you've told the program that the reference is just Sprite. If you typecast the Apple or the Pear object to DisplayObject, you cannot call its addChild() method to say add a health bar (weird thing for apples to have health bars, but why not?), because the reference does not know that the underlying object supports this functionality. But actually nothing will happen to either object, no matter how you typecast them, you will just restrict yourself from applying more advanced actions via received reference.
Actually it's good practice to limit the functionality for yourself via typecasts, because you are then protected from making "crutches" over working code which can probably spoil its purpose. Say, your code will not be surprised in case you would decide to turn Apple into an advanced Sprite class (say, public class Apple extends Sprite {...}) with tailored properties, embedded event listeners, color-changing maybe, but if you typecast the newly created Apple to Sprite or DisplayObject, you are abstracting from any extra abilities of the instance and only use its basic interface (properties and methods of a typecasted class) to perform the actions the Sprite or DisplayObject are intended for. If you have some overridden properties in the advanced Apple, they will work as you have intended while making the Apple class, even if addressed from the superclass description - this is actually what override is for.
In short, don't worry about losing functionality, but try typecasting to least possible class with used functionality.
About "what happens under the hood": Each class has its own table of properties and methods, if a class is extending another class, that class's table is identical to the superclass's up to its end, and the extra space is occupied with information on properties and methods implemented by the class. If there is an override, the overridden method's info replaces the info of the corresponding method in the table for the class, not for the superclass though. Each instance has a memory block allocated to it, there is a reference to the class's properties and methods table, which is then used to execute correct code, if a method is called via instance reference. So, when you call a method, or a property with a getter or setter assigned to it, out of an instance, the following happens:
The correct set of parameters, including "this" pointer to that instance, is pushed into the stack. The correctness of the order and the type of parameters is ensured by Flash compiler.
Then, the class that's actually the proper class of that instance is referenced via prototype property of the instance. Every class in AS3 has this property. The instance is accessed via "this" pointer previously pushed into the stack. (Technically it's stored in more than just stack, so the reference is just the same that's put in the stack)
Then, the correct offset (determined by the compiler) is returned from that table, that is the address of the called method of the class. Overridden or not, no matter here, because an improper override is detected at the compile time, and will not happen here.
Then, code execution is transferred to the returned address. The method's code then parses the parameters in stack, does some more data protection and proceeds with its implementation.
The most important thing to understand here is that nothing happens to the object itself, but the way the compiler treats the object will differ.
For example, the compiler will treat the object returned by this function as a Sprite, even if we actually return a MovieClip:
function makeSprite():Sprite
{
return new MovieClip();
}
var test:MovieClip = makeSprite();
// 1118: Implicit coercion of a value with static type flash.display:Sprite
// to a possibly unrelated type flash.display:MovieClip.
So what we need to do here (as you understand currently) is tell the compiler that the result is actually a MovieClip via typecasting:
var test:MovieClip = makeSprite() as MovieClip;
Another thing to take notice of is that if you were to trace() the result, you would get [object MovieClip] rather than [object Sprite]:
trace( makeSprite() ); // [object MovieClip]
And using is to check if it's a MovieClip will return true:
trace( makeSprite() is MovieClip ); // true
Even if you used a more primitive type for test, your object would truly be a MovieClip:
var test:Object = makeSprite();
trace(test); // [object MovieClip]
Casting a MovieClip to a Sprite doesn't strip it of its MovieClip implementation; it simply tells the calling code (in this case, this.addChild()) that "this object is a Sprite; please treat it as such." The calling code doesn't know — or care — that it's really a MovieClip, because as long as it's a DisplayObject (which a Sprite, and in turn a MovieClip, derives from), the addChild() method will happily accept it.
Since a MovieClip is a Sprite anyway, it doesn't make any difference to the calling code. As for the Apple object itself, though, it's still a MovieClip at heart, and so will continue to function on its own like one.
As an analogy, think of going to the grocery store, buying some goods, and paying at the counter. You're a person with many different roles in various aspects of life, but as far as the cashier is concerned, you're just a customer making a purchase. That doesn't make you any less of a person, but the cashier doesn't have to be interested in who you are or what you do, beyond just a customer making a purchase.
TL;DR:
Your MovieClip will stay a MovieClip, but the reference that is down casted to a Sprite will be able to access only methods and variables that are available to Sprite.

Pros and Cons of creating a separate class for the GUI (in actionscript)

This is related to a similar question I just asked; however, this one is specifically tailored to my individual project, rather than object-oriented programming in general.
I am working on a version of hangman with some interesting programming twists. I don't need to go into detail of what they are as the logic for the game is already finished. I can run an entire game by hard-coding variables for the user input (such as guess selection). I am now in the process of replacing all those bits that require user interaction with the trappings of an actual game like buttons, images, sounds, etc.
I am trying to figure out whether it is better to have all of this stuff be part of my main class, or whether I should create another class to handle it all. For example, I want my players to be able to click on an on-screen keyboard to make their guess, with each button firing a separate event listener call to the makeGuess function. Would it be better to create the buttons as direct children of my main game class, or should I create a subclass (called Keyboard, for example) that creates the keyboard section of the board with the appropriate events, then add the keyboard class as a child to the main rather than all the pieces? What are the pros and cons of each of these choices?
For the record, I'm programming using FlashDevelop, so nothing like a timeline for me.
I say you'd better create at least the Keyboard class that will parse the events fired by tapping/clicking keys inside, and give it a callback reference to your Main class, or GameLogic class, so that it can do theMain.guess(letter); and then the Main class logic will come to life and process the callback. Since this structure is not exactly related to game logic, and technically it can then be reused by implementing an interface for the callback, so that you can use this keyboard elsewhere where you want to have your player to type letters using mouse, it's better be separated from main logic.
public class Keyboard extends Sprite {
public var callback:AcceptingKeys; // an interface
... // class implementation, with all the listeners, children and stuff
// and you call in there: callback.acceptKey(key);
}
public interface AcceptingKeys {
public function acceptKey(key:String):void; // or whatever type you need
}
And you do with your Main class:
public class Main extends Sprite
implements AcceptingKeys {
...
var keyboard:Keyboard;
private function init(e:Event=null):void {
... // other code. It's FD, then this function exists
keyboard=new Keyboard();
keyboard.callback=this;
// past this point your instances can talk
}
public function acceptKey(key:String):void {
// match interface description
... // do game logic for parsing a key
}
}

AS3 Accessing stage objects from a class

I'm writing a class Player, and I'm developing collisions but flash gives me an error to this line:
function checkCollision(event:Event)
{
if (this.hitTestObject(stage.wall)) // THIS LINE!!!!!!!!
{
trace("HIT");
}
else
{
trace("MISS");
}
}
}
The error is:
Access of possibly undefined property wall through a reference with
static type flash.display:Stage.
How can I access to wall ? wall is a symbol on the stage... Should I develop it in another way? please help
MovieClip is a dynamic object, whereas Sprite or Stage are not. With these classes, unless the property is explicitly defined, the compiler will complain about the absence of the property when you try to reference it.
If you're programming with Flash IDE, "Automatically Declare stage Instances" will create properties on your stage that make dot.notation pathing possible.
If you're creating objects dynamically, you'll have to either create the properties yourself (which is impossible with static classes like Sprite), or reference them by DisplayList fetching methods getChildAt() or getChildByName().
In the case of a class, unless you extend a class that is already a DisplayObject, you won't inherently have access to stage or root. You'd have to pass a reference to the MainTimeline or Stage manually (probably during instantiation). Even if you did extend a DisplayObject, you'd have to first parent the object to the stage; until then, the properties are null.
For the sake of argument, let's assume Player class is extending Sprite, and you have parented it to the stage. Your code would correctly be written as follows:
function checkCollision(e:Event) {
if (this.hitTestObject(this.root.getChildByName("wall"))) {
trace("HIT");
} else {
trace("MISS");
}
}
Notice that the call to "wall" is not on the Stage. That's because there is only one child of stage, and that's MainTimeline (a.k.a. root).
BTW, you had an extra close brace in you example.
Yep if you have automatically declare stage instances unchecked you will get that error. It is a good practice to declare everything in AS3 and not rely on the GUI to do it. Even if it is
Public var boringBackground:Sprite;
It will pay off in the end performance and coding wise.

How to access a displayobject on stage in a class that is not a document class

How to access a display object on the stage in a class which is not a document class?
I am looking for a solution that doesn't involve passing the stage as a parameter to the class.
One solution i always come across is using "TopLevel.as". Is it a good method because as far as I have heard using global variables is not recommended because it might cause some problems while working on big projects.
All display objects have a addedToStage event dispatched when they are added to the display list, which gives you a reference to the stage. So you could do something like this:
// In the constructor
addEventListener(Event.ADDED_TO_STAGE, onAdded);
// A class level function
private function onAdded(e:Event):void {
// get reference from stage, eg:
// stage.getChildByName("nameHere");
}
There is no need to use the "Top Level" class, which is relying on global (ie: static) properties.

Interaction between classes

In my main Actionscript file i have a instance of a body class that moves the person body arms legs etc. and a gun class which has methods and properties to do with the person gun.
Right now i have a function in the Main class which is called move gun and looks like this and is called everyframe to move the gun to the bodys arm. I was hoping to move this function to the guns class so i could call it like gun.moveGun(); but the body dosent exist inside the gun variable. so i wonder if i could call the body.getArm(); function from inside the gun. I know i could call the function and pass the bodys arm location to it from the main file. But don't know if this is the best way to do it.
private function moveGun():void
{
gun.x = body.getArm('left').x;
gun.y = body.getArm('left').y;
}
It seems like keeping the gun related functions inside the gun class is the best way to organise everything but i dont know how to do this.
Also depending what button someone clicks at the start the person will either have a basketBall or gun in there hand. Ive added the swf online at Here so you can see how it works. i just wanna change how its organised because the main file is very full and though i should learn how to organise things better. There are lots of other part of the program that would be organised better if i knew how to get the object to interact or what is the best way to do it. Starting to think passing the x,y coordinates to the moveGun function inside the gun Class is the best way. If so just tell me please and ill do that.
From the code you posted, I think you need to move the gun with every frame to stick to the player's arm.
The answer you're looking for is Composition, since every person gets one and only one gun, I think you better put a reference (variable) in the person class for its gun.
and here is your player (person) class:
class Person
{
private var m_gun:Gun;
public function Person()
{
this.m_gun = new Gun();
}
// a function which is called each frame
private function updateFrame()
{
// Here you can provide your own logic in Gun class
this.m_gun.doSomething();
}
}
generally, you want to communicate between classes using the built-in event listener and dispatcher system. if 'something' happens - regardless of 'where' that occurs - dispatch an event. whenever something should react, it should have a listener.
for example, from the main class you mentioned, you might want to dispatch an event:
private function moveGun():void
{
var e:Event = new Event('moveGun', true);
dispatchEvent(e);
}
then the appropriate instance (the body? - not sure how you have things set up) listen for that:
body.addEventListener('moveGun', moveGunHandler, false, 0, true);
function moveGunHandler(event:Event):void{
gun.x = body.getArm('left').x;
gun.y = body.getArm('left').y;
}
the above is obviously psuedo-code since i have no way of knowing how your display list is set up. also, i used simple string literal event types - best practice would probably be to use custom event classes with event types defined as static constants.