Creating “Flux”: A Simple Flash Game With a Gravity Mechanic

Creating “Flux”: A Simple Flash Game With a Gravity Mechanic

Tutorial Details
    • Difficulty: Beginner
    • Platform: Flash (Flash Player 10+)
    • Language: AS3
    • Software Used: FlashDevelop
    • Estimated Completion Time: 1 hour

In this tutorial, I’ll explain the major steps and workflow for creating a simple space survival game, based on the gravity mechanic explained in a previous tutorial. This game is written in AS3 using FlashDevelop.


Play the Game

Use the left and right arrow keys to manoeuvre your ship, the up and down arrow keys to increase or reduce the size of the magnetic field it produces, and the space bar to reverse the polarity. Collect the white crystals to increase your fuel supply – but avoid the red ones, because they use it up. Don’t hit a rock, or it’s game over!

In this tutorial, we won’t actually create the full game displayed above; we’ll just get started on it, by making a very simple version with primitive graphics and just one type of object. However, by the end, you should have learned enough to be able to add the other features yourself!

The game itself is very simple in its current state – take a look at this critique for tips on how you can take it from a simple demo to a full game!


Let’s Get Started!

Set up a new AS3 project in FlashDevelop, and set its dimensions to 550x600px.

 package 
{
	[SWF(width = "550", height = "600")]
	
	public class Main extends Sprite
	{
	
	}
}

Step 1: Identifying the Game Objects

There are six objects in particle that you can identify from playing the game above:

  • Energy supply – represented by an white oval shape object
  • Asteroid – represented by a rock-like object
  • Energy consumer – represented by a red star bounded with green light.
  • Stars – the background
  • Range indicator – represented by a white circle
  • Ship – player object

Of course you can add in any other object to make the game more interactive or add a new feature. For this tutorial we’ll just make


Step 2: The Energy Class

From the objects we identified, four of them actually work in exactly the same way: by falling from top to bottom.

They are:

  • Stars
  • Energy supply
  • Energy consumer
  • Asteroid

In this tutorial, we’re only going to make the “energy supply” objects, out of the four above. So let’s begin by creating these objects and making them fall down, with a random spawning position and speed.

Start by creating an Energy class:

	package  
	{
		import flash.display.MovieClip;
		import flash.events.Event;

		public class Energy extends MovieClip
		{
			private var rSpeed:Number = 0;
			
			public function Energy(speed:Number)
			{		
				graphics.beginFill(0x321312);
				graphics.drawCircle(0, 0 , 8);
				
				rSpeed = speed;
			}
			
			// we will call this every frame
			public function move():void
			{
				this.y += rSpeed;
				//rotation speed is linked to moving speed
				this.rotation += rSpeed / 8;
			}
		}
	}

Step 3: The GameScreen Class

This class will eventually control most of the aspects of our game, including the player movement and the game loop.

Create the class:

package  
{
	
	public class GameScreen extends MovieClip
	{

		public function GameScreen()
		{
		
		}
	}
}

That’s all we need for now.


Step 4: Update The Main Class

We’ll now create an instance of GameScreen within Main:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;

	[SWF(width = "550", height = "600")]
	 
	public class Main extends Sprite 
	{
		private var game:GameScreen;
		
		public function Main():void 
		{
			// don't display a yellow rectangle on the screen at startup
			stage.stageFocusRect = false;
			
			game = new GameScreen();
			addChild(game);
			
			// give keyboard focus to the game screen immediately
			stage.focus = game;
		}
	}
}

Why bother? Well, this way, it’ll be easier to add extra screens later if we want to (like a preloader, a title screen, a game over screen…).


Step 5: Introducing a Manager Class

To avoid the GameScreen class becoming too much of a mess, we’ll use separate classes to manage each object.

Each manager class will contain all the functions that relate to, and interact with, a particular object. Here’s the EnergyManager class:

package  
{
	import flash.display.MovieClip;
	
	public class EnergyManager
	{
		// this Vector will store all instances of the Energy class
		private var energyList:Vector.<Energy>	
		private var gameScreen:GameScreen;
		
		public function EnergyManager(gs:GameScreen) 
		{
			gameScreen = gs;
			energyList = new Vector.<Energy>;	
		}
	}
}

Note that we require a reference to the GameScreen to be passed to the constructor, and we store this reference in a private variable. We also set up a Vector to store references to all the energy objects.

