Collision detection: TypeError: Error #1009: Cannot access a property or method of a null object reference - actionscript-3

I'm trying to make a game but I'm stuck at this point:
in my game you are supposed to evade balls who come in from the right and disappear left. When you hit a ball you'll be redirected to another screen.
Here's the error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Evader/cleanUpObjects()
at Evader/update()
This is my code:
Evader.as (lines with the hyphens are the erroneous lines):
public class Evader extends MovieClip
{
public var penguin:Penguin;
private var objects:Array;
public function Evader()
{
initGame();
Mouse.hide();
objects = new Array();
addEventListener( Event.ENTER_FRAME, update );
//addEventListener( Event.ENTER_FRAME, hitObject );
}
private function initGame():void
{
penguin = new Penguin();
addChild( penguin );
}
private function update( event:Event ):void
{
if( Math.random() < 0.04 )
{
spawnObject();
}
//--------------------->cleanUpObjects();
}
private function cleanUpObjects():void
{
var currentObject:Object1;
for( var i:int = objects.length-1; i >= 0; i-- )
{
currentObject = objects[ i ];
//----------------------------->if( currentObject.x > stage.stageWidth )
{
removeChild( currentObject );
objects.splice( i, 1 );
}
}
}
private function spawnObject():void
{
var object1:Object1 = new Object1(penguin);
addChild( object1 );
objects.push( object1 );
}
/**
*private function hitObject(event:Event)
*{
* if (penguin.hitTestObject(object1))
* {
* Mouse.show();
* trace("geraakt!");
* removeEventListener( Event.ADDED_TO_STAGE, init );
* removeEventListener( Event.ENTER_FRAME, update );
* removeEventListener( Event.ENTER_FRAME, hitObject );
* Project.instance.switchScreen( "vierde" );
* }
}*/
}
}
Object1.as:
public class Object1 extends MovieClip
{
private var speed:Number;
private var penguin;
public function Object1(aPenguin: Penguin)
{
penguin = aPenguin;
addEventListener( Event.ADDED_TO_STAGE, init );
addEventListener( Event.ENTER_FRAME, hitObject );
}
private function init( event:Event ):void
{
removeEventListener( Event.ADDED_TO_STAGE, init );
addEventListener( Event.REMOVED_FROM_STAGE, unInit );
addEventListener( Event.ENTER_FRAME, move );
speed = -(1 + Math.random() * 2);
x = stage.stageWidth;
y = Math.random() * stage.stageHeight;
}
private function unInit( event:Event ):void
{
removeEventListener( Event.REMOVED_FROM_STAGE, unInit );
removeEventListener( Event.ENTER_FRAME, move );
}
private function move( event:Event ):void
{
this.x += speed;
}
private function hitObject(event:Event)
{
if (penguin.hitTestObject(this))
{
Mouse.show();
trace("geraakt!");
removeEventListener( Event.ADDED_TO_STAGE, init );
removeEventListener( Event.ENTER_FRAME, hitObject );
Project.instance.switchScreen( "vierde" );
}
}
}
}
The thing is, I need to have the hitTestObject function work for all the balls, so that it checks for collisions with all the appearing balls. Penguin is my character who is supposed to evade the balls.
If I comment the hitObject code in Object1.as and uncomment it at Evader.as, I don't know what to put in if (penguin.hitTestObject(???))
Using Objects doesn't work because it will give error #1067: Implicit coercion of a value of type Array to an unrelated type Function.
Could someone help me in getting it work?
Thanks in advance!

Evader is a DisplayObject, specifically type MovielCip. Each display object has a stage field, but the stage field is null until the display object (Evader) gets added to the stage display list (using addChild, eg. stage.addChild( myEvaderInstance) ).
So just from looking at the code you provided, it's possible you haven't added Evader to the display list, therefore its stage is null in the line:
if( currentObject.x > stage.stageWidth )
In which case you wouldn't want to add the event frame listener in its constructor. You'd want to add that listener after it's been added to the stage. So, here's how you can do that. In the Evador constructor:
public function Evader()
{
initGame();
Mouse.hide();
objects = new Array();
//don't update yet, we haven't been added to the display list
//addEventListener( Event.ENTER_FRAME, update );
addEventListener( Event.ADDED_TO_STAGE, onAddedToStage );
}
private function onAddedToStage( e:Event ):void {
removeEventListener( Event.ADDED_TO_STAGE, onAddedToStage );
//add the update listener!
addEventListener( Event.ENTER_FRAME, update );
}
That should do it. We wait till Evader has been added to the display list, then add the event frame listener.

