Creating Multiple Levels AS3 - actionscript-3

Hey Guys so I'm having a little trouble creating Multiple levels. I'm not so sure if im creating them the right way but i have a player and goal_1, goal_2, etc.. Basically when the player hitTestObject the goal_1 i want it to go to a new function called level_2 then level_3 after that hitTest. so Level_1 works just fine the hitTest works and it initializes level_2 but when i try to hitTest the player and goal_2 or even goal_1 again it just goes through it and doesnt do anything.
I understand now that level_2 isnt being called every frame like level_1 since its not part of the Enter_Frame listener. But i cant figure out how to have multiple Enter Frame events and not have them run simultaneously. If thats even the right way to create multiple levels.
Can you see what i could do in order to make it work?
private function gameLoop(e:Event):void
{
playerShoot();
playerControl();
playerStageBoundaries();
checkEndGameCondition();
checkPlayerOffScreen();
level_1();
}
private function level_1():void
{
if(player.hitTestObject(mGoal_1))
{
trace("Goal_1 Collision");
//Remove button for constant movement
btnShootPlayer = false;
mGoal_1.destroyGoal_1();
player.destroyPlayer();
//Update High Score text
nScore += 10;
updateHighScore();
stage.removeEventListener(Event.ENTER_FRAME, gameLoop);
//Update level
nLevel++;
updatePlayerLevel();
level_2();
}else
{
checkEndGameCondition();
}
}
public function level_2():void
{
stage.addEventListener(Event.ENTER_FRAME, gameLoop);
TweenMax.to(mGoal_1, 1, {y:40, repeat:-1, yoyo:true, ease:Power0.easeInOut});
trace("Level_2 Initiated");
//Keep Text Scores initiated
updateHighScore();
updatePlayerLives();
player = new mPlayer();
stage.addChild(player);
player.x = (stage.stageWidth / 2) - 280;
player.y = (stage.stageHeight / 2);
mGoal_1 = new goal_1();
stage.addChild(mGoal_1);
mGoal_1.x = (stage.stageWidth / 2) + 300;
mGoal_1.y = (stage.stageHeight) - 35;
if (player.hitTestObject(mGoal_1))
{
trace("Level 2 Hit test works!");
nScore += 10;
updateHighScore();
}
}

I didn't read too carefully all the code, but I guess you can use a function variable. Declare it on class level (outside any function):
var _doFunction:Function;
than, instead calling level1 function, pass the reference and call the _doFunction:
_doFunction = level1;
_doFunction();//or _doFunction.call(); - see Adobes documentation
when you are done with the level1, than pass the next level:
_doFunction = level2;
P.S. don't forget to accept the answer if it helped to solve your problem.

Related

Object Undefined but it seems to be Defined actionscript