So far the class contain no other functions; we will add them in later.


Step 6: Creating Energy

Add the below function for creating energy, this is just a function; we will call the function later from GameScreen Class:

	public function createEnergy(number:int):void	
	{
		var energy:Energy;
		for (var i:int = 0; i < number; i++) {		

			energy = new Energy(4);				
				
			gameScreen.addEnergyToScreen(energy);
				
			energyList.push(energy);				
	
			energy.x = Calculation.generateRandomValue(30, 520);		
			energy.y = Calculation.generateRandomValue( -150, -20); 
		}
	}

We create a new energy supply with a speed of 4, add it to the display list (via the GameScreen), add it to the Vector of all energy objects that we just created, and set its position to a random point within certain bounds.

The Calculation.generateRandomValue(#, #) is a static function we haven’t written yet, so let’s do that now. Create a new class called Calculation and add this function:

	public static function generateRandomValue(min:Number, max:Number):Number
	{
		var randomValue:Number = min + (Math.random() * (max - min));
			
		return randomValue;
	}

This function will generate a random number between the two values passed to it. For more information on how it works, see this Quick Tip. Since this is a static function, we don’t need to create an instance of Calculation in order to call it.

Now, what’s that addEnergyToScreen() function? We haven’t defined that yet, so let’s do it now. Add this to GameScreen:

		public function addEnergyToScreen(energy:Energy):void
		{
			addChild(energy);
		}

It just adds the passed instance of energy to the display list. Let’s also make a corresponding function to remove a given energy object from the screen:

		public function removeEnergyFromScreen(energy:Energy):void
		{
			if (energy.parent == this)
			{
				removeChild(energy);
			}
		}

Step 7: Spawning Energy

Let’s set a timer that defines the interval for each spawning. This code goes in GameScreen‘s constructor function:

energyM = new EnergyManager(this);	//remember to pass a reference to the game screen
								
var spawnTimer:Timer = new Timer(3000, 0);
spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
spawnTimer.start();

So, every three seconds, the timer will call spawnEnergy(). Let’s write that function now:

	private function spawnEnergy(e:TimerEvent):void
	{
		energyM.createEnergy(4);    // create 4 energies
	}

Step 8: Creating Player

Let’s use another, bigger circle to represent the player. Feel free to import an image to use instead:

public function Player() 
		{
			graphics.beginFill(0x7ebff1);
			graphics.drawCircle(0, 0, 20);
			

Add this code to GameScreen to add the player to the screen:

// in the variable definitions
public var player:Player; 
// in the constructor function
player = new Player;
addChild(player);
player.x = 275;
player.y = 450;

So far we should have a few energy supplies falling few seconds, and the player appearing in the middle of the screen:

playerandenergy.

Step 9: Moving the Player

There are basically two ways to apply movement:

  1. Using Boolean (true/false) values – true = moving, false = not moving. When the right arrow key is pressed, the value for “moving right” will change to true. In each frame update, “moving right” is true, we increase the object’s x-value.
  2. Using direct update each frame – when the right arrow key is pressed, an object is told to move right immediately, by increasing its x-value.

The second method does not lead to smooth movement when the key is continuously pressed, but the first method does – so we shall use the first method.

There are three simple steps to doing this:

  1. Create two Boolean variables, one for moving right and one for moving left.
    	private var moveRight:Boolean = false;
    	private var moveLeft:Boolean = false;
    	
  2. Toggle the Boolean when keys are pressed or released:
    		addEventListener(Event.ENTER_FRAME, update);
    		addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
    		addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);
    	}
    		
    	private function KeyDownHandler(e:KeyboardEvent):void
    	{
    		if (e.keyCode == Keyboard.RIGHT) {
    			moveRight = true;
    		}
    		if (e.keyCode == Keyboard.LEFT) {
    			moveLeft = true;
    		}
    		if (e.keyCode == Keyboard.SPACE) {
    			if (isGravityPushing == true) {
    				isGravityPushing = false;
    			} else  {
    				isGravityPushing = true;
    			}
    		}
    	}
    		
    	private function KeyUpHandler(e:KeyboardEvent):void
    	{
    		if (e.keyCode == Keyboard.RIGHT) {
    			moveRight = false;
    		}
    		if (e.keyCode == Keyboard.LEFT) {
    			moveLeft = false;
    		}
    	}
    	
  3. Based on these Booleans, actually move the player every frame:

    Don’t forget to first create a function listen from the enter frame event, “updating” :

    //call this function every frame
    private function update(e:Event):void
    	if (moveRight == true) {
    		player.x += 6;
    	}
    	if (moveLeft == true) {
    		player.x -= 6;
    	}
    	

    Keep the player within the bounds of the screen:

    	if (player.x >= 525) {
    		moveRight = false;
    	}
    	if (player.x <= 20) {
    		moveLeft = false;
    	}
    	