Related

I keep getting 'ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller' inside timer event

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);
}
}

click tap or touch begin and drag an object on the same time as3

i am creating a buttons bar that can be dragged however when i lift my finger after dragging the buttons the button is getting pushed, i would like to cancel the click/tap when dragging the buttons any suggestions?
Thank you
You'll either need to remove/add your listeners as necessary, or have a property on your buttons. Something like:
public class DragButton extends Sprite
{
public var isDragging:Boolean = false;
public function DragButton()
{
// add our listeners
this.addEventListener( MouseEvent.MOUSE_DOWN, this._onMouseDown );
this.addEventListener( MouseEvent.MOUSE_UP, this._onMouseUp );
this.addEventListener( MouseEvent.CLICK, this._onMouseClick );
}
private function _onMouseDown( e:MouseEvent ):void
{
// add our move listener for dragging
this.addEventListener( MouseEvent.MOUSE_MOVE, this._onMouseMove );
}
private function _onMouseUp( e:MouseEvent ):void
{
// remove our dragging listener
this.removeEventListener( MouseEvent.MOUSE_MOVE, this._onMouseMove );
}
private function _onMouseMove( e:MouseEvent ):void
{
// drag us
this.x = e.stageX;
this.y = e.stageY;
this.isDragging = true;
}
private function _onMouseClick( e:MouseEvent ):void
{
// if we're dragging, ignore
if( this.isDragging )
{
this.isDragging = false;
return;
}
// do our click stuff
}
}

Actionscript 3, flash: Erasing area dynamically?

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

MOUSE_DOWN trigger every frame, ActionScript 3

