Strange issues when using addChild and hitTest with AS3 - actionscript-3

I am having a couple of problems when adding a child in action script 3. I am currently building a Space Invaders game and I am writing the function that adds the asteroids to the stage.
My first problem is that the all previous asteroids are being added each time I try to add a new asteroid.
My second issue is when I add the hitTestOject function. It throws up an error and it doesn't do anything when the space ship hits the asteroid object.
Here is the error I receive with the hitTestObject:
TypeError: Error #1034: Type Coercion failed: cannot convert "ast_0"
to flash.display.DisplayObject. at
spaceranger_fla::MainTimeline/addAstroid() at
flash.utils::Timer/_timerDispatch() at flash.utils::Timer/tick()
And here is my code. I use a timer so each asteroid is added every 5000ms:
// Add astoid
var astTimer:Timer = new Timer(5000);
astTimer.addEventListener(TimerEvent.TIMER, addAstroid);
var i:Number = 0;
function addAstroid (e:TimerEvent):void{
var ast = new astroid();
ast.name = "ast_"+i;
ast.y = Math.random()*stage.stageHeight;
ast.x = 565;
addChild(ast);
trace(i);
if(ship.hitTestObject(ast.name)){
gotoAndStop("2");
}
i = i+1;
}
astTimer.start();
Some advice, recommendations and answers will be greatly appreciated :)
UPDATE
I sorted the looping error. Old asteroids no longer appear again! :D
Many Thanks,
Peter Stuart

Per your first problem, it does not appear i increments - it's always 0.
When you assign name, increment i:
ast.name = "ast_" + (i++).toString();
Basically, saying i = i + 1;
Next up, hit test against the instance itself, not an identity:
ship.hitTestObject(ast)
Not sure how your game play works, but it would seem what you really want are two handlers:
one to occasionally add a new asteroid
one that tests for collisions
Currently your addAsteroid() function adds a new asteroid and immediately tests if it collides with the ship upon creation. That asteroid will never be tested for collision again. If this is similar to a classic asteroids game, you may want to push each asteroid to an array, and add an event listener for ENTER_FRAME to test each asteroid for collision against the ship.

ship.hitTestObject(ast.name) is not going to work because ast.name is a String, not a DisplayObject.
Try this :
if(ship.hitTestObject(ast)){
gotoAndStop("2");
}

Related

How to keep timer running when i go to the other frame Actionscript 3.0

I am new to actionscript.
I want to know how to run timer class and keep running even when i go to other frame.
For example. I run timer in frame 2 and when i go to frame 1 timer keeps running, until i go back to frame 2 to stop the timer.
I appreciate the help.
UPDATE :
I try to make a stopwatch with these code :
var sec,min,hr:uint = 0;
sec_txt.text = min_txt.text = hr_txt.text = "00";
var timerStopWatch:Timer = new Timer(1000);
timerStopWatch.addEventListener(TimerEvent.TIMER, timerHandler);
function timerHandler(e:TimerEvent){
var sec:String = String(uint(timerStopWatch.currentCount%60));
var min:String = String(uint((timerStopWatch.currentCount/60)%60));
var hr:String = String(uint((timerStopWatch.currentCount/60)/60));
sec_txt.text = (uint(sec)< 10) ? "0" + sec:sec;
min_txt.text = (uint(min)< 10) ? "0" + min:min;
hr_txt.text = (uint(hr) < 10) ? "0" + hr:hr;
}
When i start the timer it work, but when i go to the second frame or another it stop and show a output error :
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Stopwatch_fla::MainTimeline/timerHandler()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
What i want is, when i start the Timer and go to the other frame it will still running(ticking) and when i go back to the Timer frame i could stop it.
First, if you're going to be re-visiting the frame where your posted code lives, you want to make sure that timer doesn't get re-created every time and cause a memory leak.
Change the following line
var timerStopWatch:Timer = new Timer(1000);
To these two lines:
var timerStopWatch:Timer;
if(!timerStopWatch) timerStopWatch = new Timer(1000);
This will ensure your timer is only created once. That event listener will keep the timer in memory, so if you're constantly creating new timers and adding a listener to them, they will all stay in memory and your application will get slower and slower.
Second, make sure you clean up after yourself.
When you want your timer to be gone, stop it, remove the event listener and null the reference:
timerStopWatch.stop();
timerStopWatch.removeEventListener(TimerEvent.TIMER, timerHandler);
timerStopWatch = null;
Third, if your going to have this object span multiple frames, anything that is referenced in the event handler needs to persist in those frames as well.
That means:
sec_txt
min_txt
hr_txt
All have to exist on any frame where this timer is running. Make sure on those frames that they have their instance names set properly.
OR, check if they exist prior to using them:
if(sec_txt) sec_txt.text = (uint(sec)< 10) ? "0" + sec:sec;
If you have this problem you are probably typing code in the frame itsel. Write a document class and create your timer in there, so no matter which frame, all properties are still there and keep running.