Here’s how all that looks, in place:

package
{
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.ui.Keyboard;
    import flash.utils.Timer;
    import flash.events.KeyboardEvent;
 
    public class GameScreen
    {
        public var player:Player;
 
        private var energyM:EnergyManager;
 
        private var moveRight:Boolean = false;
        private var moveLeft:Boolean = false;
        private var isGravityPushing:Boolean = true;
 
        private var returnedPower:int = 0;
 
        private var scoreText:Text;
        private var totalScore:int=0;
        private var score:Text;
 
        public function GameScreen()
        {
            scoreText = new Text("Score :");
            addChild(scoreText);
 
            energyM = new EnergyManager;
 
            var spawnTimer:Timer = new Timer(3000, 0);
            spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
            spawnTimer.start();
 
            player = new Player;
            addChild(player);
            player.x = 275;
            player.y = 450;
 
            addEventListener(Event.ENTER_FRAME, update);
            addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
            addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);
        }

	private function KeyDownHandler(e:KeyboardEvent):void
	{
		if (e.keyCode == Keyboard.RIGHT) {
			moveRight = true;
		}
		if (e.keyCode == Keyboard.LEFT) {
			moveLeft = true;
		}
		if (e.keyCode == Keyboard.SPACE) {
			if (isGravityPushing == true) {
				isGravityPushing = false;
			}else if (isGravityPushing == false) {
				isGravityPushing = true;
			}
		}
	}
		
	private function KeyUpHandler(e:KeyboardEvent):void
	{
		if (e.keyCode == Keyboard.RIGHT) {
			moveRight = false;
		}
		if (e.keyCode == Keyboard.LEFT) {
			moveLeft = false;
		}
	}

	private function update(e:Event):void
	{
		if (player.x >= 525) {
			moveRight = false;
		}
		if (player.x <= 20) {
			moveLeft = false;
		}
		if (moveRight == true) {
			player.x += 6;
		}
		if (moveLeft == true) {
			player.x -= 6;
		}
	}
    }
}

Step 10: Move the Energy Supplies

At the moment, the energy supplies are spawning but not moving. We’ll use the GameScreen.update() function to make them move, since it runs every frame.

Add this code to GameScreen.update():

			energyM.moveAll();  // will make every energy object move

Now of course we need to make the EnergyManager.moveAll() function, so add this to EnergyManager.as:

		public function moveAll():void
		{
			for (var i:int = 0; i < energyList.length; i++) {
				var energyS:Energy = energyList[i];
				energyS.move();
			}
		}

Step 10: Collision Detection

We will need to check for collisions between each energy object and the player. (If you develop the game further, you’ll need to check this for asteroids and energy consumers, but not for stars.)

The best place to handle these checks is inside the EnergyManager, triggered every frame by the GameScreen.

One thing to consider: the collision checks will be between two circles, so hitTestObject() is not ideal. Instead, we’ll be using the method explained in this tutorial.

We can write the function as below:

	public function checkCollision(p:Player):int
	{
		// energy transferred due to collision
		var energyTransfer:int = 0;
		
		for (var i:int = 0; i < energyList.length; i++) {
			var energyS:Energy = energyList[i];
			
			var newX:Number = p.x - energyS.x;
			var newY:Number = p.y - energyS.y;
				
			var distance:Number = Math.sqrt(newX * newX + newY * newY);
				
			if (distance <= 28) {
				gameScreen.removeEnergyFromScreen(energyS);
				energyList.splice(i, 1);
				// for this simple game, we'll always transfer 1 unit
				// but you could alter this based on speed of collision
				// or any other factor
				energyTransfer = 1;
			}
		}
		return energyTransfer;
	}
  • Line 32: note that we pass in a reference to the player, so that we can access its position.
  • Line 38: EnergyS is short for Energy Supply.
  • Line 40 & 41: finding the difference in x- and y-coordinates between the player and the energy supply we are currently checking.
  • Line 43: calculate the distance between the objects via Pythagoras.
  • Line 45: check for collision; 28 is the sum of the two objects’ radii (player radius is 20, energy radius is 8).
  • Line 46 & 47: remove energy supply from screen and from Vector.
  • Line 51: add a maximum of one unit of energy per frame.