First I am still new to coding so take it easy on me. Bit of back tracking before I show the code. I got a book on how to make games with ActionScript 3, only thing is it mainly works under the assumption your working with Photoshop & Flash Builder together rather than adobe animate/flash. So it has you do things like embed images, and I'm not sure how to change the code to define the images, which is exactly the problem. However at the same time, the stage is coming up as undefined access! I really, I mean how can the stage be undefined... Well any way, Heres an example of one of the Undefined Properties:
///
class BetterScrolling extends Sprite
var ForegroundImage: Class;
var foregroundImage: DisplayObject = ForegroundImage();
var foreground = ForegroundImage;
///
Theres some code in-between.
///
function BetterScrolling(){
foreground.x = -((foreground.width - stage.width) / 2);
foreground.y = -((foreground.height - stage.height) / 2);
}
///
The point of this code is to create a scrolling Background. However I'm kinda complicating it because I have an X and an Y variable, yet I also have a slowed background in addition to my foreground. I will now link to the complete code as is currently, http://pastebin.com/WHg9DGsB Every change in that code I made with a reason in mind, even if it is a stupid one... so please don't be distracted by the other errors that I'm sure are in there... for now just the defining of my images.
There a number of issues that will keep your code from compiling.
Stage is not available when your class loads. Any code that is not inside a function will run when the application is initialized (before anything is even seen on the screen). Your error is because of these lines:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
Those lines are floating in your class declaration when stage does not yet exist.
What you want to do is move that code (and any code that isn't a variable or function definition) into a function. If you want it to run immediately, put it in your constructor (the function named the same as your class). The stage however is also not always available yet in your constructor, so to be safe, you should do the following:
function BetterScrolling() {
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, stageReady);
}else{
stageReady();
}
}
function stageReady(e:Event = null):void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//any other code that needs the stage and should run as soon as possible
}
You have a bunch of brackets and code that don't seem to belong anywhere. Lines 45 - 71 will not compile properly. Most likely, you want that code in your constructor/stage ready method as well, so adding that in, you would have something like this:
function BetterScrolling() {
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, stageReady);
}else{
stageReady();
}
}
function stageReady(e:Event = null):void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
foreground.x = -((foreground.width - stage.width) / 2);
foreground.y = -((foreground.height - stage.height) / 2);
background.x = -((background.width - stage.width) / 2);
background.y = -((background.height - stage.height) / 2);
cloud.x = -((cloud.width - stage.width) / 2);
cloud.y = -((cloud.height - stage.height) / 2);
character.x = 370
character.y = 320
rightInnerBoundary = (stage.stageWidth / 2) + (stage.stageWidth / 4)
leftInnerBoundary = (stage.stageWidth / 2) + (stage.stageWidth / 4)
topInnerBoundary = (stage.stageHeight / 2) + (stage.stageHeight / 4)
bottomInnerBoundary = (stage.stageHeight / 2) + (stage.stageHeight / 4)
}
You have vars that are blank classes, then you try to instantiate them
var BackgroundImage: Class;
var backgroundImage: DisplayObject = BackgroundImage();
This will cause a runtime error because BackgroundImage is null/undefined. Most likely, you want to export a library object in FlashPro as a class? To do that, right/alt click the object in question in the library, and go to it's properties. Check off 'export for actionscript' and give it a class name. In this case, call it BackgroundImage. Then you replace the above code with:
var backgroundImage:BackgroundImage = new BackgroundImage();
As an aside, it safer to only declare you class vars that reference other objects/classes and instantiate them in the constructor. To change it like that, change the above line to this:
var backgroundImage:BackgroundImage;
Then in your constructor, do:
backgroundImage = new BackgroundImage();
First, DisplayObject.stage property is defined only when the DisplayObject in question is attached to display list. As a general policy, never try to access stage in the constructors. You need to subscribe a certain event that will tell you when stage is really available.
public function IWannaStage()
{
// WRONG
x = stage.stageWidth >> 1;
y = stage.stageHeight >> 1;
// RIGHT
if (stage) onStage();
else addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
// Stage is really available from this point on.
x = stage.stageWidth >> 1;
y = stage.stageHeight >> 1;
}
Second, I think you're trying to create instances incorrectly. If ForegroundImage is a class, then:
A = ForegroundImage; // Wrong, you assign the reference to the class.
B = ForegroundImage(); // Wrong, this actually is type casting.
C = new ForegroundImage(); // Correct way to create a new instance of a class.
D = new ForegroundImage; // If constructor does not need any arguments you can omit brackets.

How to stop a movieClip from playing in Flash CS6 AS3 (with Box2D)