AS3 tween object not working with .hitTestObject()

I am having a major problem in my new browser app.
Okay so I made game where different cubes (squares) spawn at the top of the screen and I use the Tween class to make them go down the screen and then disappear.
However I want to detect a collision when a cube hits the player (that is also a flying cube).
I tried everything, truly everything but it does not seem to work. The problematic thing is that when I remove the "Tween" function it does detect collision with the hitTestObject method but when I add the "Tween" line collision won't be detected anymore.
It looks like this:
function enemiesTimer (e:TimerEvent):void
{
newEnemy = new Enemy1();
layer2.addChild(newEnemy);
newEnemy.x = Math.random() * 700;
newEnemy.y = 10;
if (enemiesThere == 0)
{
enemiesThere = true;
player.addEventListener(Event.ENTER_FRAME, collisionDetection)
}
var Tween1:Tween = new Tween(newEnemy, "y", null, newEnemy.y, newEnemy.y+distance, movingTime, true);
}
And the collision detection part:
private function collisionDetection (e:Event):void
{
if (player.hitTestObject(newEnemy))
{
trace("aaa");
}
}
I am desperate for some information/help on the topic, it's been bugging me for days.
Thanks for your time, I would be very happy if someone could help me out^^
First, make sure the "newEnemy" instance and the "player" instance are within the same container. If they are not, their coordinate systems might not match up and could be the source of your problem.
Otherwise, you need to keep a reference to each enemy instance you create. It looks like you are only checking against a single "newEnemy" variable which is being overwritten every time you create a new enemy. This might be why you can successfully detect collision between the player and the most recent "enemy" instance.
So... you need a list of the enemies, you can use an Array for that.
private var enemyList:Array = [];
Every time you create an enemy, push it to the Array.
enemyList.push(newEnemy);
In your "collisionDetection" function, you need to loop through all of the enemies and check if the player is touching any of them.
for(var i:int = 0; i < enemyList.length; i++)
{
var enemy = enemies[i];
if (player.hitTestObject(enemy))
{
trace("Collision Detected!");
enemy.parent.removeChild(enemy); // remove the enemy from the stage
enemies.splice(i, 1); // remove the enemy from the list
}
}
I'd suggest that you move to TweenMax, it just might solve your problem, and in my experience it's much better in every possible way.
Scroll down the following page to see a few variations of this library, I myself use TweenNano, they're completely free of charge:
https://greensock.com/gsap-as
I think some plugins cost money, but I doubt you'll ever need them.

AS3 gotoAndStop(2); causes a 1009 error second time the frame runs

