Array and Vector API Improvements

It’s not often you see updates to the ActionScript 3 class APIs these days, so I was pleasantly surprised to see that the AIR 19 beta introduces two new methods to the Vector and Array class:

  • insertAt()
  • removeAt()

They are intended as a replacement for the splice() method when you only want to add or remove a single element. So why use them over the splice() method? Well both methods make a change directly to the array or vector rather than creating and returning an altered version. They’ve been implemented with performance in mind and will perform better than the existing splice() methods.

To show the new APIs in action, here are two quick examples.

In the first example I add a score of 800 to the 2nd element of a vector of high scores:

var topScores :Vector.<int> = new <int>[1000, 500, 250, 100, 50];
topScores.insertAt(1, 800);
trace(topScores); // [1000, 800, 500, 250, 100, 50]

And in the second example I remove the lowest score from the array and trace it:

var topScores :Vector.<int> = new <int>[1000, 500, 250, 100, 50];
var lowest :int = topScores.removeAt(topScores.length - 1);
trace("The lowest score of " + lowest + " was removed.");

You can download the AIR 19 beta from Adobe Labs.

Building an HTML5 Flappy Bird clone with Adobe Animate CC: Part 4

Welcome to the fourth part of this HTML5 Flappy Bird tutorial series. In the previous post we implemented endless scrolling of our game’s ground layer. Today we’ll do the same for the pipes that our little hero must fly between.

What you will learn…

  • We’ll continue writing JavaScript directly within Adobe Animate CC
  • Some of the fundamentals of the CreateJS suite of JavaScript libraries
  • How to implement endless scrolling within your game world

What you will need…

  • A basic understanding of at least one programming language, such as JavaScript or ActionScript

In part three we wrote a Ground class that handles the scrolling of the game’s ground layer, and a Main class that acts as the game’s top-level entry point. Today we’ll take what we learned from scrolling the ground layer and write a new class that scrolls the game’s pipes. We’ll also hook our new class up to Main.

Before we start coding, it may be useful to remind yourself how the pipes look and behave within the final version of the Flappy Bird clone. Before proceeding, spend a few moments with the game: www.yeahbutisitflash.com/projects/flappy-animatecc/flappy.html.

Getting Started

You’ll need Adobe Animate CC. A trial version can be downloaded from www.adobe.com/products/animate.html. You’ll also need the FLA file you were working with in part three.

Now let’s get to work!

The Pipes Class

Launch Adobe Animate CC and open your FLA file.

Create a new timeline layer directly above the Ground class layer. Name the layer Pipes class and click on the first frame on its timeline. Open the Actions panel by selecting Window | Actions (F9) from the dropdown menu. Within the Actions panel, click on the Current frame tab and then click the Pin Script button to create a Pipes class tab. Okay, let’s write some JavaScript.

Our Pipes class will have a similar structure to the Ground class. It will have a constructor, two methods to start and stop scrolling, and an update method.

Add the following JavaScript to the Actions panel:

function Pipes()
{
  this.scrolling = false;
}

Pipes.prototype.startScrolling = function()
{
  this.scrolling = true;
}

Pipes.prototype.stopScrolling = function()
{
  this.scrolling = false;
}

Pipes.prototype.update = function()
{
  if (this.scrolling == true)
  {
    console.log("Pipes::update() scrolling");
  }
}

Our class won’t do much at the moment – it’ll simply write some text to the console when scrolling is taking place – but we’ll work on that soon enough. First let’s go ahead and wire it up to the Main class.

figure-1b

Figure 1. Selecting the Main class from the Script navigator.

As usual, we’ll open the Main class within the Actions panel. You can move to the Main class by selecting it from the Script Navigator, which is on the Action panel’s left-hand side. Within the navigator list you will see your Pipes, Ground, and Main classes. Click on the Main class and it will appear within the Script pane (Figure 1). Also, feel free to pin the class to the Actions panel.

Within your Main class, declare a member variable that holds an instance of our Pipes class:

function Main()
{
  this.ground = new Ground();
  this.pipes = new Pipes();
	
  exportRoot.screenFlash.visible = false;
  exportRoot.gameOverPrompt.visible = false;
  exportRoot.getReadyPrompt.visible = false;
  exportRoot.startInstructions.visible = false;
	
  canvas.onmousedown = this.userPressed.bind(this);
  window.onkeydown = this.userPressed.bind(this);
	
  createjs.Ticker.addEventListener("tick", this.update.bind(this));
}

Now ensure the pipes instance gets updated within the Main class’ update() method. Add the following line:

Main.prototype.update = function(evt)
{
  this.ground.update();
  this.pipes.update();
}

Finally, initiate scrolling of the pipes within the startGame() method:

Main.prototype.startGame = function()
{
  this.ground.startScrolling();
  this.pipes.startScrolling();
}

Let’s check that everything is working. Save your changes then test within the browser by selecting Control | Test Movie | In Browser (Cmd-Enter | Ctrl-Enter) from Animate CC’s dropdown menu. Click on the game’s viewport to initiate scrolling. Not only will the ground layer scroll across the screen but you should also see the following text being output to the JavaScript console:

> Pipes::update() scrolling

If you can see this then the Pipes class is working as expected and we can start fleshing it out.

Working with the Pipe Movie-Clips

Okay, now we can start thinking about using the actual pipe movie-clips sitting on the stage. As a quick reminder, take a look at the stage. If you unlock the Pipes layer on the timeline, you’ll find three pipes named pipe0, pipe1, and pipe2 respectively. The placement of these pipes on the stage is actually quite important.

The first pipe sits just outside the left of the stage, the second is positioned directly in the centre of the stage, and the third is just outside the stage’s right-hand side. The horizontal distance between the pipes is intentional: it’s the exact distance we want between every pipe that our little flappy bird will fly through.

Also, notice that each of the pipes has a different y-position. Again there’s a reason for this. Remember, as the user plays the game, each new pipe that appears will have a random y-position. However we do need to apply some constraints to these y-positions during play otherwise we run the risk of having gaps in some pipes that are impossible to reach. The pipe on the far-left has been used to indicate the highest vertical position that any of the pipes can be placed at during play. The pipe on the far-right has been used to indicate the lowest vertical position that any pipe can be placed at during play.

This means that if we wish to increase the distance between the pipes or the variation in y-positioning of each pipe then it’s simply a matter of changing things visually within the stage rather than having to find and alter any code.

Obtaining the Distance Between Pipes

Of course, our Pipes class needs to be able to determine these values by interrogating the stage when it’s first instantiated. Let’s add some code to do that. We’ll start by obtaining the distance between the pipes – we’ll deal with the vertical positioning in a moment. Add the following line to your class’ constructor:

function Pipes()
{
  this.scrolling = false;
	
  this.distanceBetweenPipes = exportRoot.pipe1.x - exportRoot.pipe0.x;
}

Calculating the distance is a simple case of subtracting the first pipe’s x-position from the second’s. We’ve stored that value within a member variable named distanceBetweenPipes allowing us to access it throughout the class.

Obtaining the Left Bounds

In order to manage the scrolling of the pipes we’ll need to know when a pipe has scrolled off the screen. We can use the pipe’s width to calculate the x-position it will be at once it has fully scrolled off the screen:

function Pipes()
{
  this.scrolling = false;
	
  this.distanceBetweenPipes = exportRoot.pipe1.x - exportRoot.pipe0.x;
  this.leftBound = -exportRoot.pipe0.nominalBounds.width;
}
The nominalBounds property returns the bounding rectangle for a movie-clip’s first frame. From that we retrieved the width of our pipe. The bounding rectangle that is returned represents the author-time dimensions and therefore does not reflect any changes made to the movie-clip at runtime. Since we don’t apply any changes in scale to our pipes at runtime, this is fine, and we can safely obtain the width knowing that it will be correct.

Obtaining the Minimum and Maximum Vertical Positions

Now let’s store the minimum and maximum vertical positions that our pipes can be at. Declare the following two member variables:

function Pipes()
{
  this.scrolling = false;
	
  this.distanceBetweenPipes = exportRoot.pipe1.x - exportRoot.pipe0.x;
  this.leftBound = -exportRoot.pipe0.nominalBounds.width;
	
  this.maxPipeY = exportRoot.pipe0.y;
  this.minPipeY = exportRoot.pipe2.y;
}

Referencing All Three Pipes

And since we’ll be scrolling all three pipes across the screen, we’ll store each within an array that we can easily access:

function Pipes()
{
  this.scrolling = false;
	
  this.distanceBetweenPipes = exportRoot.pipe1.x - exportRoot.pipe0.x;
  this.leftBound = -exportRoot.pipe0.nominalBounds.width;

  this.maxPipeY = exportRoot.pipe0.y;
  this.minPipeY = exportRoot.pipe2.y;

  this.pipes = [exportRoot.pipe0, exportRoot.pipe1, exportRoot.pipe2];
}

As with the ground slices, the order the pipes are stored within the array is important. The left-most pipe should be at the front of the array, while the right-most pipe should be at the back.

Scrolling the Pipes

We’re now in a position to write the code to actually scroll the pipes, which is almost identical to the code we wrote for the ground slices.

Within our update() method we’ll call two methods: updatePipePositions() and checkLeftPipeIsOutsideScreen(). Add the following two lines and also remove the log() statement that’s there:

Pipes.prototype.update = function()
{
  if (this.scrolling == true)
  {
    console.log("Pipes::update() scrolling");
    this.updatePipePositions();
    this.checkLeftPipeIsOutsideScreen();
  }
}

Now add the following two methods to the class:

Pipes.prototype.updatePipePositions = function()
{
  for (var i = 0; i < this.pipes.length; i++)
  {
    var pipe = this.pipes[i];
    pipe.x -= Main.SCROLL_SPEED;
  }
}

Pipes.prototype.checkLeftPipeIsOutsideScreen = function()
{
  var leftMostPipe = this.pipes[0];
  var rightMostPipe = this.pipes[2];
  if (leftMostPipe.x < this.leftBound)
  {
    leftMostPipe.x = rightMostPipe.x + this.distanceBetweenPipes;
    this.pipes.shift();
    this.pipes.push(leftMostPipe);
  }
}

Save your changes and republish the project. Test everything in a browser. You should now see the pipes scrolling along with the ground. When each pipe moves outside the left-hand side of the screen, a new one will appear from the right. This is the exact same behaviour as the slices that make up our ground layer.

Random Vertical Positions

At the moment the vertical position of each pipe doesn’t change. However, when each new pipe appears from the right we want to set a random y-position for it to make the game more challenging. Let’s go ahead and write some code to randomly set the y-position of each new pipe.

Add the following method at the end of your class:

Pipes.prototype.setRandomYPosition = function(pipe)
{
  var delta = this.minPipeY - this.maxPipeY;
  pipe.y = this.maxPipeY + Math.round(Math.random() * delta);
}

The method above takes a pipe as a parameter and randomly sets its y-position somewhere between the minimum and maximum vertical positions that were set within the constructor.

Now that we’ve defined this method let’s actually use it. Make a call to setRandomYPosition() from within your checkLeftPipeIsOutsideScreen() method and pass the pipe that has just moved off the screen to it:

Pipes.prototype.checkLeftPipeIsOutsideScreen = function()
{
  var leftMostPipe = this.pipes[0];
  var rightMostPipe = this.pipes[2];
  if (leftMostPipe.x < this.leftBound)
  {
    leftMostPipe.x = rightMostPipe.x + this.distanceBetweenPipes;
    this.setRandomYPosition(leftMostPipe);
    this.pipes.shift();
    this.pipes.push(leftMostPipe);
  }
}

The above change sets a random y-position to the pipe immediately after it’s re-positioned outside the screen’s right-hand side.

Let’s try our latest changes in the browser. Save everything and republish. After clicking the screen you should see that each new pipe that enters the screen now has a random y-position.

The Pipes Starting Position

