ActionScript - Passing & Instantiating Class Reference Containing Required Parameters? - actionscript-3

I'm unsuccessfully attempting to instantiate a reference of a class that is passed as a parameter to another class.
in this example there are 3 classes: MainClass, Canvas, MyCircle
from the MainClass i am creating an instance of Canvas, which is passed a class reference of MyCircle as i want to create instances of MyCircle from within Canvas. however, the MyCircle constructor contains required parameters that are created from within Canvas.
how can i pass and instantiate a class reference with required parameters?
MyCircle:
package
{
//Imports
import flash.display.Shape;
//Class
public class MyCircle extends Shape
{
//Constructor
public function MyCircle(color:uint, radius:uint)
{
graphics.beginFill(color, 1.0);
graphics.drawCircle(0, 0, radius);
graphics.endFill();
}
}
}
Canvas:
package
{
//Imports
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
//Class
public class Canvas extends Sprite
{
//Constructor
public function Canvas(circleClassReference:String, amount:uint)
{
var CircleReference:Class = getDefinitionByName(circleClassReference) as Class;
for (var i:uint = 0; i < amount; i++)
{
var randomColor:uint = Math.random() * 0xFFFFFF;
var randomRadius:uint = Math.random() * 100 + 50;
var circleInstance:DisplayObject = new CircleReference(randomColor, randomRadius);
circleInstance.y = i * randomRadius;
addChild(circleInstance);
}
}
}
}
MainClass:
package
{
//Imports
import flash.display.Sprite;
//Class
public class MainClass extends Sprite
{
//Constructor
public function MainClass()
{
var myCanvas:Canvas = new Canvas("MyCircle", 10);
addChild(myCanvas)
}
}
}
[EDIT]
it seems that passing the actual Class instead of the name of the class avoids the need for the dirty fix that is mentioned below.
MainClass Constructor
public function MainClass()
{
var myCanvas:Canvas = new Canvas(MyCircle, 10);
addChild(myCanvas)
}
Canvas Constructor
public function Canvas(circleClassReference:Class, amount:uint)
{
var CircleReference:Class = circleClassReference;
for (var i:uint = 0; i < amount; i++)
{
var randomColor:uint = Math.random() * 0xFFFFFF;
var randomRadius:uint = Math.random() * 100 + 50;
var circleInstance:DisplayObject = new CircleReference(randomColor, randomRadius);
circleInstance.y = i * randomRadius;
addChild(circleInstance);
}
}

Importing (or being in the same package) isn't enough to make the compiler include a class definition in the Application Domain. You will actually have to use the class you want somewhere, or embed the definition in an SWF that you load in. This should fix your error though:
package
{
//Imports
import flash.display.Sprite;
//Class
public class MainClass extends Sprite
{
//Constructor
public function MainClass()
{
//unused variable definition for class embedding purposes
var tempCircle:MyCircle;
var myCanvas:Canvas = new Canvas("MyCircle", 10);
addChild(myCanvas)
}
}
}
While this will prevent MyCircle from being undefined later on, I've always thought of it as a bit of a dirty fix (despite having it in some fairly major projects). I'd love to know a better solution, other than embedding the definition in a separate SWF.

Are you aware that you can treat classes as Objects?
Depending on what you're trying to do you could do something like this:
My Circle:
package
{
//Imports
import flash.display.Shape;
//Class
public class MyCircle extends Shape
{
//Constructor
public function MyCircle(color:uint, radius:uint);
{
graphics.beginFill(color, 1.0);
graphics.drawCircle(0, 0, radius);
graphics.endFill();
}
}
}
Canvas:
package
{
//Imports
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
//Class
public class Canvas extends Sprite
{
//Constructor
public function Canvas(classToCreate:Class, amount:uint)
{
for (var i:uint = 0; i < amount; i++)
{
var randomColor:uint = Math.random() * 0xFFFFFF;
var randomRadius:uint = Math.random() * 100 + 50;
var circleInstance:DisplayObject = new classToCreate(randomColor, randomRadius);
circleInstance.y = i * randomRadius;
addChild(circleInstance);
}
}
}
}
MainClass:
package
{
//Imports
import flash.display.Sprite;
//Class
public class MainClass extends Sprite
{
//Constructor
public function MainClass()
{
var myCanvas:Canvas = new Canvas(MyCircle, 10);
addChild(myCanvas)
}
}
}

Related

Make a child call a function from its parent AS3