I've spent 14 hours on this problem. This is a basic collision checker that sets a MovieClip animation to play when a collision occurs. The clip is
currentBallObject.clip.
It works. The clips plays. But it repeats over and over.
private function checkCollisions():void
{
var i = balls.length;
while (i--)
{
var currentBallObject = balls[i];
if (currentBallObject.contact)
{
//condition hits ground
if (currentBallObject.ground)
{
currentBallObject.body.SetPosition(new b2Vec2(currentBallObject.startX / PIXELS_TO_METRE, currentBallObject.startY / PIXELS_TO_METRE));
currentBallObject.body.SetLinearVelocity(new b2Vec2(0, 0));
currentBallObject.body.SetAngularVelocity(0);
//currentBallObject.texture.pop();
}
else // it hit player
{
// assign clip texture to current position
currentBallObject.clip.x = currentBallObject.body.GetPosition().x * PIXELS_TO_METRE;
currentBallObject.clip.y = currentBallObject.body.GetPosition().y * PIXELS_TO_METRE;
// whisk old object away
currentBallObject.body.SetPosition(new b2Vec2(currentBallObject.startX / PIXELS_TO_METRE, currentBallObject.startY / PIXELS_TO_METRE));
currentBallObject.body.SetLinearVelocity(new b2Vec2(0, 0));
currentBallObject.body.SetAngularVelocity(0);
currentBallObject.contact = false;
}
}
}
}
I added this code to delete the MovieClip or somehow get rid of it after it has played through once. (42 frames). I also tried to add a frameListener and at least a dozen other suggestions. When I add
stop()
The animation doesn't play. It just loads the last frame. The code I have now is:
private function updateClips():void
{
var i = balls.length;
while (i--)
{
var currentBallObject = balls[i];
if(currentBallObject.clip)
{
var frame:int = currentBallObject.clip.currentFrame;
//trace(currentBallObject.clip.currentFrame);
if(frame == 42)
{
currentBallObject.clip._visible = false;
currentBallObject.clip.removeMovieClip();
currentBallObject.clip.enabled = -1;
}
}
}
}
I've tried counting the frames, putting it a run-once function, a frame exit listener, I am out of ideas. I just want to make a MovieClip run one time through. I also tried putting stop() in the timeline and then the animation didn't play. It just loaded the last frame.
Right now the collisions work but the animations stay on the screen forever, looping forever.
Edit: I got the code by Patrick to run without errors.
I added the event listener with the others like this:
_input = new Input(stage);
...
addEventListener(Event.ENTER_FRAME, oEF);
addEventListener(Event.ENTER_FRAME, update);
time_count.addEventListener(TimerEvent.TIMER, on_time);
time_count.start();
}
And then created a function:
private function oEF(e:Event):void{
var i = balls.length;
while (i--)
{
var currentBallObject = balls[i];
if (currentBallObject.clip.currentFrame >= currentBallObject.clip.totalFrames)
{
currentBallObject.clip.stop();
currentBallObject.clip.removeEventListener(Event.ENTER_FRAME, oEF);
if (currentBallObject.clip.parent) currentBallObject.clip.parent.removeChild(currentBallObject.clip);
}
}
}
But I still get the same problem as any other result. The MovieClip disappears on contact without the animation happening.
Through debugging I've learned more. The value of currentFrame starts off going 1-40 then stays at 40 for the rest of the execution.
So the MovieClip is always on the last frame for every object.
if clip is a MovieClip then you can use clip.totalFrames in an enterframe listener.
function oEF(e:Event):void{
if (this.currentFrame >= this.totalFrames){
this.stop();
this.removeEventListener(Event.ENTER_FRAME, oEF);
if (this.parent) this.parent.removeChild(this);
}
}
this.addEventListener(Event.ENTER_FRAME, oEF);
I figured it out.
if (currentBallObject.clip.currentFrame == currentBallObject.clip.totalFrames)
{
trace("Frame before kill: ", currentBallObject.clip.currentFrame);
currentBallObject.clip.x = 0;
currentBallObject.clip.y = 0;
}
The above block goes right after
var currentBallObject = balls[i];
It checks if the movieClip is on the last frame and then gets rid of the clip by setting clip.x & clip.y to 0. I could find no other way to stop the movie in this particular case.

