Line 108 1136: Incorrect number of arguments. Expected 1 - actionscript-3

I cant fix this error and when I do it causes another one. I want to be able to hit key "71" and have a new instance of the movieclip added to the stage. any suggestions? Im a novice so probably alot of mistakes...
package {
import flash.display.MovieClip; //imports needed
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.engine.EastAsianJustifier;
import flash.events.KeyboardEvent;
import flash.display.Stage;
public class myJellyFish extends MovieClip {
private var startScaleX:Number;
private var startScaleY:Number;
//private var cliqued:Number;
private var stayonscreenLeft:Number;
private var stayonscreenRight:Number;
private var stayonscreenTop:Number;
private var stayonscreenBottom:Number;
private var moveDirection:Number;
private var speed:Number;
private var turnspeed:Number;
public function myJellyFish() {
startScaleX = this.scaleX;
startScaleY = this.scaleY;
stayonscreenBottom = 400;
stayonscreenRight = 500;
stayonscreenLeft = 5;
stayonscreenTop = 5;
moveDirection = .5;
speed = Math.random()*10;
turnspeed = 25;
this.addEventListener(MouseEvent.ROLL_OVER, scrolledOver);
this.addEventListener(MouseEvent.ROLL_OUT, scrolledOff);
this.addEventListener(MouseEvent.CLICK, directionChange);
this.addEventListener(Event.ENTER_FRAME, life)
trace("custom class be a working");
// constructor code
}
function myMethod () {
trace("method also be a workin'");
}
private function scrolledOver(Event:MouseEvent):void{
this.alpha = .5;
}
private function scrolledOff(Event:MouseEvent):void{
this.alpha = 1;
}
private function directionChange(e:Event):void{
moveDirection = moveDirection * -1;
}
private function life(e:Event):void{
if (moveDirection > 0){
Hmovement();
}
if (moveDirection < 0){
Vmovement();
}
}
private function Vmovement():void{
this.y += speed;
if(this.y <= stayonscreenBottom){
speed = speed * -1;
this.startScaleY * -1;
}
if(this.y >= stayonscreenTop){
speed = speed * -1;
this.startScaleY * -1;
}
}
private function Hmovement():void{
this.x += speed;
if(this.x >= stayonscreenRight){
speed = speed * -1;
}
if(this.x <= stayonscreenLeft){
speed = speed * -1;
}
}
private function generate(e:KeyboardEvent):void{
var movieClip:myJellyFish = new myJellyFish();
addChild(movieClip);
movieClip.x = (Math.random() * 200) + 20;
movieClip.y = (Math.random()*200) + 20;
movieClip.name = "jellyfish";
}
public function moreClips (event:KeyboardEvent){ //if that key is "F" it will play the tween
trace(event.keyCode);
if (event.keyCode == 71){
generate();
}
}
}//end class
}//end package

First of all, as Rin said, there will be an argument error when calling the generate function.
Secondly, you need to add a KeyboardEvent (ref) listener in order to receive the keyboard events.
The easiest way to listen to keyboard events is to add the listener to the Stage (because the KeyboardEvents will bubble to the Stage no matter where they were triggered.) In order to get a reference to the Stage, you need to wait until your MovieClip has been added to the DisplayList (when your instance of myJellyFish has been added as a child somewhere).
You do this by listening for the Event.ADDED_TO_STAGE event.
// Your constructor
public function myJellyFish() {
// ...
// Add event listener which will trigger when
// the MovieClip has been added to the DisplayList
this.addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
}
protected function handleAddedToStage(e:Event):void {
// Remove event listener since it's no longer needed
this.removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
// You now have a reference to the stage, let's add the KeyboardEvent listener
stage.addEventListener(KeyboardEvent.KEY_DOWN, moreClips);
}
Edit: fixed typo in removeEventListener.

Your generate function has 1 argument wich is e:KeyboardEvent, since you have function moreClips which alredy has the KeyboardEvent, you don't need the argument for the generate function.
Basicly what you are doing now is calling the generate() function without the argument. All you should do is remove the argument from the function.
private function generate():void{
var movieClip:myJellyFish = new myJellyFish();
addChild(movieClip);
movieClip.x = (Math.random() * 200) + 20;
movieClip.y = (Math.random()*200) + 20;
movieClip.name = "jellyfish";
}

Related

AS3 - Space Shooter Enemy Shots