So I've been reading a lot about inheritance and circular dependency and I see no way around this. Still a little new to multiple classes. My document class creates Field. My Field class creates player and pushes bitmapData from the Tile MovieClip. I want player to be able to draw that bitmapData to the field. Engine.as(document class):
package {
import flash.display.MovieClip;
public class Engine extends MovieClip {
private var field:Field;
public static var _tilesData:Array = [];
public function Engine()
{
field = new Field();
field.x = 0;
field.y = 0;
addChild(field);
}
}
Field.as:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.display.BitmapData;
import flash.display.Bitmap;
public class Field extends MovieClip{
private var player:Player;
private var sampleTile:Tile = new Tile();
public function Field()
{
player = new Player();
player.x = 0;
player.y = 0;
addChild(player);
GetSampleTiles();
}
public function GetSampleTiles()
{
for (var i:int = 0;i < 3; i++)
{
sampleTile.gotoAndStop(i);
var graphicData:BitmapData = new BitmapData(32,32);
graphicData.draw(sampleTile);
Engine._tilesData.push(graphicData);
}
}
public function DrawATile(tileToDraw:BitmapData)
{
var newTile:Bitmap = new Bitmap(tileToDraw);
newTile.x = player.x;
newTile.y = player.y;
addChild(newTile);
}
}
}
Player.as:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.display.BitmapData;
import flash.display.Bitmap;
public class Player extends MovieClip
{
public var _inp:Input = new Input();
public function Player()
{
addChild(_inp);
addEventListener(Event.ENTER_FRAME, HandleKeys);
}
public function HandleKeys(e:Event)
{
if(_inp.keyUp)
{
y -= 32;
}
if(_inp.keyDown)
{
y += 32;
}
if(_inp.keyLeft)
{
x -= 32;
}
if(_inp.keyRight)
{
x += 32;
}
if(_inp.keySpace)
{
parent.DrawATile(Engine._tilesData[0]);
}
}
}
}
Is there a better way of doing this than I am seeing? When I put DrawATile function in Player.as it works... but the tiles move around with the player.
I placed the DrawATile function in Player.as and in it I add the newTile to parent like this - parent.addChild(newTile). that way it adds it to whatever its parent is and not to itself.

AS3 - Why am I getting this 1009 error? (Cannot access a property or method of a null object)

I can't get this program to work. I Always get this error: Error #1009: Cannot access a property or method of a null object reference.
I don't understand why and would appreciate some help.
Here's my code:
Main class:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
private var enginge:Engine = new Engine(stage);
private var enemy:Enemy = new Enemy(100, 100);
public function Main():void
{
addChild(enemy);
}
}
}
Engine class:
package
{
import flash.display.Sprite;
import flash.display.Stage;
public class Engine
{
public static var stage:Stage;
public static var gravity:int = 1;
public function Engine(stage:Stage)
{
Engine.stage = stage;
}
public static function gravitate(object:Sprite):void
{
object.y += Engine.gravity;
if (object.y < Engine.stage.stageHeight - object.height / 2)
{
Engine.gravity += 1;
}
else
{
Engine.gravity = 0;
object.y = Engine.stage.stageHeight - object.height / 2;
}
}
}
}
Enemy class:
package
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
public class Enemy extends Sprite
{
private var gravity:int = 1;
public function Enemy(x:int, y:int)
{
this.graphics.beginFill(1, 1);
this.graphics.drawRect(this.x - 25, this.y - 40, 50, 80);
this.graphics.endFill();
this.x = x;
this.y = y;
this.addEventListener(Event.ENTER_FRAME, function(e:Event):void
{
Engine.gravitate(this);
});
}
}
}
In order to fix the problem you need to get rid of the anonymous function in the Enemy class.
You will have:
public function Enemy(x:int, y:int)
{
this.graphics.beginFill(1, 1);
this.graphics.drawRect(this.x - 25, this.y - 40, 50, 80);
this.graphics.endFill();
this.x = x;
this.y = y;
this.addEventListener(Event.ENTER_FRAME,handler);
}
private function handler(event:Event):void
{
Engine.gravitate(Sprite(this));
}
and the code will be working. This is due to context difference of word this inside anonymous function.
Usage of anonymous function is terrible practice and you should refrain from doing it.

Not Displaying Nape Body

