Author Topic: [SOLVED] Properly using update function to finish a level (Super new at flash)  (Read 1420 times)

WannaBeProgrammer

  • New Member
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Hey all. This is my first post as well as my first attempt to ask for help online for anything flash related. I've fooled around with AS3 for a while, but everything has been self taught. I started reading the book "Classroom in a Book: Actionscript 3.0 for ADOBE FLASH CS4 Professional" and I've followed tutorials online, but I'm still incredibly new and naive towards how things should and should not be done.

I recently finished following the Flixel side-scroller demo tutorial:

http://www.creativeapplications.net/flash/flixel-2-tutorial-flash-tutorials-games/

As well as part 2:

http://www.omegastormproductions.com/uber-flash/flixel-2-tutorial-extended

I've been using FlashDevelop on a Windows 7 machine.

Now I've been tinkering with the game to learn more. So far my exploration has involved adding shield drops that increase the shield, having the destroyed aliens produce coins, and making the ship able to collect the coins and add them to the money score. Now, I'm trying to make it so that the level ends after 100 aliens have finished spawning.

In order to do this, I added the following variables to the PlayState class. The _counter variable is the time between the final alien spawning and the text "Level complete!" appearing, and the _counter2 variable is the time between the last alien spawning and the PlayState resetting (Warning, noob coding here. Feel free to criticize):

Code: [Select]
private var _numOfAliens: Number = 0;
private var _counter: Number = 5;
private var _counter2: Number = 10;

I then modified the if statement in the update function that deals with spawning aliens to this:

Code: [Select]
if(_spawnTimer < 0 && _numOfAliens <= 100)
{
     spawnAlien();
     resetSpawnTimer();
     _numOfAliens += 1;
}