You could alter Line 51 to energyTransfer += 1, to allow the player to absorb more than one energy object at once. It’s up to you – try it out and see how it affects the game.


Step 11: Call Collision Detection Routine

We need to check for collisions every frame, so we should call the function we just wrote from GameScreen.update().

First, we need to create an integer variable to store the energy transfer value from the collision detection function. We’ll use this value for increasing the ship’s energy and adding to the player’s score.

private var returnedPower:int = 0;
returnedPower = energyM.checkCollision(player);

Step 12: Newton’s Law of Gravitation

Before we go into creating the game mechanic for the ‘Push’ and ‘Pull’ function of the ship, I would like to introduce the physics concept on which the mechanic is based.

The idea is to attract the object towards the player by means of a force. Newton’s Law of Universal Gravitation gives us a great (and simple) mathematical formula we can use for this, where the force is of course the gravitational force:

G is just a number, and we can set it to whatever we like. Similarly, we can set the masses of each object in the game to any values that we like. Gravity occurs across infinite distances, but in our game, we’ll have a cut-off point (denoted by the white circle in the demo from the start of the tutorial).

The two most important things to note about this formula are:

  • The strength of the force depends on the square of the distance between the two objects (so if the objects are twice as far away, the force is one-quarter as strong).
  • The direction of the force is along the direct line connecting the two objects through space.

Step 13: Revising Math Concepts

Before we start coding the game mechanics for the ‘Push’ and ‘Pull’ function, let’s be clear on what we want it to do:

frameWork

Essentially, we want A (the player) to exert a certain force on B (a crystal), and move B towards A based on that force.

We should revise a few concepts:

  • Flash works in radians rather than degrees.
  • Flash’s coordinate system has its y-axis reversed: going down means an increase in y.
  • We can get the angle of the line connecting A to B using Math.atan2(B.y - A.y, B.x - A.x).
  • We can use trigonometry to figure out how much we need to move B along each axis, based on this angle and the force:
    • B.x += (Force*Math.cos(angle));
    • B.y += (Force*Math.sin(angle));
  • We can use Pythagoras’s theorem to figure out the distance between the two objects:

For more information, see the tutorials Gravity in Action and Trigonometry for Flash Game Developers.


Step 14: Implementing Push and Pull

Based on the previous explanation, we can come up with an outline for our code that attracts each crystal to the ship:

  1. Find the difference in x and y between the ship and a given crystal.
  2. Find the angle between them, in radians.
  3. Find the distance between them, using Pythagoras.
  4. Check whether object is within the ship’s gravitational field.
  5. If so, calculate the gravitational force, and…
  6. …apply the force, changing the x and y values of the crystal.

Sample Code:

	public function gravityPull(p:Player): void
	{
		for (var i:int = 0; i < energyList.length; i++) {
			var energyS:Energy = energyList[i];
				
			var nX:Number = (p.x - energyS.x);
			var nY:Number = (p.y - energyS.y);
			
			var angle:Number = Math.atan2(nY, nX);
				
			var r:Number =  Math.sqrt(nX * nX + nY * nY);
				
			if (r <= 250) {
				var f:Number = (4 * 50 * 10) / (r * r); 				
				energyS.x += f * Math.cos(angle);
				energyS.y += f * Math.sin(angle);
			}
		}
	}
  • Line 53: get a reference to the player.
  • Line 55: we loop through each energy object.
  • Line 61: find the angle between the ship and the energy.
  • Line 63: find the distance between them, too.
  • Line 65: check whether the energy is within the ship’s force field.
  • Line 67: use the formula:
    • 4 = G, the “gravitational constant” I’ve chosen.
    • 50 = m1, the mass of the ship player.
    • 10 = m2, the mass of the energy object.
  • Line 69: apply movement.

Here’s a timelapse showing how this looks:

Note that the energy moves faster the closer it gets to the ship, thanks to the r-squared term.

We can implement the pushing function just by making the force negative:

	public function gravityPull(p:Player): void
	{
		for (var i:int = 0; i < energyList.length; i++) {
			var energyS:Energy = energyList[i];
				
			var nX:Number = (p.x - energyS.x);
			var nY:Number = (p.y - energyS.y);
			
			var angle:Number = Math.atan2(nY, nX);
				
			var r:Number =  Math.sqrt(nX * nX + nY * nY);
				
			if (r <= 250) {
				var f:Number = (4 * 50 * 10) / (r * r); 				
				energyS.x -= f * Math.cos(angle);
				energyS.y -= f * Math.sin(angle);
			}
		}
	}

Here the object moves more slowly as it gets further away from the player, since the force gets weaker.


Step 15: Apply the Mechanic

Of course that you will need this function to be run each frame by GameScreen – but before that, we will need to use a Boolean function to toggle between the two functions:

private var isGravityPushing:Boolean = true;  // hitting space toggles it

We are going to use true for ‘Push’ and false for ‘Pull’.

Inside KeyDownHandler():

	if (e.keyCode == Keyboard.SPACE) {
		if (isGravityPushing == true) {
			isGravityPushing = false;
		} else if (isGravityPushing == false) {
			isGravityPushing = true;
		}
	}

Afterwards, you will have to check the Boolean each frame. Add this to update():

	if (isGravityPushing == true) {
		energyM.gravityPull(player);
	}
	if (isGravityPushing == false) {
		energyM.gravityPush(player);
	}

Step 16: Modification

You might find that the movement doesn’t look so nice. This could be because the force is not quite ideal, or because of the r-squared term.

I’d like to alter the formula like so:

var f:Number = (0.8 * 50 * 10) / r;

As you can see, I’ve reduced the value of “G” to 0.8, and changed the force to depend simply on the distance between the objects, rather than the distance squared.

Try it out and see if you enjoy the change. You can always alter it however you like.


Step 17: The Text Class

We will need to show some text on the screen, for showing the score and the ship’s remaining power.

For this purpose, we’ll build a new class, Text:

package  
{
	import flash.display.MovieClip;
	import flash.text.TextField;
	import flash.events.Event;
	import flash.text.TextFormat;

	import flash.text.TextFormatAlign;

	public class Text extends MovieClip
	{
		public var _scoreText:TextField= new TextField();
		
		public function Text(string:String)
		{	
			var myScoreFormat:TextFormat = new TextFormat(); //Format changeable
			myScoreFormat.size = 24;		
			
			myScoreFormat.align = TextFormatAlign.LEFT;
			myScoreFormat.color = (0x131313);
			
			_scoreText.defaultTextFormat = myScoreFormat;
			
			_scoreText.text = string;
			
			addChild(_scoreText);
		}

		public function updateText(string:String)
		{
			_scoreText.text = string;
		}
	}
}

It’s very simple; it’s basically a MovieClip with a text field inside.


Step 18: Adding Power for Player

To give the game some challenge, we’ll make the ship’s power get used up slowly, so that the player has to collect energy objects in order to recharge.

To make the ship’s power appear on the ship itself, we can simply add an instance of Text to the ship object’s display list.

Declare these variables within the Ship class:

public var totalPower:Number = 100;  // ship starts with this much power
private var powerText:Text;

We’ll need to keep the amount of power (both stored and displayed) updated every frame, so add this new function to Player:

First, in the constructor:

			// add a new text object if it doesn't already exist
			if (!powerText) {
				powerText = new Text(String(int(totalPower))); 
				addChild(powerText);	
				powerText.x -= 20;			//Adjust position
				powerText.y -= 16;
			}

And then…

	public function updatePower():void
		{
			// fps = 24, so this makes power decrease by 1/sec
			totalPower -= 1 / 24;		
			powerText.updateText(String(int(totalPower)));
		}

The power will decrease every frame by 1/24th of a unit, meaning it’ll decrease by one full unit every second.

We need to make this run every frame, so add this line to GameScreen.update():

player.updatePower();

Step 19: Make Energy Increase Power

When the ship collides with an energy object, we want it to increase its power.

In GameScreen.update(), add the highlighted line:

returnedPower = energyM.checkCollision(player);
player.totalPower += returnedPower;