I had these two in the same Main class. Now there are Main.as and MainChar.as
When compiling doesn't show any errors but it isn't displaying the object either :c
It is the first time I am splitting code into different classes. I just figured what should be in the hero creation class and what should stay in Main.
package
{
import flash.display.Sprite;
import flash.events.Event;
import nape.geom.Vec2;
import nape.phys.Body;
import nape.phys.BodyList;
import nape.space.Space;
import MainChar;
public class Main extends Sprite
{
public var gravity:Number = 600;
public var space:Space = new Space(new Vec2(0, gravity));
public var hero:MainChar = new MainChar();
public function Main():void
{
hero.createMainCharacter(stage.stageWidth/2, stage.stageHeight/2, 50, 50);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void
{
space.step(1 / stage.frameRate, 10, 10);
var bodies:BodyList = space.bodies;
for (var i:int = 0; i < bodies.length; i++)
{
var body:Body=bodies.at(i);
if (body.userData.sprite != null)
{
body.userData.sprite.x = body.position.x;
body.userData.sprite.y = body.position.y;
body.userData.sprite.rotation=(body.rotation*180/Math.PI)%360;
}
}
}
}
}
Hero creator class:
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import nape.geom.Vec2;
import nape.phys.Body;
import nape.phys.BodyType;
import nape.shape.Polygon;
import nape.space.Space;
public class MainChar extends Sprite
{
public var space:Space = new Space(new Vec2(0, 600));
public function MainChar():void
{
}
public function createMainCharacter(x:Number, y:Number, width:Number, height:Number):void
{
var mainChar:Body = new Body(BodyType.DYNAMIC);
var mainCharShape:Polygon = new Polygon(Polygon.box(width, height));
mainChar.shapes.add(mainCharShape);
mainChar.position.setxy(x, y);
mainChar.space = space;
var mainCharSprite:Sprite = new Sprite();
mainCharSprite.graphics.beginFill(0x000000);
mainCharSprite.graphics.drawRect( -width/2, -height/2, width, height);
mainCharSprite.graphics.endFill;
addChild(mainCharSprite);
mainChar.userData.sprite = mainCharSprite;
addChild(mainChar.userData.sprite);
}
}
}
You need to add your hero as a child of your Main sprite EG:
public function Main():void
{
hero.createMainCharacter(stage.stageWidth/2, stage.stageHeight/2, 50, 50);
addEventListener(Event.ENTER_FRAME, update);
addChild(hero);
}

How to create a Collisions var in the Back class

Edit: I have now included a Player.as and a addchild
I've been trying to understand how to do this all day and again learned a lot in doing so. But I've come to a point that i need help.
I know I have to do this: create a Collisions var in the Back1 class.
Because the background called Back1 is the movieclip that contains the Collisions image
I found a good site or 2 that does a good job of explaining variables and classes but i still don't get how i should solve this problem
Research after variables and classes:
http://www.republicofcode.com/tutorials/flash/as3variables/
http://www.photonstorm.com/archives/1136/flash-game-dev-tip-1-creating-a-cross-game-communications-structure
the above problem results in the folowing error but i believe it is caused by not creating a Collisions var in the Back1 class
ArgumentError: Error #1063: Argument count mismatch on Bumper(). expected: 2, value 0.
at flash.display::MovieClip/gotoAndStop() at
DocumentClass/onRequestStart()DocumentClass.as:64] at
flash.events::EventDispatcher/dispatchEventFunction() at
flash.events::EventDispatcher/dispatchEvent() at
MenuScreen/onClickStart()MenuScreen.as:18]
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.geom.Point;
import Bumper;
//import Back1;
public class Test extends MovieClip
{
public var leftBumping:Boolean = false;
public var rightBumping:Boolean = false;
public var upBumping:Boolean = false;
public var downBumping:Boolean = false;
public var leftBumpPoint:Point = new Point(-30,-55);
public var rightBumpPoint:Point = new Point(30,-55);
public var upBumpPoint:Point = new Point(0,-120);
public var downBumpPoint:Point = new Point(0,0);
public var scrollX:Number = 0;
public var scrollY:Number = 500;
public var xSpeed:Number = 0;
public var ySpeed:Number = 0;
public var speedConstant:Number = 4;
public var frictionConstant:Number = 0.9;
public var gravityConstant:Number = 1.8;
public var jumpConstant:Number = -35;
public var maxSpeedConstant:Number = 18;
public var doubleJumpReady:Boolean = false;
public var upReleasedInAir:Boolean = false;
public var keyCollected:Boolean = false;
public var doorOpen:Boolean = false;
public var currentLevel:int = 1;
public var animationState:String = "idle";
public var bulletList:Array = new Array();
public var enemyList:Array = new Array();
public var bumperList:Array = new Array();
public var back1:Back1;
public var collisions:Collisions;
//public var back1:Collisions = new Collisions ;
public var player:Player;
public function Test()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event):void
{
player = new Player(320, 360);
back1 = new Back1();
collisions = new Collisions();
//back1.collisions = new Collisons();
addBumpersToLevel1();
}
public function addBumpersToLevel1():void
{
addBumper(500, -115);
addBumper(740, -115);
}
public function addPlayerTolevel1():void
{
addPlayer(320, 360);
}
public function loop(e:Event):void
{
trace("back1.collisions "+back1.collisions);
trace("back1 "+back1);
trace("collisions "+collisions);
if (back1.collisions.hitTestPoint(player.x + leftBumpPoint.x,player.y + leftBumpPoint.y,true))
{
just in case i've added Bumper.as
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Bumper extends MovieClip{
public function Bumper(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, bumper);
}
public function bumper(e:Event):void{
//code here
}
}
}
Player.as
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Player extends MovieClip {
public function Player(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
}
// public function removeSelf():void {
// trace("remove enemy");
// removeEventListener(Event.ENTER_FRAME, loop);
// this.parent.removeChild(this);
// }
}
}
the Back1.as file (note it's got to be instanced wrong)
package {
import flash.display.MovieClip;
public class Back1 extends MovieClip {
//public var collisions:Back1;
//what should i put here?
}
}
I am not sure I understand completely what you mean. The question is phrased strange.
I assume you want to achieve a collision between your background object (The Back class) and a player object? I can't see from the code you have posted what the player object is since there is no such variable in your Test class.
To test a collision check between two objects use the following code:
if(someObject.hitTestObject(anotherObject))
Or in your case when using hitTestPoint:
if(back1.hitTestPoint(player.x, player.y,true))
Then again I don't know from the code you have posted how the back1 class looks like. If it extends a MovieClip or Sprite and you have a Player class that does the same (OR any DisplayObject) this should work.
This:
Argument count mismatch on Bumper(). expected: 2, value 0.
The error you get seems to come from another place not shown in your code. I would assume you did not pass any parameters into the Bumper class' constructor.
Btw, is this a Flash IDE sample or some other program such as FlashDevelop or FlashBuilder? If you are using the Flash IDE and are trying to attach code to a movie clip instance placed out on the scene I don't think its possible to pass parameters to it. Sorry been a while since I've worked in the Flash IDE.
EDIT:
Here's some sample code:
//:: Change Back1 class to this
package {
import flash.display.MovieClip;
public class Back1 extends MovieClip {
public function Back1()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, 50, 50);
graphics.endFill();
}
}
}
//:: Then in your Main class (Or the Test class) add the following
var player:Player = new Player(25, 25);
var collidable:Back1 = new Back1();
addChild(player);
addChild(collidable);
//:: Goes in your loop/update
if (collidable.hitTestPoint(player.x, player.y, true))
{
trace("HIT PLAYER");
}
How you apply the graphics to the Back1 class is up to you, I just drew a simple box. It could be anything.
Set default parameters for Bumper class:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Bumper extends MovieClip{
public function Bumper(xLocation:int = 0, yLocation:int = 0) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, bumper);
}
public function bumper(e:Event):void{
//code here
}
}
}