I want the text "Level complete!" to appear 5 seconds after the final alien spawns. Then, 5 seconds after the text comes up, I want it to start the PlayState again (eventually I'll make multiple levels, but this is just a start). My attempt at this led me to making this if statement in the update function:

Code: [Select]
if (_numOfAliens >= 100)
{
     _counter -= FlxG.elapsed;
     _counter2 -= FlxG.elapsed;

     if (_counter <= 0)
     {
          _winnerText = new FlxText(0, (FlxG.width / 2) - 150, FlxG.width, "Level complete!")
        
          _winnerText.setFormat(null,48,0xFFFFFFFF,"center")
 this.add(_winnerText);
     }

     if (_counter2 <= 0)
     {
          FlxG.state = new PlayState();
     }
}

I know, you guys are probably grinding your teeth right now. Anyway, as I test the game, I realize that after the text comes up, the game starts to slow down for those 5 seconds before the PlayState resets. I'm guessing that what is happeneing is that since this is all in the update function (which I believe is the function that updates every frame?), the if statement for the _winnerText repeats forever, which continues to add the _winnerText on every frame, thus slowing the game down.

It would be great if you guys could explain the best way to this. Or just to let me know if I'm on the right track or not. If not, I'm totally fine with figuring it out on my own, I'm just at a point where I don't really know where to look. I can't seem to find any specific information on this matter.

I hope this is enough information, but if not I'd be happy to share my code for the game.

Thank you so much for reading through my post. I hope to hear from someone soon!

WannaBeProgrammer
« Last Edit: Fri, May 6, 2011 by WannaBeProgrammer »

zadvornykh

  • Active Member
  • ***
  • Posts: 205
  • Karma: +1/-0
    • View Profile
A couple of things:

1. You should avoid calling vars things like counter1 and counter2. Naming the counter after what it has to count will help keep your code manageable in the long run.

2. There is a countDead() method on FlxGroup, so you do not need to keep a separate counter in your playstate.

3. Changing your conditional statements to something like this should solve your immediate problem:
Code: [Select]
if(enemies.countDead() == 100)
{
 setTimeout(showLevelEndText, 5000);
 setTimeout(changeGameState, 1000);
}

Then put the relevant code into the new methods. This is most likely the simplest way to do timings like this (unless flixel has something build in for such things)

WannaBeProgrammer

  • New Member
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Thanks for the reply.

You should avoid calling vars things like counter1 and counter2. Naming the counter after what it has to count will help keep your code manageable in the long run.

Okay, thanks for the tip!

So after looking into it, it looks like the countDead method returns the number of "killed" objects in a specified group. However, looking through the code for this game, I don't see anything that indicates that the aliens are killed once they exit the screen to the left. Am I missing something? Shouldn't there be an if statement that runs alien.kill(); once it reaches the end of the screen? Surely they are somehow being removed since the game doesn't slow down at all, even after hundreds of aliens fly out of the boundary of the screen.

Below is the entire AS file for the Alien class.

Code: [Select]
package de.pixelate.flixelprimer
{
    import org.flixel.*;
 
    public class Alien extends FlxSprite
    {
        [Embed(source="../../../../lib/png/Alien.png")]
        private var ImgAlien:Class;
 
        public function Alien(x: Number, y: Number):void
        {
            super(x, y, ImgAlien);
            velocity.x = -200;
        }

public function getPowerupSpawnPosition():FlxPoint
{
var powerupPos: FlxPoint = new FlxPoint(x, y); // Gets the position of the alien so a powerup can spawn there
return powerupPos; // Returns the positional value so it can be used
}
 
        override public function update():void
        {
            velocity.y = Math.cos(x / 50) * 50;
            super.update();
        }
    }
}

Here is the update method in the PlayState class. NOTE: That if statement that occurs when _numOfAliens is >= 100 still has not been modified.
Code: [Select]
override public function update():void
{
     FlxU.overlap(_aliens, _bullets, overlapAlienBullet);
     FlxU.overlap(_aliens, _ship, overlapAlienShip);
     FlxU.overlap(_ship, _powerups, overlapShipPowerup); // Collision between the player and a powerup
     FlxU.overlap(_ship, _armorDrops, overlapShipArmorDrop);
     FlxU.overlap(_ship, _coins, overlapShipCoin);

     if(FlxG.keys.justPressed("SPACE") && _ship.dead == false)
     {
          spawnBullet(_ship.getBulletSpawnPosition());
     }

     _spawnTimer -= FlxG.elapsed;
     _dropTimer -= FlxG.elapsed;
 
     if(_spawnTimer < 0 && _numOfAliens <= 100)
     {
          spawnAlien();
          resetSpawnTimer();
  _numOfAliens += 1;
     }

     if (_dropTimer < 0)
     {
          spawnArmorDrop();
          resetDropTimer();
     }

     if(FlxG.keys.ENTER && _ship.dead)
     {
          FlxG.state = new PlayState();
     }

     if (_numOfAliens >= 100)
     {
          _counter -= FlxG.elapsed;
  _counter2 -= FlxG.elapsed;

  if (_counter <= 0)
  {
       _winnerText = new FlxText(0, (FlxG.width / 2) - 150, FlxG.width, "Level complete!")
               _winnerText.setFormat(null,48,0xFFFFFFFF,"center")
this.add(_winnerText);
  }

  if (_counter2 <= 0)
  {
       FlxG.state = new PlayState();
  }
     }
     super.update();
}

Here is the spawnAlien method in the PlayState class.

Code: [Select]
private function spawnAlien():void
{
     var x: Number = FlxG.width;
     var y: Number = Math.random() * (FlxG.height - 100) + 50;
     _aliens.add(new Alien(x, y));
}

I'm not sure how much all of this code helps, but I'm hoping it may be enough for someone to explain to me how these aliens are being removed from the game once they go off to the left of the screen. I'm assuming that once I know how it's done, I'll be able to utilize the countDead method that zadvornykh suggested.

WannaBeProgrammer

  • New Member
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
UPDATE:

I just looked at the comments in the Flixel tutorial I followed to make the game (probably should have done that first!) and found out someone had a similar question in terms of how aliens are removed once they leave the screen.

It turns out the author of the tutorial did not write the code for perfomance, rather just an introduction to Flixel. Therefore, the aliens and bullets actually aren't being removed from the screen once they exit to the left.

As he suggested in the comments, I'm going to take a look at the Flash Game Dojo document on memory management:

http://flashgamedojo.com/wiki/index.php?title=Memory_Management_%28Flixel%29

I'm going to check it out and see if it gets me anywhere.

OmegaStorm

  • Member
  • **
  • Posts: 36
  • Karma: +0/-0
    • View Profile
    • OmegaStorm Productions
Code: [Select]
if (x < (FlxG.width - FlxG.width) - 50)
 {
   kill(); // Kills the alien if it is not destroyed and moves off the screen
 }

Add this to the alien update (before super.update)to kill them if they leave the screen. I have it in my copy, I must have forgot to mention it in my tutorial. I'm sure writing it after the fact was the cause.

You are right though. Neither mine nor Andreas' tutorial are build with performance in mind (lol at all those Bullet = new Bullets). I was still new to Flixel (and AS3) at the time and was simply inspired to continue coding on it, sort of like you. As long as it worked, I was happy.

I'm going to be writing a new tutorial that's more optimized than that one soon. And I'll be writing it as I make it, as to not forget something this time.

Object Pools are your friend.

OmegaStorm

  • Member
  • **
  • Posts: 36
  • Karma: +0/-0
    • View Profile
    • OmegaStorm Productions
Silly me. I should probably address your original issue. You are right to assume that your text is being added during each update; 30 times a second for 5 seconds. A simple solution would be to add a Boolean that switches from false to true when the counter reach zero.

Code: [Select]
if (_numOfAliens >= 100)
{
     _counter -= FlxG.elapsed;
     _counter2 -= FlxG.elapsed;

     if (_counter <= 0 && _counterOneComplete == false)
     {
          _winnerText = new FlxText(0, (FlxG.width / 2) - 150, FlxG.width, "Level complete!")
         
          _winnerText.setFormat(null,48,0xFFFFFFFF,"center")
  this.add(_winnerText);

          _counterOneCompleted = true;
     }

     if (_counter2 <= 0 && _counterTwoComplete == false)
     {
          _counterTwoComplete = true;
          FlxG.state = new PlayState();
     }
}

Just declare them like you normally would and don't forget to have them reset to false when the state restarts.

WannaBeProgrammer

  • New Member
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Thanks OmegaStorm, your solutions worked perfectly. I'll keep tabs on your website so I can check out your new tutorial when you complete it.