Remember you can alter how much power is returned in the EnergyManager.checkCollision() function.


Step 20: Setting Up the Score

Again, we will need the text class. This time, we’ll display “Score” and then the value.

Here, we will need three more variables:

  • The “Score” text.
  • The score value text.
  • A variable to store the actual score.

Declare these in GameScreen class:

private var scoreText:Text;
private var totalScore:int = 0;
private var score:Text;

In the constructor, add this code:

scoreText = new Text("Score :");
addChild(scoreText);

score = new Text(String(totalScore));
addChild(score);
score.x = scoreText.x + 100;   //Positioning it beside the "Score : " Text.
score.y += 2;

Now, in the update() function, add this:

score.updateText(String(totalScore));

That’s it – we’ve created a basic version of the above game!

Take a look (you may need to reload the page):


Extra Features and Polishing

Space Background

Maybe you would also like a background with an embedded image and stars. Add this to your Main class:

[Embed(source = "/../lib/SpaceBackground.jpg")]	//embed
		private var backgroundImage:Class; //This line must come immediately after the embed

		private var bgImage:Bitmap = new backgroundImage();		
		private var numOfStars:int = 70;		

Now create the Star class:

package assets 
{
	import flash.display.MovieClip;
	import flash.events.Event;

	public class Star extends MovieClip
	{
		private var speed:Number;
		
		public function Star(alpha:Number, size:Number, speed1:Number) 
		{
			graphics.beginFill(0xCCCCCC);
			graphics.drawCircle(0, 0, size);
			
			speed = speed1;
		}
		
		// make sure you call this every frame
		private function moveDown():void
		{
			this.y += speed;
			
			if (this.y >= 600) {
				this.y = 0;
			}
		}
	}
}

In the Main() constructor, add this to create the stars:


for (var i:int = 0; i < numOfStars; i++) {
		createStars();
}

Here’s the actual createStars() function:


private function createStars():void
{
	var star:Star = new Star(
		Math.random(), 
		Calculations.getRandomValue(1, 2), 
		Calculations.getRandomValue(2, 5)
	);  //random alpha, size and speed
			
	addChild(star);
			
	star.x = Calculations.getRandomValue(0, 550);
	star.y = Calculations.getRandomValue(0, 600);
}

With random alpha, size, position, and speed, a pseudo-3D background can be generated.

Range indicator

A range indicator circle can be made by simply creating another circle and adding it to the ship’s display list, just like how you added the power indicator text. Make sure the circle is centred on the ship, and has a radius equal to the ship’s push/pull range.

Add transparancy (alpha value) to the circle with the below code:

			graphics.beginFill(0xCCCCCC, 0.1);

Try adding extra controls that make the range increase or decrease when the up and down arrow keys are pressed.


Conclusion

I hope you enjoyed this tutorial! Please do leave your comments.