Actionscript: add a sprite from a subclass to the display list of its super class?

Say i have these two classes:
MAIN.as
package
{
import flash.display.*; import mx.core.*;
import flash.events.*; import mx.collections.*;
import flash.geom.*; import mx.controls.*;
import flash.text.*; import mx.events.*;
import mx.styles.*;
import mx.containers.*;
public class MAIN extends Sprite
{
public var APPLICATION:Application = Application(Application.application);
public var keyDownText:TextField = new TextField();
public function MAIN()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN,KEY_DOWN);
addEventListener(Event.ENTER_FRAME,STEP);
new OBJECT_square().CREATE(10,100,1);
}
public function STEP():void {}
public function DRAW():void {}
public function KEY_DOWN(event:KeyboardEvent):void
{
keyDownText.text = "Key code: " + event.keyCode;
this.addChild(keyDownText);
}
}
}
OBJECT_square.as
package
{
import flash.display.*;
import flash.events.*;
public class OBJECT_square extends Sprite
{
public var X:int = 0;
public var Y:int = 0;
public var DEPTH:int = 0;
public var SPRITE:Sprite = new Sprite();
public function CREATE(X:int,Y:int,DEPTH:int):void
{
this.DEPTH = DEPTH;
this.X = X;
this.Y = Y;
DRAW();
}
public function DRAW():void
{
SPRITE.graphics.beginFill(0xFF0000,1);
SPRITE.graphics.drawRect(X - 10,Y - 10,20,20);
SPRITE.graphics.endFill();
addChild(SPRITE);
}
}
}
Now how is it that I can add the variable SPRITE which is a Sprite in the OBJECT_square class to the display list of MAIN class? I've tried addChild(SPRITE) and super.addChild(SPRITE). If everything works I should see a red square somewhere on the screen but right now its all blank, except for the text drawn in the MAIN class.
Basically I want it so i can just make a new OBJECT_square and it will draw itself without any more instructions from the MAIN class.
Try this:
var obj:OBJECT_square = new OBJECT_square();
obj.CREATE(10,100,1);
addChild(obj);
Or, if you really want to do it in one go, you could try this:
In main
addChild((new OBJECT_square()).CREATE(10,100,1));
And change your draw function to return the square object
public function DRAW():OBJECT_square
{
SPRITE.graphics.beginFill(0xFF0000,1);
SPRITE.graphics.drawRect(X - 10,Y - 10,20,20);
SPRITE.graphics.endFill();
addChild(SPRITE);
return this;
}