as I am new to as3, I want to implement a MachineGun, that fires while has ammo, and the trigger is pulled, In my case, the MouseEvent.MOUSE_DOWN.
The problem is that this event fires only once.
The closest I get is to this is MouseEvent.MOUSE_MOVE, but it fails my purpose when the mouse position is sustained
EDIT:
I need the updated mouse cursor every frame
When your MouseEvent.MOUSE_DOWN event handler you can create an event listener that listens for the Event.ENTER_FRAME event to be dispatched. Using the Event.ENTER_FRAME event handler you can repeatedly call a method that handles shooting the bullet. The following is an example I modeled after an example at http://www.benoitfreslon.com/actionscript-throw-bullets-to-mouse-direction:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width="500", height="500", frameRate="24", backgroundColor="0xFFFFFF")]
public class Main extends Sprite
{
private var _gun:Gun;
private var _interval:int;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_gun = new Gun();
_gun.x = stage.stageWidth / 2 - _gun.width / 2;
_gun.y = stage.stageHeight / 2 - _gun.height / 2;
addChild(_gun);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
}// end function
private function onStageMouseDown(e:MouseEvent):void
{
stage.addEventListener(Event.ENTER_FRAME, onStageEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
}// end function
private function onStageEnterFrame(e:Event):void
{
shootBullet();
}// end function
private function shootBullet():void
{
if (_interval > 5)
{
var bullet:Bullet = new Bullet();
bullet.addEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
bullet.x = _gun.x;
bullet.y = _gun.y;
bullet.angleRadian = Math.atan2(stage.mouseY - _gun.y, stage.mouseX - _gun.x);
bullet.addEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
addChild(bullet);
_interval = 0; // reset
}// end if
_interval++;
}// end function
private function onBulletEnterFrame(e:Event):void
{
var bullet:Bullet = Bullet(e.target);
bullet.x += Math.cos(bullet.angleRadian) * bullet.SPEED;
bullet.y += Math.sin(bullet.angleRadian) * bullet.SPEED;
if ( bullet.x < 0 || bullet.x > 500 || bullet.y < 0 || bullet.y > 500)
{
removeChild(bullet);
bullet.removeEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
}// end if
}// end function
private function onStageMouseUp(e:MouseEvent):void
{
stage.removeEventListener(Event.ENTER_FRAME, onStageEnterFrame);
stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
_interval = 0;
}// end function
}// end class
}// end package
import flash.display.Sprite;
internal class Gun extends Sprite
{
public function Gun()
{
graphics.beginFill(0x000000);
graphics.drawCircle(0, 0, 10);
graphics.endFill();
}// end function
}// end class
internal class Bullet extends Sprite
{
public var angleRadian:Number;
public const SPEED:Number = 10;
public function Bullet()
{
graphics.lineStyle(1, 0x000000);
graphics.drawCircle(0, 0, 10);
graphics.endFill();
}// end function
}// end class
The point of interest is in the onStageEnterFrame() method. There's an if statement that checks whether the _interval property's value is greater than 5, if so, a new bullet is created and shot otherwise the _interval property's value is incremented. The purpose of the _interval property is to space out the bullets being shot.
[UPDATE]
Here is an image of the example flash application running:
The mouse button is being held down in the top right corner hence the bullets being shot in that direction.
On receiving a MouseEvent.MOUSE_DOWN event, run a while loop making the machine gun fire. The loop breaks on receiving a MouseEvent.MOUSE_UP event. Something like this
private function handleMouseDown( event:Event ):void
{
this.addEventListener( MouseEvent.MOUSE_UP , handleMouseUp );
startFiring();
}
private function handleMouseUp( event:Event ):void
{
this.removeEventListener( MouseEvent.MOUSE_UP , handleMouseUp );
this.addEventListener( MouseEvent.MOUSE_DOWN , handleMouseDown);
stopFiring();
}
EDIT: For clarification, the stop and start firing functions are functions that run a loop to keep the machine gun firing animation going however that may be.
add firing action to ENTER_FRAME event when mouse is pressed and remove when mouse is up
this.addEventListener( MouseEvent.MOUSE_DOWN, this.handler_down );
this.addEventListener( MouseEvent.MOUSE_UP, this.handler_up );
private function handler_down(event:Event):void {
super.addEventListener( Event.ENTER_FRAME, this.handler_frame );
}
private function handler_up(event:Event):void {
super.removeEventListener( Event.ENTER_FRAME, this.handler_frame );
}
private function handler_frame(event:Event):void {
this.fire();
}
I have to do this regularly, and instead of using an enter_frame listener, I opt for a Timer() and TimerEvent.Timer listener. That way I have more control over how often the repeat is fired without accounting for frame rate and what not.
private var fireRepeat:Timer;
private function triggerDown(e:MouseEvent):void {
if (!this.fireRepeat) { // create the repeater
this.fireRepeat = new Timer(500, 0);
this.fireRepeat.addEventListener(TimerEvent.TIMER, this.fire);
}
fire(); // fire the first bullet
this.fireRepeat.reset(); // reset the repeater
this.fireRepeat.start(); // start the repeater
}
private function triggerUp(e:MouseEvent):void {
if (this.fireRepeat) { this.fireRepeat.stop(); }
}
public function fire(e:* = null):void {
trace('fire!');
}

Convert AS2 por AS3...please

oranja.onPress = function(){
this.startDrag(true);
}
oranja.onRelease = function(){
this.stopDrag();
if(this.hitTest(this._parent.trash)){
trace("trash");
this.unloadMovie();
} else {
trace("no trash");
}
}
I think you're looking for an AS3 version of this? Something like this should work:
oranja.addEventListener( MouseEvent.MOUSE_DOWN, this._onPress );
oranja.addEventListener( MouseEvent.MOUSE_UP, this._onRelease );
// called when we mouse down on the oranja clip
private function _onPress( e:MouseEvent ):void
{
oranja.startDrag( true )
}
// called when we mouse up on the oranja clip
private function _onRelease( e:MouseEvent ):void
{
oranja.stopDrag();
if( oranja.hitTest( oranja.parent.trash ) )
{
trace( "trash" );
// remove the event listeners
oranja.removeEventListener( MouseEvent.MOUSE_DOWN, this._onPress );
oranja.removeEventListener( MouseEvent.MOUSE_UP, this._onRelease );
// remove the oranja clip
oranja.parent.removeChild( oranja );
oranja = null;
}
else
trace( "not trash" );
}
You should probably replace the oranja calls in _onPress() and _onRelease() with e.target or e.currentTarget