Next: Read this critique for a guide to taking Flux from a simple demo to a full game!

  • Jesus Bejarano

    excellent , i like it alot

  • miels

    The performance of the game was not acceptable: ~10 fps FP 11.2 (Linux)

    The code wasn’t any better either.

    I don’t like how every Energy, Star MovieClip (Why are those even MovieClips if no time line is used?) has its own ENTER_FRAME loop.
    I’m surprised to see this widely known bad practice in a tutorial.

    What’s the point of the StageController?

    public static STAGE:Stage? Really?
    Why would one want to add assets to the stage anyway?

    Overcomplicated, bloated code like that will not be helpful for somebody starting with programming:
    if (space == true) {
    space = false;
    }else if (space == false) {
    space = true;
    }

    or -> space = !space

    Hardcoded values aren’t that good when it comes to maintaining the code.
    And this is a game, so speed values will definitely be tweaked.

    Although there is some movement involved, the motion was not refactored into a separate class, which would be helpful to handle every motion in the game in a uniformed way (player, energy, etc.)

    Overall disappointing. =(

    • http://michaeljameswilliams.com/ Michael James Williams

      Hey miels,

      You’re right: there were a number of odd habits and bad practices in this code. I originally let them through because they weren’t the focus of the tutorial… but that’s a bad reason.

      I’ve gone through and made a number of changes to the source and the tut:

      – StageController is now called GameScreen, as this better reflects its purpose.
      – There is only one ENTER_FRAME handler function, in GameScreen, and this calls all the other objects’ frame-based functions as required.
      — (There is still a separate Timer, though, admittedly.)
      – All references to STAGE have been removed.
      — (However, my fix is a bit of a hack; EnergyManager basically calls gameScreen.addChild())
      – “space” has been renamed to “isGravityPushing” as this it more descriptive.

      I haven’t changed the various display object classes to Sprites (rather than MovieClips) because I don’t think there’s any harm in leaving them as MCs, and based on my experiences this is a little easier to understand for beginners.

      Same goes for the “space = !space” code. Funnily enough, I almost changed this first time through… but again, I find that the longer version is generally easier to understand for a new coder.

      I also haven’t refactored the motion into separate classes, but that’s simply because of the amount of rewriting that would have been involved.

      Thanks for your feedback!

      • miels

        I’m afraid removing STAGE broke it.

        My question regarding GameController/GameScreen was more aiming to why this is not the document class.
        I guess turning it into the doc class fixes the above mentioned trouble caused by the lack of STAGE.

      • http://michaeljameswilliams.com/ Michael James Williams

        Broke it how?

        I think one good reason for a separate GameScreen is so that you can add more screens later if you wish.

      • miels

        There is no addChild() if GameScreen is not a DisplayObjectContainer.

      • http://michaeljameswilliams.com/ Michael James Williams

        Oh, whoops. I forgot to add “extends MovieClip” to the code in the tut.

  • http://www.gemfruit.com Porter

    Yay for code optimization!

    While boolean = !boolean is the best way to go about it, I can see it being confusing to beginners. That being said, I’d still change it to if(boolean) rather than if(boolean == true). There’s no reason for a double boolean check, explain this if needed, but it’s something that confused me as a beginner, and I wish someone had cleared it up sooner, so here’s our chance :)

    Overall, it’s a decent tutorial, probably just needed another hour or two to refine the code a bit.

    • http://michaeljameswilliams.com/ Michael James Williams

      Oh! You make a good point. And that else-if is totally unnecessary, heh.

      I’m surprised you find/found if(boolean) less confusing than if(boolean == true). Different strokes, I guess.

    • Wilson Lim
      Author

      Hello Porter,

      I was thinking maybe writing the code in if(boolean == true), will eventually create a better sequence reading for a beginner. Maybe a comment should be added there, that it can be written as if(boolean) too.

  • http://www.gemfruit.com Porter

    I didn’t find if(boolean == true) more confusing, I found understanding if(boolean) extremely confusing at first because I had used something else for so long. Nobody explained to me that if(something) was indeed checking if something was true already, thus the == true or false isn’t needed. I would see code that said if(jumping), and I would wonder to myself how the hell the program understood what jumping was.

    It’s a very small detail, but it’s definitely something that confuses beginners if they’re never told. As someone who started with very sloppy AS2 code for years, then learned AS3 / OOP out of the blue, I can definitely pick up on what minor things confuse those without a coding background.

    • http://michaeljameswilliams.com/ Michael James Williams

      Ah, I see. Cool, that’s what I figured :) I’ll leave the (boolean == true) checks in this since it’s consistent and easier to understand (like Wilson said).

    • miels

      People try to dance, but they can’t even walk. That’s the problem.

      There’s not that much complicated stuff to an if statement. It’s not rocket science.
      But people want to “make games” and sure enough, with an aim like this, they would not consider reading that one page it takes to know everything about if statements. That’s boring, isn’t it?

      Oh yes, the details. Like naming conventions. How about “isJumping” ?
      if (simpleSimon.isJumping) //…wait …that… looks almost like a regular sentence, could it be that easy?

      Sure, learning never stops and there are those “oh, didn’t know that, nice!” moments once in a while, but jeez it’s an if statement, which is not (and shouldn’t be) the subject of this tutorial.

  • Yusuf

    Million thanks for the tutorial. I’ve learned a loooot of things in OOP and how it works in action.

    However,I would like to note that you’ve forgot to add the code for increasing the score in “GameScreen.update();” ,at the end just after you finished setting up the score, which is:

    totalScore += returnedPower * 10;

    Also, I noticed that by saying: “Declare these variables within the Ship class:” you meant the “Player” class. look it up using the search engine of your browser.

    Thank you so much for the amazing tutorial Mr.Wilson.