B
H
0'
S
B
L
O
G
path: "/actionscript-flappy-bird-clone" title: "ActionScript Flappy BIrd Clone" published: true date: "14-07-2018"
Hello, in this tutorial we will learn how to clone the popular mobile game "Flappy Bird" using ActionScript [3] - also known as Flash (Flash is the runtime that the language ActionScript runs within).
This is a beginner friendly tutorial - assuming you have basic programming knowledge (data types, variables, for loops, if statements and functions/methods), Prior knowledge of ActionScript will help, otherwise prior knowledge of Javascript and/or Java since ActionScript is heavily influenced by these languages. I will produce a tutorial for getting started with Flash Development soon, but as an IDE you can use Adobe's FlashBuilder (I believe a trial version is available), or FlashDevelop (entirely free - and is what I use).
First, make sure you have a public class that extends "Sprite". And initialize then defined the following variables, and input the methods (functions) like I have done so in the code snippet below.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.display.Shape;
import flash.events.KeyboardEvent;
import flash.utils.setInterval;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* //// Flappy Bird [Clone] (ActionScript/Flash)
* @author bh0
*/
public class Main extends Sprite
{
/// Player aka Bird
public var playerSpeed:int;
public var playerGravity:Number;
public var playerVelocity:Number;
public var playerThrust:int;
public var score:int;
public var scoreText:TextField;
public var bird:Shape;
public var pipe1:Shape;
public var pipe2:Shape;
public function Main()
{
playerSpeed = 10; // player aka bird
playerGravity = 0.6; // 0.6
playerVelocity = 0;
playerThrust = 25; // 20 15
score = 0;
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
/// Draw Objects
/// Enter Game Loop
}
public function update():void {
/// Set (And Update) Score
/// Handle Bird's / Player's Positiong
/// Move Pipes
/// Player Successfully Avoided Pipes
/// Collision Detection
}
/// Movement
public function move(e:KeyboardEvent):void {
}
public function draw():void {
/// Bird
/// Score
/// Pipe/s (Pipe1 & Pipe2)
}
}
}
Inside our draw method, we draw two rectangles (the pipes) and a square (the bird), After our shapes are drawn, we add them to the "stage" (game-world) using the addChild function, notice that the colours are hexadecimal.
public function draw():void {
/// Bird
bird = new Shape();
bird.graphics.beginFill(0X00FFFF00, 0.5);
bird.graphics.drawRect(200, 200, 100, 100);
bird.graphics.endFill();
addChild(bird);
/// Score
// var scoreTextFormat:TextFormat = new TextFormat();
// scoreTextFormat.size = 130;
scoreText = new TextField();
// scoreText.setTextFormat(scoreTextFormat);
scoreText.x = 400;
scoreText.y = 200;
scoreText.textColor = 0X003E7091;
addChild(scoreText);
/// Pipe/s (Pipe1 & Pipe2)
pipe1 = new Shape();
pipe1.graphics.beginFill(0X00FF00, 0.5);
pipe1.graphics.drawRect(600, 0, 100, 160); // h: 100, y: 200 or 170
pipe1.graphics.endFill();
addChild(pipe1);
pipe2 = new Shape(); // these had to become independant for collision to work
pipe2.graphics.beginFill(0X00FF00, 0.5);
pipe2.graphics.drawRect(600, 400, 100, 160); // h: 100, y: 200 or 170
pipe2.graphics.endFill();
addChild(pipe2);
}
Then we call our draw function. method (which is only done once) inside the initialization ("init") method,
/// Draw Objects
draw();
A game loop in our case is one function (the update function) which will be called over and over again, forcing our game to update as if real-time events are occurring, I accomplished this using the setInterval function (JavaScripters will likely recognize this one), it essentially calls our update every 30 milliseconds.
We then call it inside our init function (after we have drawn our objects).
/// Enter Game Loop
setInterval(update, 30);
Inside our update function, we can begin handling the bird's position. The first set of instructions handle are bird's "flap" mechanic (though this won't actually work yet - but it will when we implement our input code). After this, we check if the bird fell off the screen and move it back to the top if so (optional). I suggest you play around with these variables to get a feel for what each one of them does.
/// Handle Bird's / Player's Positiong
playerVelocity += playerGravity;
playerVelocity *= 0.9;
bird.y += playerVelocity;
if (bird.y >= 480) { // 480 = bottom of game-area
bird.y = 0;
playerVelocity = 0;
}
Now we will make the bird "flap" each time the up arrow key is pressed, this is the code that will do that.
/// Movement
public function move(e:KeyboardEvent):void {
if (e.keyCode == 38) { // 38 = up arrow key
playerVelocity -= playerThrust;
}
}
Though this method will never get called unless we add an event-handler - a special function which automatically detects the input for us and calls a function of our choosing when the type of input it expects occurs, obviously we will call our move function. This code goes inside our "init" function.
// entry point
stage.addEventListener(KeyboardEvent.KEY_DOWN, move);
We should now be able to see the bird flap, We will move the pipes towards the left of the screen, check for a collision (if two objects are touching) between the pipe and the bird, and if there was no collision we will increase the bird's score. We will also adjust our object's positioning approrpiately.
/// Move Pipes
pipe1.x -= 2.4;
pipe2.x -= 2.4;
/// Player Successfully Avoided Pipes
if (pipe1.x <= -650 || pipe2.x <= -650) { // -650 = left side of game-area
pipe1.x = 270; // 270 = right side of game-area
pipe2.x = 270;
score += 1;
}
/// Collision Detection
if (bird.getBounds(stage).intersects(pipe1.getBounds(stage)) || bird.getBounds(stage).intersects(pipe2.getBounds(stage)) || bird.y >= stage.height - 200) {
bird.y = 200;
score = 0;
pipe1.x = 270;
pipe2.x = 270;
}
We have already implemented the scoring system, all we have to do now is make sure our score gets updated and is turned into a string so it can be displayed on the screen.
/// Set (And Update) Score
scoreText.text = score.toString();
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.display.Shape;
import flash.events.KeyboardEvent;
import flash.utils.setInterval;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* //// Flappy Bird [Clone] (ActionScript/Flash)
* @author bh0
*/
public class Main extends Sprite
{
/// Player aka Bird
public var playerSpeed:int;
public var playerGravity:Number;
public var playerVelocity:Number;
public var playerThrust:int;
public var score:int;
public var scoreText:TextField;
public var bird:Shape;
public var pipe1:Shape;
public var pipe2:Shape;
public function Main()
{
playerSpeed = 10; // player aka bird
playerGravity = 0.6; // 0.6
playerVelocity = 0;
playerThrust = 25; // 20 15
score = 0;
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
stage.addEventListener(KeyboardEvent.KEY_DOWN, move);
/// Draw Objects
draw();
/// Enter Game Loop
setInterval(main, 30);
}
public function main():void {
/// Set (And Update) Score
scoreText.text = score.toString();
/// Handle Bird's / Player's Positiong
playerVelocity += playerGravity;
playerVelocity *= 0.9;
bird.y += playerVelocity;
if (bird.y >= 480) { // 480 = bottom of game-area
bird.y = 0;
playerVelocity = 0;
}
/// Move Pipes
pipe1.x -= 2.4;
pipe2.x -= 2.4;
/// Player Successfully Avoided Pipes
if (pipe1.x <= -650 || pipe2.x <= -650) { // -650 = left side of game-area
pipe1.x = 270; // 270 = right side of game-area
pipe2.x = 270;
score += 1;
}
/// Collision Detection
if (bird.getBounds(stage).intersects(pipe1.getBounds(stage)) || bird.getBounds(stage).intersects(pipe2.getBounds(stage)) || bird.y >= stage.height - 200) {
bird.y = 200;
score = 0;
pipe1.x = 270;
pipe2.x = 270;
}
}
/// Movement
public function move(e:KeyboardEvent):void {
if (e.keyCode == 38) { // 38 = up arrow key
playerVelocity -= playerThrust;
}
}
public function draw():void {
/// Bird
bird = new Shape();
bird.graphics.beginFill(0X00FFFF00, 0.5);
bird.graphics.drawRect(200, 200, 100, 100);
bird.graphics.endFill();
addChild(bird);
/// Score
// var scoreTextFormat:TextFormat = new TextFormat();
// scoreTextFormat.size = 130;
scoreText = new TextField();
// scoreText.setTextFormat(scoreTextFormat);
scoreText.x = 400;
scoreText.y = 200;
scoreText.textColor = 0X003E7091;
addChild(scoreText);
/// Pipe/s (Pipe1 & Pipe2)
pipe1 = new Shape();
pipe1.graphics.beginFill(0X00FF00, 0.5);
pipe1.graphics.drawRect(600, 0, 100, 160); // h: 100, y: 200 or 170
pipe1.graphics.endFill();
addChild(pipe1);
pipe2 = new Shape(); // these had to become independant for collision to work
pipe2.graphics.beginFill(0X00FF00, 0.5);
pipe2.graphics.drawRect(600, 400, 100, 160); // h: 100, y: 200 or 170
pipe2.graphics.endFill();
addChild(pipe2);
}
}
}
Admittedly, I was not too sure Flash's coordinates system worked and were not sure about the dimensions of the stage (game-area/world), so this is something you can improve upon, perhaps using variables/properties to better represent such numbers. You could also make your code much more object-oriented and modular, I did attempt this but had issues rendering the objects, I intend on making a tutorial demonstrating how to use classes and instances in ActionScript (it is essentially the same as in Java) and hopefully at this point you can figure out how to solve/avoid the rendering issue/s I experienced.
Flash and ActionScript are technologies that used to be commonly used by "indie" game developers to make popular web-games, and since I love game development, I have always wanted to make a game using Flash/ActionScript - so this is a present to myself [as it happens to be my birthday this time of the month, partly a reason why I did not fuss on minor details.],