AS3 - Accessing subclass of subclass - actionscript-3

Im making this game, and I really want to access a "subclass of subclass". So I have something like this: MainClass > MonsterLibrary > SampleMonster.
I want to add this Sample Monster from MainClass, but I have to use it through MonsterLibrary, so I dont have to add monster by monster at my MainClass. Every monster respawn would be written in MonsterLibrary class.
I guess it should be something like this.
public class MainGame extends MovieClip {
public function MainGame() {
var mylibrary:MonsterLibrary = new MonsterLibrary();
mylibrary.MonsterLibrary();
Main class.
public class MonsterLibrary extends MovieClip {
#all var here.#
public function MonsterLibrary(){
var monster:SampleMonster = new SampleMonster(330,250);
addChild(monster);
}
MonsterLibrary class.
public class SampleMonster extends MonsterLibrary{
public function SampleMonster(startX:Number, startY:Number) {
//SETTING STARTING LOCATION
x = startX;
y = startY;
SampleMonster class.
I know Im doing it wrong, but I have no idea how to make this work. I keep getting this error ->
1061: Call to a possibly undefined method MonsterLibrary through a reference with static type MonsterLibrary.

You get that error because you're trying to directly call the constructor of MonsterLibrary:
public function MainGame()
{
var mylibrary:MonsterLibrary = new MonsterLibrary();
mylibrary.MonsterLibrary(); // <- wrong
...
}
The MonsterLibrary() function is the constructor of the MonsterLibrary class and it's called automatically when you use the new operator to create a new instance of the class.
If you want your MonsterLibrary class to act as a monster factory (a class that creates monster objects), create a new function that returns a monster:
...
public function CreateMonster ( sType:String ):SampleMonster
{
var oMonster:MovieClip = null; // you can use BaseMonster instead of MovieClip
if ( sType == "SampleMonster" )
{
oMonster = new SampleMonster ( ... );
... // initialize the monster here
}
...
return ( oMonster );
}
...
// get a monster and add it to the stage
var oMonster:MovieClip = oMonsterLibrary.CreateMonster ( "SampleMonster" );
oStage.addChild ( oMonster );
Note that MonsterLibrary doesn't need to extend MovieClip - it really doesn't need to extend any type (other than Object) since (I assume) it's not a visual object. Its purpose is to be a factory, not to be on the screen. oStage in the code above is your top-level display object - it could be the actual stage or a DisplayObject that acts as your stage.
The SampleMonster type shouldn't extend MonsterLibrary - a particular monster is not a library. Your monsters should derive either directly from MovieClip or (better) from a common base monster class; something like:
public class BaseMonster extends MovieClip
{
...
}
Then your SampleMonster can derive from this base monster:
public class SampleMonster extends BaseMonster
{
...
}

I'm confused at what you are trying to accomplish.
Are you looking to have the MonsterLibrary return a monster every time you call a method ?
ie you could have a method in MonsterLibrary class like this :
public function getMonster():SampleMonster
{
var monster:SampleMonster = new SampleMonster(330,250);
return monster;
}
Then your MainGame might look like this :
public class MainGame extends MovieClip {
public function MainGame() {
var mylibrary:MonsterLibrary = new MonsterLibrary();
var newMonster:SampleMonster = mylibrary.getMonster();
addChild(newMonster);
Going further you could have a parameter for the getMonster method to specify a monster type.
for example :
public function getMonster(monsterType:int):Monster
{
// create the appropriate monster and return it
}
Keep in mind that in your code adding the monster to the Display List of the MonsterLibrary, means it will never be seen UNLESS you add MonsterLibrary to the Display List of MainGame
Also you have SampleMonster extending MonsterLibrary, which is not going to work.
SampleMonster should probably extend MovieClip or Sprite or if you intend on having multiple monsters you'd want to have a base Monster Class that any specific monster might extend.

Related

How to access, change, and then return the changed value from another class as3

I am trying to make a game similar to pong, and I am putting the code into each class of my movieclips instead of into the timeline. I have a variable ballspeedx in my class ball. What ballspeedx does is change the speed of which the object moves horizontally. I am trying to call that variable in that class from my main class, named main. Not only do I want to be able to call it, I want to be able to change it and then return the changed value. Can someone explain how to do that?
Make your variable "ballspeedx" a public variable in "ball" class. When you create its object in main class, you can access its public variables. You can also change this. You can add getter and setter functions in "ball" class to change/access the variable value if its private.
Ball.as:
public var ballspeedx:int = 10;
Main.as:
var ball:Ball = new Ball();
trace(ball.ballspeedx);
ball.ballspeedx = 20;
trace(ball.ballspeedx);
You can make ballspeedx a public member of your ball class.
public var ballspeedx:Number;
OR, you can create a getter and setter for the private property:
private var _ballspeedx:Number;
public function get ballspeedx():Number { return _ballspeedx:Number; }
public function set ballspeedx($value:Number):void { _ballspeedx = $value; }

Get instance objects which are not on first frame

I'm using actionscript 3.0 and Flash Professional CS5.5
I ran into a problem with instance objects which are not on the first frame.
My first frame is a menu and my second frame contains a TLF text field.
I have given the text field an instance name, let's say "username_txt".
Now if I turn off the "Automatically Declare Stage Instances" and do this in my main class
public class MainClass extends MovieClip {
public var username_txt:TLFTextField;
public function MainClass() {
username_txt.text = "anything";
}
}
I will receive a run time error stating that I try to access the property of a null object. (I have import all the necessary classes so that is not the problem)
This does not happen when I put the text right in the first frame though.
Any help?
Thanks in advance
As the text field has not yet been instantiated since the frame has not yet been reached, I'm unsure there is an elegant way to perform this task.
Perhaps a better model would be to decouple your data model from your views.
Create a singleton class to store data:
package
{
public class ApplicationModel
{
/** Singleton instance. */
private static var instance:ApplicationModel = new ApplicationModel();
/** Return singleton instance. */
public static function getInstance():ApplicationModel
{
return instance;
}
/** Data Model */
public var username:String;
/** Constructor as singleton enforcer */
public function ApplicationModel()
{
if (instance)
throw new Error("ApplicationModel is a singleton and can only be accessed through ApplicationModel.getInstance()");
}
}
}
Then from within anywhere such as keyframes or classes, you can get the instance of the object, implemented either as:
ApplicationModel.getInstance().username = "test";
Or a better practice would be:
var applicationModel:ApplicationModel = ApplicationModel.getInstance();
applicationModel.username = "test";
As per your example:
public class MainClass extends MovieClip {
public var username_txt:TLFTextField;
public function MainClass() {
ApplicationModel.getInstance().username = "anything";
}
}
Then, on the frame you need to update your TLFTextField (frame script of frame 2), you set the text based upon the model:
username_txt.text = ApplicationModel.getInstance().username
Your view will always update when needed.

ActionScript3: Inheriting constructor arguments from parents

I'm making a game in action script 3. In it, I have an actor class from which player and enemy classes will be derived. I'm doing this so that unless I need to provide specific AI or fancy behavior (such as for bosses), I can just make a new clip in the library for each enemy without making an actionscript file.
However, I've run into a problem.
Whenever I try to pass arguments to the construction of an enemy (make it spawn with more health), I get error 1136 (Incorrect number of arguments.)
This is because the constructor created automatically at runtime doesn't have the same arguments as it's parent class. Is there any way to get around this without making a class file where I copy and paste the parent constructor function for each of my hundreds of enemies?
Edit
actually rereading your question I think you may be looking for super();
Example
public class Actor{
private var myHelth:uint;
public function Actor(helth:uint = 100){
myHelth = helth; //this will be set to 100 if nothing it passed in or the value passed
}
}
Class that extends Actor:
public class Boss extends Actor{
public function Boss(){
super(200); //passes 200 to Actor;
}
}
If you're trying to pass data into a classes constructor you need to make sure it's accepting arguments.
public class Actor{
private var myHelth:uint;
public function Actor(helth:uint = 100){
myHelth = helth; //this will be set to 100 if nothing it passed in or the value passed
}
}
Then to use
var a:Actor = new Actor(200); //setting health to 200
var b:Actor = new Actor(); //using the default of 100
Make sure your symbols in Flash Pro have appropriate AS linkage, then use pass constructor arguments in super statements:
Actor - base class
package
{
public class Actor
{
public function Actor(name:String, role:String)
{
}
}
}
Player - inherits from Actor defining its own constructor parameters:
package
{
public final class Player extends Actor
{
public function Player(... params:Array)
{
// pass desired inherited constructor parameters
super("name", "role");
}
}
}
Enemy - inherits from Actor defining its own constructor parameters:
package
{
public final class Enemy extends Actor
{
public function Enemy(... params:Array)
{
// pass desired inherited constructor parameters
super("name", "role");
}
}
}

AS3.0: Acces properties of created instance from 2nd class

I'm building a small game.
On my document class i create a instances of the class Character and Level with the following code:
//add the Level
level = new TileGrid();
level.y = 100;
level.x = 400;
addChild(player);
//add our player
player = new Character();
player.y = 150;
player.x = 400;
addChild(player);
I also create a controller class which handles the user input. (for example checks if the player is able to move to the right.)
I also create eventlisteners for keyboardevents and stuff.
When a key is pressed i want to check if the movement is possible by calling the checkTile(tileNumber) function of the TileGrid class from within the controller class.
The controller class looks like this:
package {
import flash.events.KeyboardEvent;
import flash.events.Event;
public class Controller{
//Constructor code
public function Controller(){}
//Keyboard pressed -> move character
public function keyPressed(evt:KeyboardEvent):void
{
trace(level.checkTile(30));
}
}
And the TileGrid class looks something like this:
package {
import flash.events.KeyboardEvent;
import flash.events.Event;
public class TileGrid{
//Constructor code
public function TileGrid(){
//Creating all the tiles and adding them to the stage.
}
//Check if a certain tile is walkable
public function checkTile(tileNumberType){
if(tileNumberType > 15){
return false;
}else{
return true;
}
}
}
But when i test this i get the following error:
Line 81 1120: Access of undefined property level.
When i try: trace(Object(parent).level.checkTile(30)); i get: 1120: Access of undefined property parent.
How can i access methods from one class with an instance from a second class ?
I think you must do something like this:
...
// somewhere in your document class (or somewhere else)
var player:Character = new Character();
var level:TileGrid = new TileGrid();
var controller:Controller = new Controller(player, level);
...
// in your Controller class
private var level:TileGrid;
private var player:Character;
public Controller(player:Character, level:TileGrid) {
this.player = player;
this.level = level;
}
public function keyPressed(event:KeyboardEvent):void {
level.checkTile(30); // in this line "level" means "this.level"
}
In that case you must say which player and which level the controller must control. The controller is a class that has no knowledge of any other class. The variables are not global (in your example, and they shouldn't be) so you can't acces them from everywhere.
Classes in AS can't access their context. This means that if I have:
function foo():void
{
var k:MyCustomClass = new MyCustomClass();
var j:MyOtherClass = new MyOtherClass();
}
the two instances j and k don't know about each other.
In this particular case, however, because you're clearly dealing with a parent structure, it is possible to get the parent's properties. This is possible because you have a path to the variable in a public scope.
Try this instead:
trace(Object(parent).level.checkTile(30));
Also note the Object(parent). A DisplayObject's parent is a DisplayObjectContainer, which does not have a level property. By wrapping parent in Object, however, you're telling Flash, "It's OK, you should look for this property at runtime not when compiling."

Controlling objects of another class that are already on the stage

I'm quite ashemed to ask this question here because I'm sure that I'm missing something very basic. I'm not even sure what should be the correct title for this question.
Let's say that I've a button object (instance of Flip) and a coin object (instance of Coin) on the stage. The coin object has two frames: one showing Heads and one for Tails.
MyCoin class is as following:
package
{
import flash.display.MovieClip;
public class Coin extends MovieClip
{
protected var _coinFace:uint;
public function Coin()
{
stop();
}
public function get coinFace():uint {
return _coinFace;
}
public function set coinFace(value:uint):void {
_coinFace = value;
}
public function show():void {
gotoAndStop(_coinFace);
}
}
}
Objective: When user clicks the button, the coin should flip and show a random coinFace. I've added an eventListener to the Flip class as follows:
public function Flip()
{
this.addEventListener(MouseEvent.CLICK, onMouseClick);
}
Problem: How do I reach the coin object on the screen via onMouseClick function? Let's say that the object on the stage has instance name of myCoin. I suppose that had I not done this with an external class and simply used actions from the frame I could just use the instance name as a variable. I couldn't figure to do the same it in an external class. Do I first create the object which is already on the stage?
Where you create the instance of each, the flip object needs to be passed an instance of the coin object.
var myCoin:Coin = new Coin();
var myFlip:Flip = new Flip(myCoin);
Then inside the Flip class:
private var _coin:Coin;
public function Flip(coin:Coin) {
_coin = coin;
this.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function onMouseClick(e:MouseEvent):void {
_coin.gotoAndStop(2); // Or what ever needs to be done to the coin on click
}
Alternatively, depending on the complexity of the overall structure, you can a build a control class that acts as a link between the two.