I'm a rather new to programming with AS3 and started with the rather old MJW AvoiderGame tutorial. Since this tutorial is a bit old, I have got a lot of errors while trying to learn AS3. Now I got an error that I cant figure out.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AvoiderGame/onTick()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
The problem seems to be in the onTick function in AvoiderGame class. Here is the AvoiderGame class:
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class AvoiderGame extends MovieClip
{
public var army:Array;
public var enemy:Enemy;
public var avatar:Avatar;
public var gameTimer:Timer;
public var gameClock:Clock;
public function AvoiderGame()
{
army = new Array();
var newEnemy = new Enemy( 200, -15 );
army.push( newEnemy );
addChild( newEnemy );
avatar = new Avatar();
addChild( avatar );
avatar.x = mouseX;
avatar.y = mouseY;
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, onTick );
gameTimer.start();
}
public function onTick( timerEvent:TimerEvent ):void
{
gameClock.addToValue( 25 );
if ( Math.random() < 0.1 )
{
var randomX:Number = Math.random() * 800;
var newEnemy:Enemy = new Enemy( randomX, -15 );
army.push( newEnemy );
addChild( newEnemy );
gameScore.addToValue( 10 );
}
avatar.x = mouseX;
avatar.y = mouseY;
for each ( var enemy:Enemy in army )
{
enemy.moveDownABit();
if ( avatar.hitTestObject( enemy ) )
{
gameTimer.stop();
dispatchEvent( new AvatarEvent( AvatarEvent.DEAD ) );
}
}
}
public function getFinalScore():Number
{
return gameScore.currentValue;
}
public function getFinalClockTime():Number
{
return gameClock.currentValue;
}
}
}
It's fairly obvious - in onTick() the first line is
gameClock.addToValue( 25 );
but you never initialize the gameClock field. That way it has the default null value hence the error you see. You should initialize it accordingly just the way you initialize the gameTimer field.
Related
I'm trying to remove this item from the stage and keep getting this error. The code seems to work and the object is removed but the game seems kinda buggy.
Here's the full error:
ArgumentError: Error #2025: The supplied DisplayObject must be a child
of the caller. at flash.display::DisplayObjectContainer/removeChild()
at
JumpingGame/onTick2()[E:\Folder\Folder\Folder\Folder\JumpingGame.as:95]
at flash.utils::Timer/_timerDispatch() at flash.utils::Timer/tick()
The error is pointing to:
removeChild(enemy)
removeChild(leg);
removeChild(life);
I'm also getting:
TypeError: Error #1009: Cannot access a property or method of a null
object reference
on this line theLives.text = liveLives.toString();
Here's my code:
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class JumpingGame extends MovieClip
{
public var army:Array;
public var powerups:Array;
public var pluslives:Array;
public var newDoodle:doodle;
public var enemyTimer:Timer;
public var legTimer:Timer;
public var lifeTimer:Timer;
public function JumpingGame()
{
enemyTimer = new Timer( 40 );
enemyTimer.addEventListener( TimerEvent.TIMER, onTick );
enemyTimer.start();
legTimer = new Timer( 20 );
legTimer.addEventListener( TimerEvent.TIMER, onTick2 );
legTimer.start();
lifeTimer = new Timer( 30 );
lifeTimer.addEventListener( TimerEvent.TIMER, onTick3 );
lifeTimer.start();
army = new Array();
var newEnemy = new Enemy( 100, -15 );
army.push( newEnemy );
addChild( newEnemy );
powerups = new Array();
var newLeg = new Leg( 300, -15 );
powerups.push( newLeg );
addChild( newLeg );
pluslives = new Array();
var newLife = new Plus1( 300, -15 );
pluslives.push( newLife );
addChild( newLife );
newDoodle = new doodle();
addChild( newDoodle );
newDoodle.y = stage.stageHeight - 50;
newDoodle.x = stage.stageWidth / 2;
}
public function onTick( timerEvent:TimerEvent ):void
{
if (Math.random() <0.005 )
{
var randomX:Number = Math.random() * 320;
var newEnemy:Enemy = new Enemy( randomX, -15 );
army.push( newEnemy );
addChild( newEnemy );
}
for each ( var enemy:Enemy in army )
{
enemy.moveDownABit();
if (newDoodle.hitTestObject( enemy ) )
{
//gotoAndPlay ("Game Over");
removeChild(enemy);
liveLives -= 1;
theLives.text = liveLives.toString();
}
}
}
public function onTick2( timerEvent:TimerEvent ):void
{
if (Math.random() <0.008 )
{
var randomX2:Number = Math.random() * 320;
var newLeg:Leg = new Leg( randomX2, -15 );
powerups.push( newLeg );
addChild( newLeg );
}
for each ( var leg:Leg in powerups )
{
leg.moveDownABit2();
if (newDoodle.hitTestObject( leg ) )
{
//gotoAndPlay ("Game Over");
removeChild(leg);
liveScore += 2000;
theScore.text = liveScore.toString();
}
}
}
public function onTick3( timerEvent:TimerEvent ):void
{
if (Math.random() <0.001 )
{
var randomX3:Number = Math.random() * 320;
var newLife:Plus1 = new Plus1( randomX3, -15 );
pluslives.push( newLife );
addChild( newLife );
}
for each ( var life:Plus1 in pluslives )
{
life.moveDownABit3();
if (newDoodle.hitTestObject( life ) )
{
//gotoAndPlay ("Game Over");
removeChild(life);
liveLives += 1;
theLives.text = liveLives.toString();
}
}
}
}
}
Try using:
enemy.parent.removeChild(enemy)
leg.parent.removeChild(leg);
life.parent.removeChild(life);
And there is no liveLives var, or theLives textfield on stage is misspelled.
The problem you have is caused by removing the objects from the display list without removing them from the data structure that you store them in.
Take a look at this excerpt from your code:
Let's say that powerups has only one element and hitTestObject returns true. The object is removed from display.
for each ( var leg:Leg in powerups )
{
if (newDoodle.hitTestObject( leg ) )
{
removeChild(leg);
the code is executed the second time. The object is still in the array. hitTestObject still returns true. The object cannot be removed from display, because it was removed already when the function was executed for the first time.
You have two data structures: the display list and your array and they are out of sync.
To solve this, remove the object from the array, not just the display list:
find the index of the object that you want to remove with indexOf()
remove the element at that index with splice()
In this case, you should not use 3 array to store child objects. Simple that, you create 3 empty movie clips and add child to them. After that, you remove them when hit test.
Something like that:
public function onTick( timerEvent:TimerEvent ):void
{
if (Math.random() <0.005 )
{
var randomX:Number = Math.random() * 320;
var newEnemy:Enemy = new Enemy( randomX, -15 );
armyContainer.addChild( newEnemy );
}
var childs:Array = [];
for (var i:int = 0; i<armyContainer.numChildren; i++) {
var enemy:Enemy = armyContainer.getChildAt(i) as Enemy;
enemy.moveDownABit();
if (newDoodle.hitTestObject( enemy ) )
{
//gotoAndPlay ("Game Over");
//removeChild(enemy);
childs.push(enemy);
liveLives -= 1;
theLives.text = liveLives.toString();
}
}
for each ( var child:Enemy in childs )
{
armyContainer.removeChild(child);
}
}
I know this is a common question, but I've looked through all of the others and couldn't figure out a solution for my problem.
I've debugged and found the offending line of code, but I'm not sure what exactly it is that's wrong with it or how to fix it.
Code below - the error is thrown when "enemy.movement();" calls the movement function in the Enemy class. The first 2 lines of code(var xDist and var yDist) or specifically flagged.
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
public class zombiestandoffMain extends MovieClip
{
static public var enemy:Enemy;
static public var player:Player;
public var gameTimer:Timer;
public var crosshair:Crosshair;
public var army:Array;
public function zombiestandoffMain()
{
//enemy = new Enemy();
//addChild( enemy );
army = new Array();
var newEnemy = new Enemy;
army.push( newEnemy );
addChild( newEnemy );
player = new Player();
addChild( player );
crosshair = new Crosshair();
addChild( crosshair );
crosshair.x = mouseX;
crosshair.y = mouseY;
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, onTick );
gameTimer.start();
}
public function onTick( timerEvent:TimerEvent ):void
{
var newEnemy:Enemy = new Enemy;
army.push( newEnemy );
addChild( newEnemy );
crosshair.x = mouseX;
crosshair.y = mouseY;
for each ( var enemy:Enemy in army ) {
enemy.movement();
}
//if ( player.hitTestObject( enemy ) )
//{
//}
}
}
}
And the Enemy class:
package
{
import flash.display.MovieClip;
import flash.geom.Point;
import flash.events.Event;
public class Enemy extends MovieClip
{
public var sideSpawn = int(Math.random() * 3)
public function Enemy()
{
if (sideSpawn == 0) {//top
x = Math.random() * 800;
y = 200;
} else if (sideSpawn == 1) {//left
x = -20;
y = (Math.floor(Math.random() * (1 + 800 - 200)) + 200);
} else if (sideSpawn == 2) {//right
x = 800 + 20;
y = (Math.floor(Math.random() * (1 + 800 - 200)) + 200);
} else { //bottom
x = Math.random() * 800;
y = 800 + 20;
//(Math.floor(Math.random() * (1 + high - low)) + low);
}
}
public function movement():void {
var xDist = Math.abs(zombiestandoffMain.enemy.x - zombiestandoffMain.player.x);
var yDist = Math.abs(zombiestandoffMain.enemy.y - zombiestandoffMain.player.y);
if (xDist > yDist) {
if (zombiestandoffMain.enemy.x > zombiestandoffMain.player.x)
zombiestandoffMain.enemy.x-=2;
else zombiestandoffMain.enemy.x+=2;
} else {
if (zombiestandoffMain.enemy.y > zombiestandoffMain.player.y)
zombiestandoffMain.enemy.y-=2;
else zombiestandoffMain.enemy.y+=2;
}
}
}
}
My best guess is that the x and y coords for enemy are null - but I've tried inserting values for the coords and still get the same error.
Thank you for any help!
You've only declared enemy, you must also define it. Set enemy inside zombiestandoffMain to a new Enemy obect:
enemy = new Enemy();
I guess it's with the zombiestandoffMain you are referencing in the movement() method. I do not see any definition of it in the Enemy Class. if it is meant to be defined manually in the flash environment or somewhere make sure that this property is (zombiestandoffMain) is reference properly. Hope that helps
I keep getting the following error when I fire a Shot I made in Flash CS6 AS 3.0
1118: Implicit coercion of a value with static type Object to a possibly unrelated type flash.display:DisplayObject.
package
{
import flash.display.MovieClip;
import flash.ui.Mouse;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.media.SoundChannel;
public class AvoiderGame extends MovieClip
{
public var army:Array;
public var reishoot:ReiShoot;
public var enemy:Enemy;
public var avatar:Avatar;
public var gameTimer:Timer;
public var useMouseControl:Boolean;
public var downKey:Boolean;
public var bullets:Array = [];
public var backgroundMusic:BackgroundMusic;
public var enemySound:EnemySound;
public var bgmSoundChannel:SoundChannel;
public var sfxSoundChannel:SoundChannel;
function AvoiderGame()
{
/*useMouseControl = false;
downKey = false;
if( useMouseControl )
{
avatar.x = mouseX;
avatar.y = mouseY;
}
else
{
avatar.x = 200;
avatar.y = 250;
}
*/
backgroundMusic = new BackgroundMusic();
bgmSoundChannel = backgroundMusic.play();
bgmSoundChannel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished );
enemySound = new EnemySound();
army = new Array();
//Initial Position of the Enemy
var newEnemy = new Enemy( 2700, 600 );
army.push( newEnemy );
addChild( newEnemy );
avatar = new Avatar();
addChild( avatar );
avatar.height = 220;
avatar.width = 120;
avatar.addEventListener(MouseEvent.CLICK, shoot);
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, onTick );
gameTimer.start();
//addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
}//End AvoiderGame
function shoot(e:MouseEvent):void
{
var b:Shot = new Shot();
b.addEventListener(Event.ENTER_FRAME, bulletflies);
stage.addChild(b);
bullets.push(b);
}
function bulletflies(e:Event):void
{
e.currentTarget.y -= 5;
if(e.currentTarget.y < 0 || e.currentTarget.y > stage.height)
{
stage.removeChild(e.currentTarget);
bullets.splice(bullets.indexOf(e.currentTarget), 1);
}
}
public function onBackgroundMusicFinished( event:Event ):void
{
bgmSoundChannel = backgroundMusic.play();
bgmSoundChannel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished );
}
public function onKeyPress(keyboardEvent:KeyboardEvent):void
{
if ( keyboardEvent.keyCode == Keyboard.DOWN )
{
downKey = true;
}
}
public function onKeyRelease( keyboardEvent:KeyboardEvent ):void
{
if ( keyboardEvent.keyCode == Keyboard.DOWN )
{
downKey = false;
}
}
public function onAddToStage(event:Event):void
{
stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );
}
public function onTick( timerEvent:TimerEvent ):void
{
if ( Math.random() < 2800 )
{
var randomY:Number = Math.random() * 2800;
var newEnemy:Enemy = new Enemy( width, randomY );
army.push( newEnemy );
addChild( newEnemy );
gameScore.addToValue( 1 );
//sfxSoundChannel = enemySound.play();
}//End if statement
/*
if( useMouseControl )
{
avatar.x = mouseX;
avatar.y = mouseY;
}
else
{
if ( downKey )
{
avatar.moveDown();
}
}
*/
avatar.x = mouseX;
avatar.y = mouseY;
for each ( var enemy:Enemy in army )
{
enemy.moveDownABit();
if ( avatar.hitTestObject( enemy ) )
{
bgmSoundChannel.stop();
gameTimer.stop();
dispatchEvent( new AvatarEvent( AvatarEvent.DEAD ) );
}//End if statement
}//End for loop
}//End onTick function
public function getFinalScore():Number
{
return gameScore.currentValue;
}
}//End AvoiderGame class
}//End package
Line 90 is stage.removeChild(e.currentTarget);
With this, you need to cast e.currentTarget to a DisplayObject:
stage.removeChild(e.currentTarget as DisplayObject);
Just a guess: you've started your ENTER_FRAME loop, (which will remove 'b') before you've said addChild(b). Try putting 'b' on the display list before you try to remove it!!
Aha! I think I may have found your problem, though I am unsure of how it relates to the error code...
Take a look at your Shot class (which I have found here https://stackoverflow.com/questions/22244959/why-does-this-not-shoot). Every frame, you tell the Shot class to test whether it is in the boundaries of the stage still, and if so, to remove itself from the stage. In line 90, you also tell the stage to determine if the bullet is still in bounds, and if so, to remove it again.
You have tried to remove the bullet from the stage twice!
Again, I stress, this seems to be unrelated to the error code, but hopefully it points you in the right direction.
I need to load in an external swf and be able to use it as a Movieclip in FlashDevelop i.e I need to be able to go to specific keyframes, start and stop it playing etc. Some simple working sample code would be hugely appreciated as I cannot find any satisfactory tutorials through Google.
EDIT
I now have this code
package
{
import flash.net.*;
import flash.display.*;
import flash.events.*;
import flash.utils.getQualifiedClassName;
public class Main extends MovieClip
{
var animatedBox:MovieClip = new MovieClip();
var ldr:Loader = new Loader();
var frames:int = 0;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onload);
ldr.load(new URLRequest("../lib/test.swf"));
}
function onload(e:Event)
{
if ( !e.target )
return;
if( e.target.content is MovieClip )
{
animatedBox = e.target.content as MovieClip;
animatedBox.gotoAndPlay("Start");
}
else
{
trace( getQualifiedClassName( e.target.content ) );
}
}
}
}
After I try to run it I get [Fault] exception, information=TypeError: Error #1009: Cannot access a property or method of a null object reference.
Any ideas?
import flash.utils.getQualifiedClassName;
var mc: MovieClip;
var ldr: Loader = new Loader();
ldr.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoad );
ldr.load( new URLRequest("your.swf") );
function onLoad( e:Event ):void
{
if( !e.target )
return;
trace( getQualifiedClassName( e.target.content ) );
/* if you get: flash.display::AVM1Movie
it means you are trying to load an AS1 or AS2 SWF
into AS3 SWF. They both need to be AS3 */
mc = e.target.content as MovieClip;
mc.gotoAndPlay( 2 );
// or mc.gotoAndPlay( 'yourLabel' );
}
long story short, I made image for it.
I am beginner in actionscripting, found out that only animating is not enough.
What I try to accomplish:
You can use a simple mask to achieve this. Here's a working example (using LEFT mouse button, though. I don't think RIGHT one would be suitable for this):
package examples
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class MaskTest extends Example
{
private var _toBeErased:Sprite;
private var _discoverable:Sprite;
private var _holesContainer:Sprite;
private var _mouseIsPressed:Boolean = false;
public function MaskTest()
{
}
// Call this method once this Class instance has been added to stage
public function init():void
{
// Create sprites
_toBeErased = new Sprite();
addChild( _toBeErased );
_discoverable = new Sprite();
addChild( _discoverable );
_holesContainer = new Sprite();
addChild( _holesContainer );
// Draw sprites
_toBeErased.graphics.beginFill( 0xFFFF00 );
_toBeErased.graphics.drawRect( 0, 0, 900, 600 );
_toBeErased.graphics.endFill();
_discoverable.graphics.beginFill( 0xFFAAAA );
_discoverable.graphics.drawRect( 0, 0, 900, 600 );
_discoverable.graphics.endFill();
// Set mask
_discoverable.mask = _holesContainer;
// Add mouse listeners
stage.addEventListener( MouseEvent.MOUSE_MOVE, onMouseMove );
stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown );
stage.addEventListener( MouseEvent.MOUSE_UP, onMouseUp );
}
// Mouse listeners callbacks...
private function onMouseDown( e:MouseEvent ):void{
_mouseIsPressed = true;
}
private function onMouseUp( e:MouseEvent ):void{
_mouseIsPressed = false;
}
private function onMouseMove( e:MouseEvent ):void
{
if( !_mouseIsPressed )
return;
// Get a random size for circle
var radius:Number = 5 + (Math.random()*10-5);
// Create new circle and paint it
var circle:Sprite = new Sprite();
circle.graphics.beginFill( 0x000000 );
circle.graphics.drawCircle( 0, 0, radius );
circle.graphics.endFill();
// Move it randomly, just a bit
circle.x = _holesContainer.mouseX + (Math.random()*20-10);
circle.y = _holesContainer.mouseY + (Math.random()*20-10);
_holesContainer.addChild( circle );
}
}
}
Check out http://f6design.com/journal/2009/05/24/erase-an-image-using-your-mouse-in-as3/
Basically, you have to make use of the erase Blend Mode: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BlendMode.html