5 Aug 2011

Chapter 1: The basics.

This tutorial will cover:
  •  Importing graphics.
  • Adding stuff to the stage (screen).
  •  Tracing.
  • Using variables
  • Detecting keyboard usage.
  • Moving an object.
Ok, let's get this started.
Open FlashDevelop (FD).
Project ► New Project ► AS3 Project
Check the 'Create directory for project' box.
Give it a name and click OK.
Project ► Properties.
Set Dimensions to 600 x 400. 
Use the background color of your choice.
Set framerate to 30.

Now you have the basic layout of your game.

On the right side, expand the 'src' folder and open (double-click) 'Main.as'.That file is your document class.

The document class will be loaded as soon as your game is loaded.
Let's take a quick look at it:

import flash.stuff.stuff;  
/*This allows us to use external classes in our code. 
       FD auto imports the required classes, so don't worry about it for now.*/
 
/** Some text... */
       /*The parts between /* */ are comments. They don't affect our code
       but are really useful. 
       Commenting out your code is a good practice. */  
 
public class Main extends Sprite {
public function Main():void {
code 
}
} 
      /*We have a class called 'Main', which extends the base class 'Sprite'.
      We'll get into details later.
      The function with the name of our class is the constructor. Its code will
      run as soon as an instance of the class is created.*/ 


Ok, enough technical stuff for now. Time to start working on the game.

Let's start by making graphics for our game. For this tutorial, we'll make a Pong-like one... Don't worry, the point of the tutorials is that you understand the code and once you finish it and with some practice, you'll be able to do pretty much anything that comes to your mind.

Anyway...draw a rectangular paddle of 150x30 pixels.
(cute, isn't it?)

Now open your project's folder (if you don't know it, go to the window where you create a new project and check the 'Location' field.) Open the 'lib' folder and save the pic as 'paddle.png'.

Now go to File ► New ► AS3 Document...
We'll make a new class that will store all our media.

Clear all the code of the new file and type the following:

package{
   public class Assets {
             [Embed (source = '../lib/paddle.png')] public static const Pad:Class;
     public function Assets() : void {
      }
   }
}


We'll be using the Embed metatag to import all our media. 
There will be more examples along the tutorials.

The 'public static' part will allow us to access the variable or constant from anywhere. In this example, our constant that references the paddle pic will be called 'Pad'.

Save the file as 'Assets.as' (an ActionScript -AS- file must be named the same as the class it holds).
Save it to your 'src' folder.

Now that we imported the pic, we need to bring it to the stage.
Create another AS3 file and delete the code in it. Then type:

package{
import flash.display.Bitmap;
import flash.display.Sprite;
   public class Paddle extends Sprite {
             private var pic:Bitmap = new Assets.Pad();
     public function Paddle():void{
      }
   }
} 

We declared a private variable (we can only access it from the class that holds it) with name 'pic'.
Our variables can have almost any name, just don't start them with numbers or symbols other than underscore (_) and dollar ($).

Our pic will be of type Bitmap (the type must be declared after the colon). Then we used the 'new' keyword to create an instance of the class 'Pad' which, as you remember, holds our pic.
Creating an instance of a class is not enough to make it 'spawn', let's bring it to the stage.


Change the constructor to:

public function Paddle() : void {
   addEventListener(Event.ADDED_TO_STAGE, go);
      }

Listeners allow our objects to respond to a determined situation.
In this case, it will respond when the object is added to the stage.
The text after the comma is the name of the function that will be called when the event is triggered.

So, resuming, we're telling it to run the 'go' function when it's added to the stage.

Now we need to make that function.
Add the following below the constructor:

private function go(e:Event) : void {
   removeEventListener(Event.ADDED_TO_STAGE, go);
   //We don't need our object to listent to that anymore, se we remove it. 
   addChild(pic);
  }


All functions go below the constructor.
The 'addChild()' method is used to add objects to the stage.

Everything is ready. Once an instance of our class Paddle is added to the stage, it will add our pic to it.
The problem is that there's nothing adding our Paddle to the stage...

Our Paddle class should look like this:

package{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event; 
 
  public class Paddle extends Sprite {
             private var pic:Bitmap = new Assets.Pad();
 
     public function Paddle() : void {
   addEventListener(Event.ADDED_TO_STAGE, go);
      }
 
private function go(e:Event) : void {
   removeEventListener(Event.ADDED_TO_STAGE, go);
   addChild(pic);
    }
  }
} 

Now save it (you should save your work after any change) and go to the document class (Main.as).

Below the line 'public class Main extends Sprite {' declare a reference to the paddle.

private var paddle:Paddle;

Then below the part that says 'entry point' type:

paddle = new Paddle();


This will create an instance of the Paddle class.
In our Paddle class, we created an instance of the Pad class right away, just after declaring the variable.
You can do it either way.

Now that we have our paddle, let's move it to the stage. 
Do you remember how?

addChild(paddle);


Our document class should look like this:

package {
 import flash.display.Sprite;
 import flash.events.Event;
 
 /**
  * ...
  * @author Senekis
  */
 public class Main extends Sprite {
                private var paddle:Paddle; 
 
  public function Main():void {
   if (stage) init();
   else addEventListener(Event.ADDED_TO_STAGE, init);
  }
 
  private function init(e:Event = null):void {
   removeEventListener(Event.ADDED_TO_STAGE, init);
   // entry point
                        paddle = new Paddle(); 
                        addChild(paddle); 
  }
 }
}

Save the file (Ctrl + s) and then run it (Ctrl + ENTER).
You should see your paddle. ☺

It spawned at the top left?
That's because our stage is on the fourth quadrant
of a cartesian system. Meaning (0,0) is at top-left corner.
 
Head to the Paddle.as and go below the line where you typed 'addChild(pic)'. 
Type this:

y = stage.stageHeight - pic.height;
x = stage.stageWidth * .5 - pic.width * .5;

Some simple math using the 'width' and 'height' properties of our pic as well as the dimensions of our stage to center the paddle at the bottom of the screen.

Looks better? Now we need to make it so the player can control it with the keyboard.

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler, false, 0, true);

This will let us know when a keyboard key is pressed.
Let's make the function...

private function keyDownHandler(e:KeyboardEvent):void {
      if (e.keyCode == 37 || e.keyCode == 65) {
        trace('Paddle is moving left');
     }
 }

Note that we always tell the type of the event that triggers each function (KeyboardEvent in this case).
The thing after the colon is the type that the function returns.
We'll get into that in another chapter.