We’re almost done with the Pipes class for the time being. However you may have noticed that our game currently begins with a pipe already on the screen. This is going to make things quite tricky for the player so let’s write some code to reposition all three pipes outside the right-hand side of the screen to begin with. We’ll also set an initial random y-position for each of the three pipes. And since we’ll need to reset the position of the pipes each time a new game is started, let’s also declare our array of pipe references within our new method too rather than doing it only once within the constructor.

Add the following method at the end of your class:

Pipes.prototype.setupStartPosition = function()
{
  this.pipes = [exportRoot.pipe0, exportRoot.pipe1, exportRoot.pipe2];

  for (var i = 0; i < this.pipes.length; i++)
  {
    var pipe = this.pipes[i];
    pipe.x = (lib.properties.width * 1.5) + (i * this.distanceBetweenPipes);
    this.setRandomYPosition(pipe);
  }
}

It’s fairly straightforward. We use a for-loop to walk through our array of pipes. Within that loop we set the x-position and apply a random y-position to each pipe. Both the stage width and the distance between pipes is used when calculating each pipe’s initial x-position. This will ensure that each pipe sits outside the screen’s right-hand side when the game begins, and also ensure they have the correct gap between them. We actually use one and a half times the stage width to make an even larger gap between the bird and the first pipes. This will give the player just a little more breathing space when they start each new game.

The stage width itself is determine by querying the global lib variable, which contains an object named properties. This object contains a number of properties used to describe your stage including width, height, fps, and color.

With the setupStartPosition() in place, call it from your constructor and also remove the declaration for the pipes member variable since it’s now handled within setupStartPosition():

function Pipes()
{
  this.scrolling = false;
	
  this.distanceBetweenPipes = exportRoot.pipe1.x - exportRoot.pipe0.x;
  this.leftBound = -exportRoot.pipe0.nominalBounds.width;
	
  this.maxPipeY = exportRoot.pipe0.y;
  this.minPipeY = exportRoot.pipe2.y;
	
  this.pipes = [exportRoot.pipe0, exportRoot.pipe1, exportRoot.pipe2];
  this.setupStartPosition();
}

Save and republish. Now when you run the game from the browser you’ll notice that there is no longer a pipe sitting on the stage. When you click, the first pipe will now scroll in from outside the screen and also have a random y-position. This is exactly what we want!

Summary

That’s us finished with the scrolling of the ground layer and the pipes. We’ve seen how easy it is to write JavaScript that interacts with the stage’s contents to create an endless scrolling effect.

Next time we’ll simulate physics within our game world and get our little hero flapping. See you then.

Christopher Caleb

ccaleb
Christopher Caleb is a freelance developer and published author. His body of work spans a wide range of projects that encompass casual games, interactive kiosks, social networks, and mobile applications. Christopher’s expertise covers both native and cross-platform technologies, with a focus on optimisation within hardware constraints. He specialises in delivering highly engaging experiences with usability being a primary concern.

He blogs at www.yeahbutisitflash.com and tweets as @chriscaleb.

iOS Concurrency

The beta release of Adobe AIR 19 has landed and the big news is that we finally have the AS3 Workers API for iOS.

So what are Workers? Well put simply, Workers lets us create multi-threaded AIR and Flash Player applications. This is significant because you can finally relegate CPU intensive tasks to a background worker thread while your main application thread continues to do its own thing. So for example, you could write code to perform some heavy image processing in the background without your app’s UI being blocked. In fact, this is one of the primary reasons for using workers: to ensure your app’s user interface and animation stay as smooth as possible even when there’s a lot of processor intensive code being run.

You can find the API documentation for the Worker class on Adobe’s official AS3 Language Reference site. There’s also the Introducing Concurrency on iOS article on the Adobe Developer Connection website, which will help you get started.

And if you want a more detailed introduction to workers then take a look at Shawn Blais’s excellent tutorial on the subject. Part three is particularly interesting as Shawn shows the Nape physics engine running in a separate thread to guarantee a silky smooth 60 frames-per-second simulation.