Disclaimer: I'm really new/incredibly bad at AS3 so it's probably something really stupid that should never happen
Okay so, the first time my main menu frame runs, it runs fine and sends me to the gameplay frame when I press the button. After the gameplay is complete, it returns to the menu frame, and runs fine until I press the same button from before, which calls this error: .
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main_fla::MainTimeline/frame2()[Main_fla.MainTimeline::frame2:6]
at flash.display::MovieClip/gotoAndPlay()
at Main_fla::MainTimeline/easyPress()[Main_fla.MainTimeline::frame3:83]
at Main_fla::MainTimeline/mClickE()[Main_fla.MainTimeline::frame3:45]
My code for the button is as follows:
buttEasy.addEventListener(MouseEvent.CLICK, mClickE);
buttHard.addEventListener(MouseEvent.CLICK, mClickH);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mMove);
function mClickE(e:MouseEvent){
easyPress();
trace("easyP");
menuUsed = true;
}
function easyPress(){
trace("Waited for press and release");
sTime = 0;
sTempo = (6) ;
sBall = 0;
ballSpeed = 7;
gameIsOver = false;
menuUsed = true;
lvlArray0= new Array(1,0,0,2,0,0,1,0,0,3,0,0,1,0,0,2,0,0,1,0,0,3,0,01,0,0,2,0,0,1);
init2 = false;
buttEasy.removeEventListener(MouseEvent.CLICK, mClickE);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mMove);
gotoAndPlay(2);
}
I honestly have no idea why this is happening. I'm using mouse events instead of button press events and whatnot because my movieclips started disappearing and flashing and other unexplainable stuff...
yeah...
I just registered, so I can't post this as a comment.
Anyway the error occurs on frame 2, not in the script you've provided (which is on frame 3).
You can see this in the error message:
"at Main_fla::MainTimeline/frame2()[Main_fla.MainTimeline::frame2:6]"
-> frame 2 line 6.
There you're accessing something that doesn't exist anymore. (-> something that is now null)
Maybe an object on the stage that has been removed. (But there are a lot of other possibilities, so don't stick with that solution)
Post the script you have on frame 3 for further help.
The flashing and other unexplainable stuff happens, because of this error. It aborts the script and runs the flash normally. (this means that for example the stop(); method won't be executed -> the player runs through all your frames -> the objects on the stage appear to be flashing)
You're probably just addressing the "stage" before the reference is given. Start your code with:
addEventListener(Event.ADDED_TO_STAGE, init);
and a handler for this listener
private function init(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// write your code after this
}
If you're framescripting (writing AS3 code in a frame) It's not really your problem.
But as the problem states - you're calling some objects property or method witch is null. Your debugger will be able to point to the null object that you try to call on frame 2.

How to fix AS3 TypeError: Error #1009: Cannot access a property or method of a null object reference?

I am getting this error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Skool_fla::MainTimeline/frame1()[Skool_fla.MainTimeline::frame1:10]
at flash.display::MovieClip/gotoAndStop()
at Skool_fla::MainTimeline/goback()[Skool_fla.MainTimeline::frame2:22]
What is causing this error and how do I fix it?
This is my code for both the frames:
Frame 1: This is the main menu screen where you can access the credit section
import flash.events.MouseEvent;
//setting up the variables
//events
//stop the timeline
stop();
//the play button
play_btn.addEventListener(MouseEvent.CLICK, playani);
function playani(e:MouseEvent)
{
//asking it to progress to the load menu
gotoAndStop(3);
}
//the credits button
credit_btn.addEventListener(MouseEvent.CLICK, creditslide);
function creditslide(e:MouseEvent)
{
//asking it to go the credits frame
gotoAndStop(2);
}
Frame 2: This is where the credits appear
//
//
//all the imports
//events
var credit:credits_bck = new credits_bck ();
var credits_name: credit_nm = new credit_nm ();
var back_butn: back_button = new back_button ();
addChild (credit);
addChild (credits_name);
addChild (back_butn);
back_butn.addEventListener(MouseEvent.CLICK,goback);
function goback(G:MouseEvent)
{
removeChild (credit);
removeChild (credits_name);
gotoAndStop(1);
}
Either play_btn or back_butn is null. Your error message's line numbers don't correspond to your code so it's hard to say. But the gist is you're trying to access a property of something that isn't anything. Check to make sure you're initializing your variables/references properly.
Maybe your problem is Flash bug too.
In my FLA there was a layer with one empty keyframe. If I puted a vector graphics on it, the error was gone. If there was one or multiple MovieClips and there was no vector graphic - the error was there again.
Then I made a new layer and copy pasted all the objects from damaged layer to new and deleted the damaged layer. It solved the problem.
NOTE: Don't copy the keyframes. Only copy the contents.
Now my project is much more complicated and sadly the error came back again.
Test movie frequently and if the error comes back, check the last keyframes and layers you created.

AS3 AI hitTestObject with itself?

Im've created a timer that starts every 1 second.
This is the code what's happening every 1 second.
var Random_Value_X:Number = Math.ceil(Math.random() * 1500);
var Random_Value_Y:Number = Math.ceil(Math.random() * 2000);
var enemy:MovieClip = new AI(stage);
addChild(hero);
enemy.x = Random_Value_X;
enemy.y = Random_Value_Y;
Ok. Then I got the class called AI where I've made it so the AI follows my player. The thing is, I need to make a hitTest that testes if an AI hitting another AI? Is there a way I can give every new AI a ID? Like the first gets called "AI1" and second AI2" and then I can make a code that says like If(AT1.hitTestObject(AT2 || AT3))
Hope you understand what I trying to explain! :)
You should just put them all in an array. Then you can loop through the array and do the hit testing for each one. Depending on how many you have, you might need to split them up into groups so you don't have to do so many checks each frame.
I'm pretty sure you can't just use logical or in the hitTestObject method like that.
Considering that you are on root and keyword "this" referring root. If you make instance of class "enemy" then all objects of it will have type "enemy".
import flash.events.Event;
// for every enemy you create, addlistener to it
// it will force to check itself with others
enemy.addEventListener(Event.ENTER_FRAME,checkHit);
// this function will be available to all enemies
// will inform itself that it is hiting enemy instance
function checkHit(e:Event){
// for e.g. object is moving in x direction
// to keep it simple so you can run it in new file
// with two object one is called enemy and other enemy1
// in your case its changing position
e.target.x += 1;
// loop with all children, break when hit someone
for(var i:uint=0;i<this.numChildren;i++){
// in current situation e.target is also a child of root
// therefore avoid checking it
if(e.target==this.getChildAt(i)) continue;//trace("Its me");
// if hit
// currently testing hit with all objects on stage
// you can change it to check specific type
if(e.target.hitTestObject(this.getChildAt(i))){
trace("I got hit by: "+this.getChildAt(i).toString());
break;
}
}
}