if (e.keyCode == 37 || e.keyCode == 65) {
This is known as a conditional.
It works like this: If the condition between ( ) is evaluated as true,the code block between { } will run.

In this case, if LEFT or 'A' are pressed (keyCodes 37 and 65) the code will run.
|| means OR, so it can translate to: 'if(LEFT or A are pressed)...'

Then we have a trace. trace() is one of the most useful methods. It's a must when looking for bugs in your code and to know if something is working.

Save it and run a test. Press left key or 'A' and you should see a message in the panel below.

Tracing is good for testing and debugging, but now that we know it works, we need to make something happen when those keys are pressed.
Let's add a new variable to our Paddle class:

private var movingLeft:Boolean;

That goes below the line where we declared the pic variable. Variables should be declared there.

A Boolean is a value that can either be true or false.We'll use it in situations like this, where we want to know if something is happening (is the player pressing left or 'A'?).

If you don't explicitly give a value to your boolean variable, its default value will be 'false'.
Anyway, replace your trace statement for:

if (!movingLeft) {
movingLeft = true;
}

'!' means NOT, so it translates to: if(not movingLeft)...

We're checking if it's not already moving left, and then if that evaluates to true, we tell it to make our movingLeft variable true.
Now let's make something happen when movingLeft is true. Add this to the 'go' function:

addEventListener(Event.ENTER_FRAME, enterFrame, false, 0, true);

The code within an enter frame function will run every frame.
At the start of our project, we set the framerate to 30, that means the code of the enter frame function will run 30 times/sec.

Let's build the function...:

private function enterFrame(e:Event):void {
        if (movingLeft) {
                  x -= speed; 
      }

So... if we're pressing 'A' or left, its x value (horizontal position) will decrease by the value of the speed variable. So, let's declare that variable and give it a value:

private var speed:int = 10;

Data of type 'int' are integers.
Save and test.

The paddle should be moving! ☺
But once it starts moving, it won't stop, so we need a way to fix that. Let's check for key release:

stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler, false, 0, true);

Add it below the listener for KEY_DOWN.
Then we make the function...

private function keyUpHandler(e:KeyboardEvent):void {
                 if (e.keyCode == 37 || e.keyCode == 65) {
                        if (movingLeft) { 
                              movingLeft = false; 
                        }
                 }


Now test it. It should stop moving when the key is released.
There's a new problem: If you hold the key down, the paddle will keep moving and get out of bounds, and while allowing stuff to get out of bounds may have a use in some applications, it wouldn't be nice to have such feature in a pong game, so let's fix that:

private function enterFrame(e:Event):void {
        if (movingLeft) {       
                if (x - speed >= 0) { 
                        x -= speed;  
                }                
                else {           
                        x = 0;   
                }
        }

What we did is to check if the paddle will get out of the screen if it keeps moving left, and if so, instead of moving it by the value of the speed variable, we move it to x = 0 (the left border of the stage). 


An if...else block works like this: 
If the condition is met, the first code block will run. If not, it will run the code block after the 'else'.


Let's practice these 'else' blocks by adding movement to the right side.
Change the keyDownHandler function to the following:

private function keyDownHandler(e:KeyboardEvent):void {
                if (e.keyCode == 37 || e.keyCode == 65) { 
                        if (!movingLeft) {                
                                movingLeft = true;         
                        }
                }
                else if (e.keyCode == 39 || e.keyCode == 68) {  
                        if (!movingRight) {                 
                                movingRight = true;      
                        }
                }               
        }

Key codes 39 and 68 correspond to RIGHT and 'D'.
Go to the part where you declare variables and add a new boolean with name 'movingRight'.

private var movingRight:Boolean;

Now let's update the keyUpHandler and enterFrame function:

private function keyUpHandler(e:KeyboardEvent):void {
                 if (e.keyCode == 37 || e.keyCode == 65) {
                        if (movingLeft) {     
                              movingLeft = false; 
                        }
                 }
                  else if (e.keyCode == 39 || e.keyCode == 68) {
                        if (movingRight) {          
                              movingRight = false; 
                        }    
                    }
                 }


private function enterFrame(e:Event):void {
        if (movingLeft) {       
                if (x - speed >= 0) {
                        x -= speed; 
                }                
                else {          
                        x = 0;   
                }
        }
        else if (movingRight) {      
                if (x + speed + pic.width <= 600) { 
                        x += speed;  
                }                
                else {           
                        x = 600 - pic.width;  
                }
        }
}    

We just applied the same logic than before.
Test it. you should be able to control the paddle with arrow keys (left and right) or A and D.


That's pretty much it for this chapter. 
Just add the following function to the Paddle class:

private function die(e:Event):void {
        removeChild(pic);
        pic = null;
        stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
        stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
        removeEventListener(Event.ENTER_FRAME, enterFrame);
        removeEventListener(Event.REMOVED_FROM_STAGE, die);
       }

And this line below the ENTER_FRAME listener:


addEventListener(Event.REMOVED_FROM_STAGE, die, false, 0, true);

We'll get into details about the purpose of this function on the Garbage Collection chapter, but it's good to already have the code there se we don't need to edit all our classes once we reach that chapter.


Thanks for reading, I hope you're finding this tutorial useful and interesting. Feel free to leave comments. (:

 DOWNLOAD THE FILES: Click here


Suggested practices

Before moving on to the next chapter, it's suggested that you do the following exercise:

  • Make a new AS3 project.
  • Import three different graphics using the Embed metatag.
  • Create classes for each one and add them to the stage.
  • Add keyboard listeners to all of them.
  • First object should move left and right with LEFT and RIGHT keys.
  • Second object should move up and down with I and K.
  • Last object should move up, down, right and left with W,A,S and D. 

Chapter 0                                                   Chapter 2

    20 comments:

    1. Anonymous10.8.11

      Great tutorial. The suggested practices are somewhat challenging and interesting.

      And you cover the information well, thanks for these tutorials, they're really good, I hope you make alot >.>

      ReplyDelete
    2. Anonymous26.12.11

      These tutorials help me tremendously. The absolute best part about them is that at some points it will explain something clearly, and then never mention it again, so when it isn't clear at a certain point, you have to apply the information you've learned previously, and therefore get a better grasp on it.

      Thank you!

      ReplyDelete
    3. Anonymous28.12.11

      what do you draw with?

      ReplyDelete
    4. Anonymous4.1.12

      Really helpful tutorial. I have been searching the internet for tutorials on how to code with no prior knowledge of it, and this has been the only one that has truly helped me understand.
      Thank You! <3

      I hope you make plenty more

      ReplyDelete
    5. Anonymous4.1.12

      28.12.11, you draw with another program, like paint for windows. Then you can save that drawing into the lib folder. Hope this helps

      ReplyDelete
    6. I did use paint for some basic drawings. I have since downloaded and use GIMP (Graphics Image Manipulation Program). It is free as well as being a much more powerful graphics manipulation program.

      ReplyDelete
    7. Anonymous3.9.12

      i can not seem to find the lib folder

      ReplyDelete
    8. Anonymous5.11.12

      3.9.12, the lib folder is likely in C:\Users\yournamehere\Documents or wherever you created the project

      ReplyDelete
    9. Anonymous30.3.13

      not seeing the paddle and getting an error:

      Could not compile because the fcsh process could not be started.
      Build halted with errors (fcsh).
      INITIALIZING: Failed, unable to run compiler
      Done(1)

      can anyone help me with this?

      ReplyDelete
    10. Anonymous17.5.13

      private function go (e:Event = null) : void {
      ^
      Build halted with errors (fcsh).

      C:\Users\Lucas\Documents\New Project\src\Paddle.as(9): col: 26 Error: Type was not found or was not a compile-time constant: Event.

      ReplyDelete
    11. Anonymous17.5.13

      import flash.events.Event;

      ReplyDelete
    12. If you want to preview in Google Chrome instead of your default browser, go to Tools > Program Settings > FlashViewer. Then change External Player Path to C:\Users\\AppData\Local\Google\Chrome\Application\chrome.exe . Note that if you have a space in the path to your .as3proj file (spaces in the filename itself are fine) will result in a new tab for every "word" in the file path. For example, if you save it in C:\My Project\project.as3proj, it will open 2 tabs, C:\My and Project\bin\MyProject.swf

      ReplyDelete
    13. my pong keeps going to the right after pressed i tried to get it to sop doing that but i don't know what to do yet noob.

      ReplyDelete
      Replies
      1. Anonymous22.3.14

        You might have forgotten to set movingRight to false when the key is up.

        Delete
    14. Anonymous22.3.14

      Greetings from 2014! Great tutorial, helps a lot!

      ReplyDelete
    15. I see no 'lib' folder.

      ReplyDelete
      Replies
      1. Anonymous12.1.15

        Neither did I. I looked up what it was and it's supposed to be your library folder. All you have to do is make a new folder and naming it by right-clicking your project folder.

        Delete
    16. First off, I didn't see a 'lib' folder, so I just saved it in the project's folder.
      When running the program for the first time, I got this error:

      C:\Program Files (x86)\FlashDevelop\Flex\frameworks\flex-config.xml(56): Error: unable to open 'libs/player/10.1/playerglobal.swc'

      Build halted with errors (fcsh).

      What can I do to fix it?

      ReplyDelete
    17. Anonymous27.3.15

      Anyone else getting the 'libs/player/##.#/playerglobal.swc' issue, a temp fix is to edit the flex-config.xml and put in the correct folder name, rather than let the program calculate it. or rename the folder to what Flex determined it should be.

      ReplyDelete
    18. Felix6.6.15

      I solved the abovementioned problem after trying out some stuff. Here's how to fix it.

      1. Download latest flash debugger (mine is 17.0)
      2. Go to where you installed flexsdk
      3. Go to frameworks/libs/player
      4. Rename the folder with the highest value to whatever value your flash debugger is (mine is 17.0)
      5. Profit.

      ReplyDelete