Problems with an object appearing on a frame I don't want it to appear on AS3

I am a total noob at AS3, roughly 1 year experience so please be lenient with me :)
I currently am making an endless runner game and I'm making the obstacles spawn using this method
var therespawn:RespawnObject;
var thecone:trafficcone;
var started:Boolean = false;
var dx:Number = 10;
var dy:Number = 10;
stage.addEventListener(Event.ENTER_FRAME, startGame);
addEventListener(Event.ENTER_FRAME, collision);
addEventListener(Event.ENTER_FRAME, coneCollision);
function startGame(evt:Event):void {
if (started == false) {
spawnHazard();
}
}
function spawnHazard() {
started = true;
therespawn = new RespawnObject();
addChild(therespawn);
thecone = new trafficcone();
addChild(thecone);
therespawn.x = -50;
therespawn.y = 310;
thecone.x = 600;
thecone.y = 310;
}
function collision(evt:Event):void {
thecone.x -= 15;
if(thecone.hitTestObject(therespawn)) {
thecone.x = 600;
}
}
Now the only way to finish the game or end it is to get hit by an obstacle which ive shown down below:
function coneCollision(evt:Event):void {
if(MainChar.hitTestObject(thecone)) {
gotoAndStop("frameFive");
}
}
Everytime the highscore frame appears the cone is still spawning and despawning, why is that?
I haven't declared them as global?
Any help appreciated, thanks!
You can fix your problem by setting started to false:
function coneCollision(evt:Event):void {
if(MainChar.hitTestObject(thecone)) {
started = false;
gotoAndStop("frameFive");
}
}
The flash timeline really only has to with the way MovieClips are visually displayed as children of the stage. Removing an object from the timeline doesn't just suddenly nullify all the code associated with that object. In other words, your ENTER_FRAME method still runs in the background even if the object is no longer a child of the Stage, regardless of the frame number for the MovieClip. If you're serious about coding you might consider investigating in Classes and Object Oriented AS3. Classes are much nicer to work with than the Flash timeline.

I got an Error #1009 saying I Cannot access a property or method of a null object reference. Now what?

So I got that error when trying to run my game. It's a simple little game that revolves around picking up orbiting jerry cans whilst trying to avoid orbiting enemies. So I hit Ctrl+Shft+Enter and found the problem was at line 26 (if (this.y +...) in my Ship Class.
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Ship extends Sprite
{
public function Ship(_x:int,_y:int)
{
this.x = _x;
this.y = _y;
//adds event listener that allows the player to move
addEventListener(Event.ENTER_FRAME, player_move);
}
public function player_move(e:Event)
{
//check if at left or right side of stage
if (this.y - this.height / 2 <= 0)
{
this.y = 50;
}
if (this.y + this.height / 2 >= stage.height - this.height)
{
this.y = 370;
}
if (this.x - this.width / 2 <= 0)
{
this.x = 50;
}
if (this.x + this.width / 2 >= stage.width - this.width)
{
this.x = 500;
}
}
public function left():void
{
//the speed in which the player will move left
this.x -= 10;
}
public function right():void
{
//the speed in which the player will move right
this.x += 10;
}
public function up():void
{
//the speed in which the player will move right
this.y -= 10;
}
public function down():void
{
//the speed in which the player will move right
this.y += 10;
}
}
}
Now what do I do? How do I fix this? I can't find the answer anywhere. I know it has something to do with my Main class as in it, I have stated that if the Player his the enemy, his ship is placed back at his original co-ords.
Any help would be greatly appreciated. Thanks.
Your null object is the stage reference. Every DisplayObject has a reference to the stage, however, this is null until the object is actually on the stage.
The stage is the main container of your application. Everything that is visual in your application will be on the stage in some way. Your main document class will be on the stage, all timeline objects, etc.
Your object is counted as being on stage even if its added to a different container, just as long as that container is on the stage in some way. So to put it in the most basic terms, if the object is somewhere where the user should be able to see it, stage will not be null.
To work around this, you're going to have to add your ENTER_FRAME event listener after your object has been added to the stage. Luckily, you can listen for an event that is fired when this happens.
In the constructor:
addEventListener(Event.ADDED_TO_STAGE, init);
Then add your handler:
private function init(evt:Event){
addEventListener(Event.ENTER_FRAME, player_move);
}
Remember, stage will be null until an object is added to the stage, which is the event we're listening for now. Then, just add your ship to the main game or whichever container it's going in, container.addChild(ship), and if that container is a part of the stage, you should be good to go.