I'm very new to AS3 and programming in general and I've been developing a space shooter game in AS3 and have run into trouble regarding the enemy shots. The enemies fly vertically down from the top of the screen and should fire two shots (one going left and one going right) once their y coordinates equal that of the player. This works fine, except after anything from 30 seconds to 2 minutes, the following errors occur.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at EnemyShip2/fireWeapon()[G:\Games Related\1942\src\EnemyShip2.as:78]
at EnemyShip2/loop2()[G:\Games Related\1942\src\EnemyShip2.as:65]
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at EnemyShot/removeSelf()[G:\Games Related\1942\src\EnemyShot.as:43]
at EnemyShot/loop()[G:\Games Related\1942\src\EnemyShot.as:36]
Below is the relevant code, for the enemy ship class as well as the enemy shot class.
Enemy Ship
package
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.Stage;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
/**
* ...
* #author D Nelson
*/
[Embed(source = "../assets/enemyship2.png")]
//This enemy moves relatively slowly and fires horizontal shots
public class EnemyShip2 extends Bitmap
{
private var vy:Number = 3;
//private var ay:Number = .2;
private var target:HeroShip;
private var enemyShip2:EnemyShip2;
private var enemyfireTimer:Timer;
private var enemycanFire:Boolean = true;
public function EnemyShip2(target:HeroShip):void
{
this.target = target;
scaleX = 0.3;
scaleY = 0.3;
x = Math.floor(Math.random() * 550);
y = -105;
addEventListener(Event.ENTER_FRAME, loop2, false, 0, true);
enemyfireTimer = new Timer(1000, 1);
enemyfireTimer.addEventListener(TimerEvent.TIMER, handleenemyfireTimer, false, 0, true);
}
private function handleenemyfireTimer(e:TimerEvent) : void
{
//the timer runs, so a shot can be fired again
enemycanFire = true;
}
private function removeSelf2():void
{
removeEventListener(Event.ENTER_FRAME, loop2);
if (stage.contains(this))
{
stage.removeChild(this);
}
}
private function loop2 (e:Event):void
{
//vy += ay;
y += vy;
if (y > stage.stageHeight)
{
removeSelf2();
}
if (y >= target.y && (enemycanFire))
{
fireWeapon();
enemycanFire = false;
enemyfireTimer.start();
}
if (this.x > 540 || this.x < 10)
{
removeSelf2();
}
}
private function fireWeapon():void
{
stage.addChild(new EnemyShot(target, x, y, -4));
stage.addChild(new EnemyShot(target, x, y, +4));
}
}
}
Enemy Shot
package
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.events.Event;
import flash.display.Stage;
/**
* ...
* #author D Nelson
*/
[Embed(source="../assets/enemyshot.png")]
public class EnemyShot extends Bitmap
{
private var speed:Number;
private var target:HeroShip;
private var vx:Number;
public function EnemyShot(target:HeroShip, x:Number, y:Number, vx:Number)
{
this.target = target;
this.x = x;
this.y = y;
this.vx = vx;
scaleX = 0.3;
scaleY = 0.3;
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e:Event) : void
{
x += vx;
if (x >= 600 || x <= -50)
{
removeSelf();
}
}
private function removeSelf():void
{
removeEventListener(Event.ENTER_FRAME, loop);
if (stage.contains(this))
{
stage.removeChild(this);
}
}
}
}
Also provided is the main class, in case that is of any help.
package
{
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.display.Stage;
import flash.events.*;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.ui.Mouse;
import flash.utils.*;
import flash.utils.ByteArray;
import flash.utils.Timer;
import flash.text.*;
import flash.media.Sound;
import flash.media.SoundChannel;
/**
* ...
* #author D Nelson
*/
public class Main extends MovieClip
{
[Embed(source = "snd/gamemusic2.mp3")]
private var MySound : Class;
private var mainsound : Sound;
private var shootsound: Sound = new ShootSound;
private var sndChannel:SoundChannel = new SoundChannel;
public var heroShip:HeroShip;
public var enemyShip1:EnemyShip1
public var enemyShip2:EnemyShip2
public var enemyShip3:EnemyShip3
public var enemyShip4:EnemyShip4
public var bossShip: BossShip
public var enemyShot: EnemyShot;
public var playerShot: PlayerShot;
private var background1:Background1;
private var background2:Background2;
public static const scrollspeed:Number = 2;
public var playerShotArray:Array = new Array()
public var enemyShotArray:Array = new Array()
public var enemies1Array:Array = new Array()
public var enemies2Array:Array = new Array()
private var fireTimer:Timer; //this creates a delay between each shot
private var canFire:Boolean = true; //this checks if a shot can be fired
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
mainsound = (new MySound) as Sound;
shootsound = (new ShootSound) as Sound;
mainsound.play();
background1 = new Background1();
background2 = new Background2();
//setting the backgrounds one below another
background1.y = 0;
background2.y = background1.height;
//add background at the lowest depth level
stage.addChildAt(background1,0);
stage.addChildAt(background2, 0);
//sets up the timer and its listener
fireTimer = new Timer(250, 1);
fireTimer.addEventListener(TimerEvent.TIMER, handlefireTimer, false, 0, true);
stage.addEventListener(KeyboardEvent.KEY_DOWN, handleCharacterShoot);
//background scrolling effect
stage.addEventListener(Event.ENTER_FRAME, backgroundScroll);
//loop for enemy1 variety
stage.addEventListener(Event.ENTER_FRAME, loop1, false, 0, true);
//loop for enemy2 variety
stage.addEventListener(Event.ENTER_FRAME, loop2, false, 0, true);
//speed of player shots
setInterval(playerShootMovement, 10);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//entry point
heroShip = new HeroShip();
stage.addChild(heroShip);
//test values for enemies
/*enemyShip1 = new EnemyShip1();
stage.addChildAt(enemyShip1, 2);
enemyShip1.y = stage.stageWidth * 0.3;
enemyShip1.x = 300;
enemyShip2 = new EnemyShip2();
stage.addChildAt(enemyShip2, 2);
enemyShip2.y = stage.stageWidth * 0.3;
enemyShip2.x = 200;
enemyShip3 = new EnemyShip3();
stage.addChildAt(enemyShip3, 2);
enemyShip3.y = stage.stageWidth * 0.3;
enemyShip3.x = 100;
enemyShip4 = new EnemyShip4();
stage.addChildAt(enemyShip4, 2);
enemyShip4.y = stage.stageWidth * 0.3;
enemyShip4.x = 400;
bossShip = new BossShip();
stage.addChildAt(bossShip, 1);
bossShip.y = 10;
bossShip.x = 130;*/
Mouse.hide();
}
private function handlefireTimer(e:TimerEvent) : void
{
//the timer runs, so a shot can be fired again
canFire = true;
}
public function playerShoot():void
{
//if canFire is true, allow a shot to be fired, then set canFire to false and start the timer again
//else, do nothing
if (canFire)
{
//Add new line to the array
playerShotArray.push(playerShot = new PlayerShot);
//Spawn missile in ship
playerShot.y = heroShip.y;
playerShot.x = heroShip.x+11;
addChild(playerShot);
canFire = false;
fireTimer.start();
sndChannel = shootsound.play();
}
}
public function playerShootMovement():void
{
//code adapted from the Pie Throw tutorial
for (var i:int = 0; i < playerShotArray.length; i++)
{
playerShotArray[i].y -= 10;
if (playerShotArray[i].y == 850)
{
playerShotArray.shift();
}
}
}
public function handleCharacterShoot(e:KeyboardEvent):void
{
/**
* SpaceBar = 32
*/
if (e.keyCode == 32)
{
playerShoot();
}
}
public function backgroundScroll (evt:Event):void
{
background1.y += scrollspeed;
background2.y += scrollspeed;
if (background1.y >= stage.stageHeight)
{
//the background is below the visible stage area, put it above the other background
background1.y = background2.y - background2.height;
}
else if (background2.y >= stage.stageHeight)
{
background2.y = background1.y - background2.height;
}
}
//EnemyShip 1 spawning
private function loop1(e:Event):void
{
//generates probability for the ship to spawn (lower number to increase odds, decrease it to decrease odds)
if (Math.floor(Math.random() * 55) == 5)
{
var enemyShip1:EnemyShip1 = new EnemyShip1(heroShip);
enemyShip1.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy1, false, 0, true);
enemies1Array.push(enemyShip1);
stage.addChild(enemyShip1);
}
}
private function removeEnemy1(e:Event):void
{
//removes the enemy that most recently left the screen from the array
enemies1Array.splice(enemies1Array.indexOf(e.currentTarget), 1);
}
//EnemyShip2 spawning
private function loop2(e:Event):void
{
if (Math.floor(Math.random() * 40) == 5)
{
var enemyShip2:EnemyShip2 = new EnemyShip2(heroShip);
enemyShip2.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy2, false, 0, true);
enemies2Array.push(enemyShip2);
stage.addChild(enemyShip2);
}
}
private function removeEnemy2(e:Event):void
{
enemies2Array.splice(enemies2Array.indexOf(e.currentTarget), 1);
}
}
}
Initially I thought it was to do with enemies firing shots while being too far to either side of the screen, but that doesn't seem to be the case. Any help would be greatly appreciated.
You need to make sure you remove the ENTER_FRAME listeners whenever you remove the object.
Actually, my advise is to not add ENTER_FRAME handlers throughout your game objects. This gets hard to manage and leads to bugs like you've encountered. Instead, add a single ENTER_FRAME as your core game loop, and update objects by calling an update() function on a list of game objects you maintain in your main game class. When you remove an object you simply won't call update() anymore. It also becomes easy to pause the game by just removing the ENTER_FRAME handler.
For example, here's a pattern I like to use for simple games:
interface IGameObject {
update():void;
}
class Enemy extends Sprite implements IGameObject {
public update():void {
// move, fire, etc
}
}
class Player extends Sprite implements IGameObject {
public update():void {
// move, fire, etc
}
}
class Bullet extends Bitmap implements IGameObject {
public update():void {
// move, collide, etc
}
}
class Main extends Sprite {
private objects:Vector.<IGameObject> = new <IGameObject>[];
public start():void {
addEventListener(Event.ENTER_FRAME, update);
}
public stopGame():void {
removeEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void {
for each (var object:IGameObject in objects) {
object.update();
}
}
public addObject(object:IGameObject):void {
objects.push(object);
addChild(object as DisplayObject);
}
public removeObject(object:IGameObject):void {
objects.splice(objects.indexOf(object), 1);
removeChild(object as DisplayObject);
}
}
Add and remove objects using addObject and removeObject. You can invoke them through a reference to Main or through event handlers you dispatch from your objects.

AS3 How to call a button from another class?

I'm trying to create a button that when you click on it, the ship fires a laser, but the button isn't working. I mean I didn't get any error when debugging, however it won't allow me to click on the button, but instead it allows me to click on my ship to fire. Any help is greatly appreciated, thanks!
My Fire.as
package control {
import flash.events.Event;
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.events.Event;
import objects.Ship;
public class Fire extends MovieClip {
private var my_x: Number;
private var my_y: Number;
private var ourShip: Ship;
var mouseDown: Boolean;
public function Fire(margin_left: Number, margin_bottom: Number, ourShip_mc: Ship) {
my_x = margin_left;
my_y = margin_bottom;
ourShip = ourShip_mc;
if (stage) {
init();
} else {
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(e: Event = null): void {
if (hasEventListener(Event.ADDED_TO_STAGE)) {
removeEventListener(Event.ADDED_TO_STAGE, init);
}
this.x = my_x + this.width / 2;
this.y = stage.stageHeight - my_y - this.height / 2;
this.addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(event: MouseEvent): void {
//EVENT DISPATCHER
dispatchEvent(new Event("eventshoot", true));
trace("Fire clicked");
}
}
}
My Ship.as
package objects {
import flash.display.MovieClip;
import flash.display.Stage;
import flash.ui.Keyboard;
import flash.ui.Mouse;
import flash.utils.Timer;
import flash.display.JointStyle;
import control.Controller;
import control.Joystick;
import control.Fire;
public class Ship extends MovieClip {
var mouseDown: Boolean;
private var stageRef: Stage;
private var key: Controller;
private var speed: Number = 2.5;
private var vx: Number = 0;
private var vy: Number = 0;
private var friction: Number = 0.93;
private var maxspeed: Number = 8;
//fire related variables
private var fireTimer: Timer; //causes delay between fires
private var canFire: Boolean = true; //can you fire a laser
public var move_left: Boolean = false;
public var move_up: Boolean = false;
public var move_right: Boolean = false;
public var move_down: Boolean = false;
public function Ship(stageRef: Stage): void {
this.stageRef = stageRef;
key = new Controller(stageRef);
this.addEventListener(Event.ENTER_FRAME, ShipMove);
stage.addEventListener("eventshoot", firenow);
//setup your fireTimer and attach a listener to it.
fireTimer = new Timer(250, 1);
fireTimer.addEventListener(TimerEvent.TIMER, fireTimerHandler, false, 0, true);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function ShipMove(event: Event): void {
if (move_left)
vx -= speed;
else if (move_right)
vx += speed;
else
vx *= friction;
if (move_up)
vy -= speed;
else if (move_down)
vy += speed;
else
vy *= friction;
}
public function firenow(event: Event) {
fireLaser();
}
public function loop(e: Event): void {
//update position
x += vx;
y += vy;
//speed adjustment
if (vx > maxspeed)
vx = maxspeed;
else if (vx < -maxspeed)
vx = -maxspeed;
if (vy > maxspeed)
vy = maxspeed;
else if (vy < -maxspeed)
vy = -maxspeed;
//ship appearance
rotation = vx;
scaleX = (maxspeed - Math.abs(vx)) / (maxspeed * 4) + 0.75;
//stay inside screen
if (x > stageRef.stageWidth - 30) {
x = stageRef.stageWidth - 30;
vx = -vx;
} else if (x < 30) {
x = 30;
vx = -vx;
}
if (y > stageRef.stageHeight) {
y = stageRef.stageHeight;
vy = -vy;
} else if (y < 0) {
y = 0;
vy = -vy;
}
}
private function fireLaser(): void {
//if canFire is true, fire a laser
//set canFire to false and start our timer
//else do nothing.
if (canFire) {
stageRef.addChild(new LaserGreen(stageRef, x + vx, y - 10));
canFire = false;
fireTimer.start();
}
}
//HANDLERS
private function fireTimerHandler(e: TimerEvent): void {
//Timer ran, fire again.
canFire = true;
}
public function takeHit(): void {
dispatchEvent(new Event("hit"));
}
}
}
Updated, here's the Engine.as, sorry for not replying it to your comment below, the structure is messed up if I do so.
package objects {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import control.Joystick;
import control.Fire;
public class Engine extends MovieClip {
private var preloader: ThePreloader;
public function Engine() {
preloader = new ThePreloader(474, this.loaderInfo);
stage.addChild(preloader);
preloader.addEventListener("loadComplete", loadAssets);
preloader.addEventListener("preloaderFinished", showSponsors);
stage.addEventListener("gameSTART", fGameStart);
}
private function loadAssets(e: Event): void {
this.play();
}
private function showSponsors(e: Event): void {
stage.removeChild(preloader);
var ps: PrerollSponsors = new PrerollSponsors(stage);
ps.addEventListener("prerollComplete", showMenu);
ps.preroll();
}
private function showMenu(e: Event): void {
new MainMenu(stage).load();
}
public static var enemyList: Array = new Array();
private var ourShip: Ship;
private var joystick: Joystick;
private var fire: Fire;
private var scoreHUD: ScoreHUD;
public function fGameStart(evt: Event): void {
ourShip = new Ship(stage);
ourShip.x = stage.stageWidth / 2;
ourShip.y = stage.stageHeight / 2;
ourShip.addEventListener("hit", shipHit, false, 0, true);
stage.addChild(ourShip);
joystick = new Joystick(120, 70, ourShip);
addChild(joystick);
fire = new Fire(420, 70, ourShip);
addChild(fire);
scoreHUD = new ScoreHUD(stage);
stage.addChild(scoreHUD);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e: Event): void {
if (Math.floor(Math.random() * 20) == 5) {
var enemy: E1 = new E1(stage, ourShip);
enemy.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy, false, 0, true);
enemy.addEventListener("killed", enemyKilled, false, 0, true);
enemyList.push(enemy);
stage.addChild(enemy);
} else if (Math.floor(Math.random() * 80) == 5) {
var enemy2: E2 = new E2(stage, ourShip);
enemy2.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy, false, 0, true);
enemy2.addEventListener("killed", enemyKilled, false, 0, true);
enemyList.push(enemy2);
stage.addChild(enemy2);
}
}
private function enemyKilled(e: Event) {
scoreHUD.updateKills(1);
scoreHUD.updateScore(e.currentTarget.points);
}
private function removeEnemy(e: Event) {
enemyList.splice(enemyList.indexOf(e.currentTarget), 1);
}
private function shipHit(e: Event) {
scoreHUD.updateHits(1);
}
}
}
So every time the fire button (Fire.as) is clicked, it dispatched an event "eventshoot", and the ship (Ship.as) pick it up. And when the ship receive it, the ship itself fires a laser, that's the idea. But since there are prerolls, menus...stuff like that will loaded before starting the game, I can't just simply drag the fire button to the stage. The engine will load the ship, fire button, enemy, score... to the stage when game started. And I got a error 1009 when debugging "TypeError: Error #1009: Cannot access a property or method of a null object reference.", it is from:
stage.addEventListener("eventshoot", fire now);
in Ship.as
I understand that I'm getting this error because there is no fire button on stage, so my ship can't pickup the "eventshoot" event, is there a way I can make the ship only pickup that event after making sure the button is loaded to the stage to avoid the error?
While you certainly can create a class for your button, the functionality to make the ship object fire a laser should not be in the button.
Given a Ship class that looks like this:
package
{
import flash.display.MovieClip;
public class Ship extends MovieClip
{
public function fireLaser():void
{
trace("pew pew");
}
}
}
You can instantiate this class and add it to your main timeline with this code:
var ship:Ship = new Ship();
addChild(ship);
If you placed the symbol by hand you do not need to do this and instead only need to give it an instance name of ship.
To make something clickable, add an event listener to it. For example, to make the ship itself clickable:
var ship:Ship = new Ship();
addChild(ship);
ship.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
function onMouseDown(event:MouseEvent):void
{
trace("ship clicked");
}
If you have a button on the main time line with an instance name of fire, you can as easily add the listener to that button:
var ship:Ship = new Ship();
addChild(ship);
// v---this changed
fire.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
function onMouseDown(event:MouseEvent):void
{
trace("fire button clicked");
}
Last but not least, if you want to call a method on an object instead of using trace(), you can do that, too:
var ship:Ship = new Ship();
addChild(ship);
fire.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
function onMouseDown(event:MouseEvent):void
{
ship.fireLaser(); // this changed, laser fired "pew pew"
}
tl, dr;
The button itself shouldn't do anything. If the button did anything with the ship directly, it would have to know the ship. The button shouldn't know the ship. All the button does is say "I got clicked" by dispatching an event, everything else should be handled outside.
You know, just like when you wrote your question here, it's not the entire internet (including me) sitting in the keyboard buttons of your computer listening to your input. All your keyboard buttons did was saying "I got clicked". Everything else got handled outside, by your operating system, browser, etc.

Looping Error when doing a hitTest in as3

So, I have this code:
public function hitTest1(e:Event) : void
{
if (hitTestObject(target.hit)){
gotoAndStop(2,"Scene 1");
removeEventListener(Event.ENTER_FRAME, hitTest1);
}
}
In which target is the object that is going to be hit, and hit is a symbol in a layer over said object. When I run the code I get this error over an over again.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.Mass.basics1::Asteroid/hitTest1()
NOTE: Asteroid is the .as file that contains all of this code.
Here is the rest of the code for reference :
package com.Mass.basics1
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class Asteroid extends MovieClip
{
public var target:Cosmo;
private var stageRef:Stage;
private var speed:Number;
// public var ourAsteroid:Asteroid = new Asteroid(stage);
public function Asteroid(stageRef:Stage)
{
this.stageRef = stageRef;
setupAsteroid(true);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
addEventListener(Event.ENTER_FRAME, hitTest1);
}
public function hitTest1(e:Event):void
{
if (hitTestObject(target.hit))
{
gotoAndStop(2,"Scene 1");
removeEventListener(Event.ENTER_FRAME, hitTest1);
}
}
public function setupAsteroid(randomizeY:Boolean = false):void
{
//inline conditional, looks complicated but it's not.
y = randomizeY ? Math.random() * stageRef.stageHeight:0;
x = Math.random() * stageRef.stageWidth;
rotation = Math.random() * 360;
scaleX = Math.random();
scaleY = scaleX;
speed = 20 + Math.random() * 10;
}
public function loop(e:Event):void
{
y += speed;
if (y > stageRef.stageHeight)
{
setupAsteroid();
}
}
}
}
So, where is the "target" object? You're just declaring a variable, but not creating the object or setting a reference. It's a public variable, so maybe you are setting a reference somewhere else? In that case, make sure you assign a reference before you are calling hitTest1 function...

A loop in enterframe?

I'm animating a bunch of words in AS3. Because I'm going to be using this on a mobile device, I want to use bitmaps rather than Sprites. So I've created WordObjects, which have a .bitmap property that I can access.
I have the following code, which fires on the click event and loops through an array inside an enterframe event. This is probably a bad idea, but I'm not sure how to do it better. (What is surprising is that it runs just fine in Flashbuilder, but slows to a crawl in Flash CS5.)
Is there some better way to do this? I just want an efficient way to animate the array of bitmaps.
private function clickhandler (e:MouseEvent){
this.addEventListener(Event.ENTER_FRAME, blowemup);
}
private function blowemup(e:Event){
var newPosition:Number;
for(var i:int=0; i<arrWordObjects.length; i++)
{
newPosition = updatePosition(arrWordObjects[i].bitmap);
arrWordObjects[i].bitmap.x += newPosition;
arrWordObjects[i].bitmap.y += getRandomNumber();
}
}
Something that will make a huge difference is using for each(Object in Array) rather than the standard for loop.
private function blowemup(e:Event):void
{
var newPosition:Number;
var i:ArrWordsObjectClass; // <-- don't know what the class for this is, just replace
for each(i in arrWordObjects)
{
newPosition = updatePosition(i.bitmap);
i.bitmap.x += newPosition;
i.bitmap.y += getRandomNumber();
}
}
A for each loop is typed, meaning a lot of time is saved where normally it'd be trying to work out what arrWordObjects[i] is every iteration.
Also, side note: using one ENTER_FRAME driven function and looping through everything in your application that you want to handle each frame is much more efficient than applying hundreds of listeners for objects.
I normally create a handler class that contains the ENTER_FRAME and an array storing my objects, like so:
package
{
import flash.events.Event;
import flash.display.Sprite;
public class Handler extends Sprite
{
// vars
public var elements:Array = [];
/**
* Constructor
*/
public function Handler()
{
addEventListener(Event.ENTER_FRAME, _handle);
}
/**
* Called on each dispatch of Event.ENTER_FRAME
*/
private function _handle(e:Event):void
{
var i:Element;
for each(i in elements)
{
i.step();
}
}
}
}
Then I create a base class for all the objects that I want to handle, containing the step() function called above.
package
{
import flash.display.DisplayObject;
public class Element extends Object
{
// vars
public var skin:DisplayObject;
/**
* Called on each dispatch of Event.ENTER_FRAME at Handler
*/
public function step():void
{
// override me
}
}
}
Now just extend Element with your objects:
package
{
import flash.display.Sprite;
public class MyThing extends Element
{
/**
* Constructor
*/
public function MyThing()
{
skin = new Sprite();
skin.graphics.beginFill(0);
skin.graphics.drawCircle(0,0,40);
skin.graphics.endFill();
}
/**
* Override step
*/
override public function step():void
{
skin.x += 4;
}
}
}
And get it all going!:
var handler:Handler = new Handler();
var m:MyThing;
var i:uint = 0;
for(i; i<10; i++)
{
m = new MyThing();
m.y = Math.random()*stage.stageHeight;
handler.elements.push(m);
addChild(m.skin);
}
How many bitmaps do you plan to have on the stage at a time?
I have had 40 900x16px bitmaps animating on the stage at full speed running on my iphone using air 2.6.
I used a foreach loop in an enterframe event which i added on mouseclick and removed once the animation was finished.
Remember to compile it for the mobile with gpu rendering enabled. (gpu in your app.xml if you are using air 2.6)
This is worth a read too, it explains a lot about performance for mobile devices
http://help.adobe.com/en_US/as3/mobile/WS901d38e593cd1bac-3d719af412b2b394529-8000.html
Here is a basic example of what I had...
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
[SWF(frameRate="30", backgroundColor="#FF00FF")]
public class Test extends Sprite
{
private var fields:Vector.<Bitmap> = new Vector.<Bitmap>();
public function Test()
{
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.align = StageAlign.TOP_LEFT;
for(var i:int = 0; i< 37; i++){
var bd:BitmapData = new BitmapData(960, 16, true, 0x000000);
bd.fillRect(new Rectangle(0, 0, 900, 16), Math.round( Math.random()*0xFFFFFFFF ));
var b:Bitmap = new Bitmap(bd);
b.x = 0;
b.y = i*16;
stage.addChild(b);
fields.push(b);
}
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private var inertia:Boolean = false;
private var yCurrent:Number;
private var ySpeed:Number;
private var startY:Number;
private var cy:Number = 0;
private function onEnterFrame(e:Event):void{
if(!inertia){
ySpeed = (startY - yCurrent) ; // / 16;
startY = yCurrent
} else {
ySpeed *= 0.8;
if(ySpeed < 0.01 && ySpeed > -0.01){
inertia = false;
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
cy += ySpeed;
if(cy > 640)
cy -= 640;
var ty:Number = cy;
for each(var tf:Bitmap in fields){
tf.y = ty;
ty += 16;
if(ty > 640)
ty -= 640;
}
}
private function onMouseDown(e:MouseEvent):void{
inertia = false;
startY = e.stageY;
yCurrent = e.stageY;
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onMouseMove(e:MouseEvent):void{
yCurrent = e.stageY;
}
private function onMouseUp(e:Event):void{
inertia = true;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
}
}
I would suggest looking at writing a custom effect on Adobe's website over registering for ENTER_FRAME event. What you've put up there means this code will forever run as long as the program is running. If you wanted to stop the effect or run for 10 frames and stop then you'll have to write more code. It gets even more complex if you want to apply this to several instances. You're going to have to resolve problems that custom effects framework solves.
I'd read how to write custom effects here:
http://livedocs.adobe.com/flex/3/html/help.html?content=createeffects_1.html

"upload" is not a function

I have an annoying problem. I've googled a bit and can't really find any good answers, so I'm hoping to find some help here.
I'm getting this error, which seems to be fairly common:
TypeError: Error #1006: update är inte en funktion. // = update is not a function (english)
at se.qmd.spaceInvaders::ShipHandler/onEnterFrame()
Update definently is a function, so I really can't understand what the problem is.
My setup. I'm using Flashdevelop. I have a Main class, which is set as the document class in my fla file.
I have a package structure with my Main class in the src folder, and my subclasses in se.qmd.spaceInvaders and se.qmd.starLight. I also use TweenMax and keep it in the "normal" package structure from the src folder.
In the Main class I add to the stage an instance of the class LeGun - which is also an "exported" movieclip in the fla file, an instance of the class StarHandler and an instance of the class ShipHandler. I also have a keyboard listener which with the help of an enterframe function moves my instance of the LeGun class.
Fine, no problems. The StarHandler works like it should, and the ShipHandler works as it should up until i call 1 or 2 methods in the Ship class - which is also an "exported" movieclip in the fla file. The Ship class is of course the class that contains the Ship that is handled by the ShipHandler.
I'm including my ShipHandler and Ship classes below, and hope it doesn't make the post excede some length.
ShipHandler.as :
package se.qmd.spaceInvaders {
import flash.display.MovieClip;
import se.qmd.spaceInvaders.Ship;
import flash.display.Stage;
import flash.events.Event;
public class ShipHandler extends MovieClip {
private var _shipArray:Array = [];
private const NUM_START_SHIPS:int = 25;
private var s:Stage = null;
private var _directionX:Number = 1;
private var _directionY:Number = 1;
private var _velocityX:Number;
private var _velocityY:Number;
private const YBORDER_TOP:int = 50;
private const YBORDER_BOTTOM:int = 525;
public function ShipHandler(o:Stage) {
s = o; // tar emot stage från main
createObjects();
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function createObjects():void {
for (var i:int = 0; i < NUM_START_SHIPS; i++) {
var aShip:Ship = new Ship();
aShip.x = Math.random() * (s.stageWidth - aShip.width) + aShip.width / 2;
aShip.y = Math.random() * (s.stageHeight - aShip.height -135) + aShip.height / 2 + 55;
this.addChild(aShip);
_shipArray.push(aShip);
aShip.startMove(Math.random(), Math.random());
}
}
private function onEnterFrame(e:Event):void {
for (var i:int = 0; i < _shipArray.length; i++) {
var aShip:Ship = _shipArray[i] as Ship;
aShip.update();
}
}
}
}
Ship.as :
package se.qmd.spaceInvaders {
import flash.display.MovieClip;
import flash.events.Event;
public class Ship extends MovieClip {
private var _directionX:Number = 1;
private var _directionY:Number = 1;
private var _velocityX:Number;
private var _velocityY:Number;
private const YBORDER_TOP:int = 50;
private const YBORDER_BOTTOM:int = 525;
public function Ship() {
//s = o; // tar emot stage
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
this.width = 50;
this.height = 18;
}
public function update():void {
// x led vänster kant
if(this.x <= this.width / 2) {
this.x = this.width / 2;
_directionX *= -1;
}
// x led höger kant
if(this.x >= 800 - this.width / 2) {
this.x = 800 - this.width/2;
_directionX *= -1;
}
// y led top kant
if(this.y <= YBORDER_TOP + this.height/2) {
this.y = YBORDER_TOP + this.height / 2;
_directionY *= -1;
}
// y led botten kant
if(this.y >= YBORDER_BOTTOM - this.height/2) {
this.y = YBORDER_BOTTOM - this.height / 2;
_directionY *= -1;
}
this.x += _velocityX * _directionX;
this.y += _velocityY * _directionY;
}
public function startMove(directionX:Number, directionY:Number):void {
trace(directionX, directionY);
_velocityX = 10;
_velocityY = 10;
if (directionX < 0.5) {
_directionX = -1;
}
if (directionY < 0.5) {
_directionY = -1;
}
}
public function changeDirection():void {
_directionX *= -1;
_directionY *= -1;
}
}
}
As soon as i call either the methods startMove or update from the ShipHandler, i get the error i wrote above.
Would appreciate any help as it seems to me I must be doing something fundamentally wrong...
It sounds to me like Ship is just a MovieClip (which is a dynamic class and hence the compiler is not complaining when you're trying to access a method that does not exist at compile-time.) MovieClips don't have an update() method, so when you try to invoke it, it cannot be found on the Ship instance.
Is the MovieClip in your FLA file really exported as se.qmd.spaceInvaders.Ship (and not just Ship)? If it's just Ship, that would explain why your written class is not assigned as the class of your ship graphics, leaving it to be just a simple MovieClip which would explain this error.
I have tried your original code and it works fine for me. I did not need to change anything.
Are you compiling from the Flash IDE? In that case, try cleaning the cache with Control > Delete ASO files like this:
Try casting the ship instead like this:
private function onEnterFrame(e:Event):void {
for (var i:int = 0; i < _shipArray.length; i++) {
var aShip:Ship = Ship(_shipArray[i]);
if(aShip)
aShip.update();
else
throw Error("ship is null at position " + i)
}
}
Or use Vector instead of Array:
var _shipArray : Vector.<Ship> = new Vector.<Ship>();