You can download the AIR 19 beta from Adobe Labs.

Video: Intro to Flash Pro’s WebGL Runtime API

The video from my Introduction to Flash Professional’s WebGL Runtime API webinar is now available.

The encoding for the video unfortunately looks a bit wonky in places but I’ve provided the slides from the presentation below so you should be able to follow along with the audio.

In addition, the FLA and source code from the presentation is available on GitHub. You’ll find the original JavaScript version of the code that I ran through during the webinar and there’s also a bonus TypeScript implementation in there too. Oh and a big thanks to Robert Penner for the improvements to my TypeScript code.

Finally, here’s a link to the running version of the actual WebGL content that I produced during the webinar.

Thanks once again to everyone who attended!

Code: Intro to Flash’s WebGL Runtime API

I’ve placed the example source code from yesterday’s webinar on GitHub. You’ll find the original FLA file complete with the JavaScript source code (it’s inside bunny.html). As an added bonus I’ve also included a TypeScript version of the example.

You can find the repository here: https://github.com/ccaleb/flash-webgl-intro

And here’s a link to a running version of the code.

Slides: Intro to Flash’s WebGL Runtime API

Thanks to everyone who attended today’s webinar about Flash Professional’s WebGL Runtime API. Here are the slides from today.

Unfortunately I ran out of time and had to quickly skip over most of my content on ECMAScript 6 and TypeScript. If you’d like to know more though then please visit the links listed at the end of the presentation.

Webinar: Intro to Flash’s WebGL Runtime API

On June 17th (8:00AM PST) I’ll be presenting a one hour webinar on Flash Professional’s WebGL Runtime API. If you’d like to find out how to create interactive Flash content that will run on both desktop and mobile browsers then it might be worth dropping by.

I’ll be walking through the steps required to build an interactive Flash animation, covering the basics of Flash’s WebGL Runtime API and also showing how visual content is constructed and exported. During the session I’ll be jumping between JavaScript coding and some good ol’ timeline work, so whether you’re a developer or designer, there should be something that piques your interest.

You can find out more details and check your local time from Adobe’s Flash Professional Team Blog.

Making HTML5 Games using Flash Professional

Colin Holgate from Funny Garbage recently presented his experience of creating HTML5 games using Flash Professional.

As Colin demonstrates, anyone wanting to target HTML5 while using the familiar Flash workflow can easily do that using Flash’s HTML5 Canvas document type. And as you can see from the video, the end results are quite impressive.

TestFlight and Build Numbers

If you’ve been uploading builds to TestFlight you’ll no doubt have noticed that you need to increment your app’s version number each time you want to deploy a new build. Annoyingly Adobe AIR’s <versionNumber> tag has always populated both the CFBundleShortVersionString and CFBundleVersion keys in the iOS info.plist file, meaning there was no way to simply update the build number while keeping the app’s version number the same.

Thankfully the recently released AIR 18 beta SDK fixes this issue by providing you with a <versionNumber> and a <versionLabel> tag. The <versionNumber> tag is used to update the build number, while <versionLabel> is used for the app’s actual version number. So if you’re only making a minor update to your app you can now simply update its build number rather than the version number.

You can download the AIR 18 Beta from Adobe Labs. The release notes are available from here.

PixiJS Version 3 Released

PixiJS has got to be my favourite JavaScript 2D rendering engine. It’s awesome! So I was pretty damn pleased to find out that a new major version has just been released by Mat Groves.

pixiv3-logo

A lot has changed including a new modular architecture and increased focus on WebGL rendering. With WebGL now available across a wide range of mobile devices it’s great to see Pixi being architected in such a way to ensure that the WebGL side of things is as efficient as possible. Also, for those targeting multiple screen resolutions (who isn’t these days), PixiJS v3 has a new resolution manager making it easier to work across different resolutions and pixel densities.

A new version of the official site will be coming soon along with documentation and example code. In the meantime you can find out more on Mat’s blog and grab the latest version from GitHub. In fact, there are some impressive demos on Mat’s blog showing off just what v3 is capable of.