Why are my array movie clips getting harder to click when they get faster?

I am making a game where insects come down from the top of the screen, and the user must kill them. The insects are in an array. Each time the user kills them, the score goes up..after a while the insects get faster and faster. When they get faster, some of them don't get killed when you click them. You have to click multiple times for them to die. I want them to get killed in one click, but this isn't working when they get faster!
function makeEnemies():void
{
var chance:Number = Math.floor(Math.random() * 150);
if (chance <= + level)
{
//Make sure a Library item linkage is set to Enemy...
tempEnemy = new Enemy();
//Math.random(); gets a random number from 0.0-1.0
tempEnemy.x = Math.round(Math.random() * 1000);
addChild(tempEnemy);
enemies.push(tempEnemy);
tempEnemy.speed = enemyBaseSpeed + ((level - 1) * speedLevelInc);
}
}
function moveEnemies():void
{
var tempEnemy:MovieClip;
for (var i:int =enemies.length-1; i>=0; i--)
{
tempEnemy=enemies[i];
if (tempEnemy.dead)
{
score++;
score++;
roachLevel.score_txt.text = String(score);
enemies.splice(i,1);
}
else // Enemy is still alive and moving across the screen
{
//rotate the enemy between 10-5 degrees
tempEnemy.rotation += (Math.round(Math.random()*.4));
//Find the rotation and move the x position that direction
tempEnemy.x -= (Math.sin((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
tempEnemy.y += (Math.cos((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
if (tempEnemy.x < 10)
{
tempEnemy.x = 11;
}
if (tempEnemy.x > stage.stageWidth - offset)
{
tempEnemy.x = stage.stageWidth - offset;
}
if (tempEnemy.y > stage.stageHeight)
{
removeEnemy(i);
lives--;
roachLevel.lives_txt.text = String(lives);
}
}
}
}
function removeEnemy(id:int)
{
removeChild(enemies[id]);
enemies.splice(id,1);
}
There is also code inside the insect.
import flash.events.MouseEvent;
import flash.display.MovieClip;
import fl.motion.Animator;
import flash.events.*;
play();
var MainTimeLine = MovieClip(root);
var mysound:squish = new squish();
this.addEventListener(MouseEvent.CLICK, kill);
this.dead = false;
function kill(e:MouseEvent):void
{
this.dead=true;
mouseChildren=false
mysound.play();
gotoAndPlay(21);
this.removeEventListener(MouseEvent.CLICK, kill);
flash.utils.setTimeout(removeSelf,2000);
}
function removeSelf():void
{
this.parent.removeChild(this);
}
You shouldn't remove an enermy from the array while iterating it.
You make enemies.splice(i,1); in your loop iterating from enemies.length to 0. While you changing your array size, you don't adjust the loop condition.
I think your main issue might be that you are reusing your insects, maybe pooling them. If you do this, you need to make sure that you are adding the eventListener for the click again when recycling.
If you are adding the listener in the constructor, that will only execute when the insect is created, not when you recycle him.
Your issue is the setTimeOut(), which is causing a memory leak. Using a timer is much safer, but if you must use it, keep a reference to the call and clear it when you no longer need it.
Also, the code you posted doesn't show where you're adding a listener to MainTimeline or parent, but if you are you need to remove that as well before the insect can be garbage collected.