Jun 28, 2012
Posted on Jun 28, 2012 in Hints and Tips | 10 comments
In this tutorial, we’ll take a basic browser game (which we built in a Tuts+ Premium tutorial), and add progress bars, a preloader, a splash screen, and a lot more polish.
Introduction
In this Tuts+ Premium tutorial, we built a basic card matching game with JavaScript, whose images came from Flickr. Check out the demo:

Click to try the game as it is now.
In this tutorial, we’ll add a lot of polish to the game, by implementing a preloader and progress bar, a splash screen, and a keyword search. Take a look at how the game will turn out:

Click to try the game with the improvements we’ll be adding.
In this tutorial, you’ll learn the JavaScript and HTML necessary to code all these improvements. Download the source files and extract the folder called StartHere; this contains all the code from the end of the Premium tutorial.
In flickrgame.js there is a function called preloadImage(), which contains this line:
tempImage.src = flickrGame.tempImages[i].imageUrl;
For the purposes of testing, change it to:
tempImage.src = "cardFront.jpg";
This will show the images on the cards all the time, which makes testing a lot easier. You can change this back at any time.
Now, read on!
Step 1: addKeyPress()
Right now we have the tag “dog” hard coded, but the game will get boring quickly if we force the user to use dog photos all the time!
The search input has been sitting there looking pretty, but being totally non-functional all this time. Let’s fix that. We will listen for the user to hit the Enter key and then call the doSearch() method using whatever they typed in to call the Flickr API.
Add the following beneath the resetImages() function, in flickrgame.js.
function addKeyPress() {
$(document).on("keypress", function (e) {
if (e.keyCode == 13) {
doSearch();
}
});
}
Here we listen for a keypress and if the keyCode is equal to 13, we know they pressed the Enter key so we call the doSearch() function.
We need to modify the doSearch function to use the text in the input, so make the following changes:
function doSearch() {
if ($("#searchterm").val() != "") {
$(document).off("keypress");
var searchURL = "http://api.flickr.com/services/rest/?method=flickr.photos.search";
searchURL += "&api_key=" + flickrGame.APIKEY;
searchURL += "&tags=" + $("#searchterm").val();
searchURL += "&per_page=36"
searchURL += "&license=5,7";
searchURL += "&format=json";
searchURL += "&jsoncallback=?";
$.getJSON(searchURL, setImages);
}
}
Here, we first check that the input is not empty (we don’t want to search for nothing), then we remove the keypress listener. Finally, we alter the tags to use the input’s value.
The last thing we need to do is remove the call to doSearch() in the JS file. Find where we are manually calling doSearch() and remove it. (It’s right after the addKeyPress() function.)
Dont forget to actually call the addKeyPress() function. I called it right beneath where I declared it.
function addKeyPress() {
$(document).on("keypress", function (e) {
if (e.keyCode == 13) {
doSearch();
}
});
}
addKeyPress();
Now if you test the game you wont see any images until you do a search.
Step 2: Contacting Server
When we make our first call to Flickr’s API there is a slight delay. We will show an animated GIF (a “throbber”) while we contact the server, and remove it once the call comes back.
Add the following to the doSearch() function.
function doSearch() {
if ($("#searchterm").val() != "") {
$(document).off("keypress");
$("#infoprogress").css({
'visibility': 'visible'
});
var searchURL = "http://api.flickr.com/services/rest/?method=flickr.photos.search";
searchURL += "&api_key=" + flickrGame.APIKEY;
searchURL += "&tags=" + $("#searchterm").val();
searchURL += "&per_page=36"
searchURL += "&license=5,7";
searchURL += "&format=json";
searchURL += "&jsoncallback=?";
$.getJSON(searchURL, setImages);
}
}
This sets the #infoprogress div to be visible. Once the information comes back from Flickr, we will hide it. To do so, add the following code to the setImages() function:
function setImages(data) {
$("#infoprogress").css({
'visibility': 'hidden'
});
$.each(data.photos.photo, function (i, item) {
var imageURL = 'http://farm' + item.farm + '.static.flickr.com/' + item.server + '/' + item.id + '_' + item.secret + '_' + 'q.jpg';
flickrGame.imageArray.push({
imageUrl: imageURL,
photoid: item.id
});
});
infoLoaded();
}
If you test the game now, you should see the loader image show while contacting the Flickr API.
Step 3: Get Photo Info
We need to get the information for each photo we use. We will call the method=flickr.photos.getInfo on each photo, and then call the infoLoaded() function every time the information is loaded. Once the information for every photo has loaded, the game continues as before.
There is a lot of new information to take in here, so we will break it down step by step. First, add the following to the setImages() function:
function setImages(data) {
$("#infoprogress").css({
'visibility': 'hidden'
});
if (data.photos.photo.length >= 12) {
$("#searchdiv").css({
'visibility': 'hidden'
});
$.each(data.photos.photo, function (i, item) {
var imageURL = 'http://farm' + item.farm + '.static.flickr.com/' + item.server + '/' + item.id + '_' + item.secret + '_' + 'q.jpg';
flickrGame.imageArray.push({
imageUrl: imageURL,
photoid: item.id
});
var getPhotoInfoURL = "http://api.flickr.com/services/rest/?method=flickr.photos.getInfo";
getPhotoInfoURL += "&api_key=" + flickrGame.APIKEY;
getPhotoInfoURL += "&photo_id=" + item.id;
getPhotoInfoURL += "&format=json";
getPhotoInfoURL += "&jsoncallback=?";
$.getJSON(getPhotoInfoURL, infoLoaded);
});
} else {
alert("NOT ENOUGH IMAGES WERE RETURNED");
addKeyPress();
}
flickrGame.numberPhotosReturned = flickrGame.imageArray.length;
}
Now that we are getting the tags from the user we should make sure enough images were returned to make up a single game (12). If so, we hide the input so the player can’t do another search mid-game. We set a variable getPhotoInfoURL and use the method=flickr.photos.getInfo – notice that we are using the item.id for the photo_id. We then use the jQuery’s getJSON method, and call infoLoaded.
If not enough images were returned, we throw up an alert and call addKeyPress() so the user can do another search.
So we need to know how many images were returned from the call to the Flickr API, and we store this in the variable numberPhotosReturned, which we add to our flickrGame object:
var flickrGame = {
APIKEY: "76656089429ab3a6b97d7c899ece839d",
imageArray: [],
tempImages:[],
theImages: [],
chosenCards: [],
numberPhotosReturned: 0
}
(Make sure you add a comma after chosenCards: [].)
We cannot test just yet; if we did we would be calling preloadImages() 36 times in a row since that is all our infoLoaded() function does at the moment. Definitely not what we want. In the next step we will flesh out the infoLoaded() function.
Step 4: infoLoaded()
The infoLoaded() function receives information about a single photo. It adds the information to the imageArray for the proper photo, and keeps track of how many photos’ info have been loaded; if this number is equal to numberPhotosReturned, it calls preloadImages().
Delete the call to preloadImages() and put the following inside the infoLoaded() function:
flickrGame.imageNum += 1;
var index = 0;
for (var i = 0; i < flickrGame.imageArray.length; i++) {
if (flickrGame.imageArray[i].photoid == data.photo.id) {
index = i;
flickrGame.imageArray[index].username = data.photo.owner.username;
flickrGame.imageArray[index].photoURL = data.photo.urls.url[0]._content;
}
}
if (flickrGame.imageNum == flickrGame.numberPhotosReturned) {
preloadImages();
}
}
Here we increment the imageNum variable and set a variable index equal to 0. Inside the for loop we check to see if the photoid in the imageArray is equal to the data.photo.id (remember the data is a JSON representation of the current image being processed). If they do match we set index equal to i and update the appropriate index in the imageArray with a username and photoURL variable. We’ll need this information when we show the image attributions later.
This might seem a bit confusing, but all we are doing is matching up the photos. Since we don’t know the order in which they will be returned from the server we make sure their id’s match, and then we can add the username and photoURL variables to the photo.
Lastly, we check if imageNum is equal to the numberPhotosReturned, and if it is then all images have been processed so we call preloadImages().
Don’t forget to add the imageNum to the flickrGame object.
var flickrGame = {
APIKEY: "76656089429ab3a6b97d7c899ece839d",
imageArray: [],
tempImages:[],
theImages: [],
chosenCards: [],
numberPhotosReturned: 0,
imageNum: 0
}
(Make sure you add a comma after the numberPhotosReturned: 0.)
If you test now it will take a little longer for you to see the photos. On top of calling the Flickr API to retrieve the photos, we are now getting information about each one of them.
Step 5: Progress Bar for Photo Info
In this step we will get the progress bar showing when we load the photo information.
Add the following code to the setImages() function:
function setImages(data) {
$("#infoprogress").css({
'visibility': 'hidden'
});
$("#progressdiv").css({
'visibility': 'visible'
});
$("#progressdiv p").text("Loading Photo Information");
if (data.photos.photo.length >= 12) {
$("#searchdiv").css({
'visibility': 'hidden'
});
$.each(data.photos.photo, function (i, item) {
var imageURL = 'http://farm' + item.farm + '.static.flickr.com/' + item.server + '/' + item.id + '_' + item.secret + '_' + 'q.jpg';
flickrGame.imageArray.push({
imageUrl: imageURL,
photoid: item.id
});
var getPhotoInfoURL = "http://api.flickr.com/services/rest/?method=flickr.photos.getInfo";
getPhotoInfoURL += "&api_key=" + flickrGame.APIKEY;
getPhotoInfoURL += "&photo_id=" + item.id;
getPhotoInfoURL += "&format=json";
getPhotoInfoURL += "&jsoncallback=?";
$.getJSON(getPhotoInfoURL, infoLoaded);
});
} else {
$("#progressdiv").css({
'visibility': 'hidden'
});
alert("NOT ENOUGH IMAGES WERE RETURNED");
addKeyPress();
}
flickrGame.numberPhotosReturned = flickrGame.imageArray.length;
}
This shows the #progressdiv and changes the paragraph’s text within the #progressdiv to read “Loading Photo Information”. If not enough images were returned we hide the #progressdiv.
Next add the following to the infoLoaded() function:
function infoLoaded(data) {
flickrGame.imageNum += 1;
var percentage = Math.floor(flickrGame.imageNum / flickrGame.numberPhotosReturned * 100);
$("#progressbar").progressbar({
value: percentage
});
var index = 0;
for (var i = 0; i < flickrGame.imageArray.length; i++) {
if (flickrGame.imageArray[i].photoid == data.photo.id) {
index = i
flickrGame.imageArray[index].username = data.photo.owner.username;
flickrGame.imageArray[index].photoURL = data.photo.urls.url[0]._content;
}
}
if (flickrGame.imageNum == flickrGame.numberPhotosReturned) {
preloadImages();
}
}
Here we set a variable percentage equal to Math.floor(flickrGame.imageNum / flickrGame.numberPhotosReturned * 100); this makes sure we get a number between 0 and 100. Then we call $("#progressbar").progressbar() and set the value property equal to percentage.
Now if you test the game it should work just as before, but with a progress bar. Well, there is one problem: the progress bar sticks around after the images get drawn. In the game we first load the photo information, then we preload the images and both use the progress bar. We will fix this in the next step.
Step 6: Preloading the Images
In this step we will utlilize the jQuery.imgpreload plugin (it’s already in the source download). As soon as all the file information from the above steps has been loaded, the progress bar resets itself and monitors the loading of the images.
Add the following to the preloadImages() function:
function preloadImages() {
flickrGame.tempImages = flickrGame.imageArray.splice(0, 12);
for (var i = 0; i < flickrGame.tempImages.length; i++) {
for (var j = 0; j < 2; j++) {
var tempImage = new Image();
tempImage.src = "cardFront.png";
tempImage.imageSource = flickrGame.tempImages[i].imageUrl;
flickrGame.theImages.push(tempImage);
}
}
$("#progressdiv").css({
'visibility': 'visible'
});
$("#progressdiv p").text("Loading Images");
var tempImageArray = [];
for (var i = 0; i < flickrGame.tempImages.length; i++) {
tempImageArray.push(flickrGame.tempImages[i].imageUrl);
}
$.imgpreload(tempImageArray, {
each: function () {
if ($(this).data('loaded')) {
flickrGame.numImagesLoaded++;
var percentage = Math.floor(flickrGame.numImagesLoaded / flickrGame.totalImages * 100);
$("#progressbar").progressbar({
value: percentage
});
}
},
all: function () {
$("#progressdiv").css({
'visibility': 'hidden'
});
drawImages();
}
});
}
Here we set the #progressdiv to be visible and change the paragraph to read “Loading Images”. We set up a temporary array and add the temporary images’ URLs to it, then pass the entire array to $.imgpreload to kick off the preload.
The each function gets run each time a photo is preloaded, and the all function gets run when all the images have been preloaded. Inside each() we check to make sure the image actually was loaded, increment the numImagesLoaded variable, and use the same method for the percentage and progress bar as before. (The totalImages is 12 since that how many we are using per game.)
Once all the images have been preloaded (that is, when all() is run) we set the #progessdiv to hidden and call the drawImages() function.
We need to add the numImagesLoaded and totalImages variables to our flickrGame object:
var flickrGame = {
APIKEY: "76656089429ab3a6b97d7c899ece839d",
imageArray: [],
tempImages:[],
theImages: [],
chosenCards: [],
numberPhotosReturned: 0,
imageNum: 0,
numImagesLoaded: 0,
totalImages: 12
}
(Make sure you add the comma after imageNum.)
If you test the game now, you should see the progress bar for both the photo information and for the preloading of the images.
Step 7: Showing the Attributions
To conform to the Flickr API terms of service, we have to show attributions for the images we use. (It’s also polite to do so.)
Add the following code within the hideCards() function:
function hideCards() {
$(flickrGame.chosenCards[0]).animate({
'opacity': '0'
});
$(flickrGame.chosenCards[1]).animate({
'opacity': '0'
});
flickrGame.theImages.splice(flickrGame.theImages.indexOf(flickrGame.chosenCards[0]), 1);
flickrGame.theImages.splice(flickrGame.theImages.indexOf(flickrGame.chosenCards[1]), 1);
$("#image1").css('background-image', 'none');
$("#image2").css('background-image', 'none');
if (flickrGame.theImages.length == 0) {
$("#gamediv img.card").remove();
$("#gamediv").css({
'visibility': 'hidden'
});
showAttributions();
}
addListeners();
flickrGame.chosenCards = new Array();
}
Here, we check if the number of images left is zero, and if so we know the user has matched all of the cards. We therefore remove all the cards from the DOM and set the #gamediv to be hidden. Then, we call the showAttributions() function which we will code next.
Step 8: Show Attributions
In this step we will code the showAttributions() function.
Add the following beneath the checkForMatch() function you coded in the steps above:
function showAttributions() {
$("#attributionsdiv").css({
'visibility': 'visible'
});
$("#attributionsdiv div").each(function (index) {
$(this).find('img').attr('src', flickrGame.tempImages[index].imageUrl).
next().html('<span>Username: </span> ' + flickrGame.tempImages[index].username + '<br/>' + '<a href="' + flickrGame.tempImages[index].photoURL + '"target="_blank">View Photo</a>');
});
}
Here we set the #attributionsdiv to be visible, and then loop through each div within it. There are 12 divs, each with an image and a paragraph; we use jQuery’s find() method to find the img within the div, set the src of the image to the correct imageUrl, and use jQuery’s next() method to set the username and photoURL to the info from Flickr.
Here are links to jQuery’s find() and next() methods so you can learn more about them.
If you test the game now and play through a level, you’ll see the attributions with a link to the image on Flickr. You will also see two buttons: one for the next level and one for a new game. We will get these buttons working in the next steps.
Step 9: Next Level
In our call to the Flickr API we set per_page to 36, to request that many images at once. Since we are using 12 images per game, this means that there can be up to three levels. In this step we will get the Next Level button working.
Add the following code within the setImages() function:
function setImages(data) {
// ... snip ...
flickrGame.numberPhotosReturned = flickrGame.imageArray.length;
flickrGame.numberLevels = Math.floor(flickrGame.numberPhotosReturned / 12);
}
We need to know how many levels the game will have. This depends on how many images were returned from our search. It will not always be 36. For example, I searched for “hmmmm” and it returned about 21 photos at the time. We’ll use Math.floor() to round the number down – we don’t want 2.456787 levels, after all, and it would throw the game logic way off.
Make sure you add the numberLevels variable to the flickrGame object:
var flickrGame = {
APIKEY: "76656089429ab3a6b97d7c899ece839d",
imageArray: [],
tempImages:[],
theImages: [],
chosenCards: [],
numberPhotosReturned: 0,
imageNum: 0,
numImagesLoaded: 0,
totalImages: 12,
numberLevels: 0
}
(Don’t forget to add the comma after totalImages: 12.)
Now modify the drawImages() function as follows:
function drawImages() {
flickrGame.currentLevel += 1;
$("#leveldiv").css({
'visibility': 'visible'
}).html("Level " + flickrGame.currentLevel + " of " + flickrGame.numberLevels);
flickrGame.theImages.sort(randOrd);
for (var i = 0; i < flickrGame.theImages.length; i++) {
$(flickrGame.theImages[i]).attr("class", "card").appendTo("#gamediv");
}
addListeners();
}
Here we increment the currentLevel variable, set the #leveldiv to be visible and set the HTML of the div to read what level we are on and how many levels there are.
Once again, we need to add the currentLevel variable to our flickrGame object.
var flickrGame = {
APIKEY: "76656089429ab3a6b97d7c899ece839d",
imageArray: [],
tempImages:[],
theImages: [],
chosenCards: [],
numberPhotosReturned: 0,
imageNum: 0,
numImagesLoaded: 0,
totalImages: 12,
numberLevels: 0,
currentLevel: 0
}
(I’m sure you don’t need reminding by now, but make sure you add the comma after numberLevels: 0.)
Now modify the showAttributions() function to the following:
function showAttributions() {
$("#leveldiv").css({
'visibility': 'hidden'
});
$("#attributionsdiv").css({
'visibility': 'visible'
});
if (flickrGame.currentLevel == flickrGame.numberLevels) {
$("#nextlevel_btn").css({
'visibility': 'hidden'
});
} else {
$("#nextlevel_btn").css({
'visibility': 'visible'
});
}
$("#attributionsdiv div").each(function (index) {
$(this).find('img').attr('src', flickrGame.tempImages[index].imageUrl);
$(this).find('p').html('<span>Username: </span> ' + flickrGame.tempImages[index].username + '<br/>' + '<a href="' + flickrGame.tempImages[index].photoURL + '"target="_blank">View Photo</a>');
});
}
We hide the #leveldiv by setting its visibility to hidden.
Next we check whether the currentLevel is equal to the numberLevels. If they are equal, there are no more levels available so we hide the #nextlevel_btn; otherwise, we show it.
Finally we need to wire up the #nextlevel_btn. Add the following code beneath the addKeyPress() function you created in the step above:
$("#nextlevel_btn").on("click", function (e) {
$(this).css({
'visibility': 'hidden'
});
$("#gamediv").css({
'visibility': 'visible'
});
$("#attributionsdiv").css({
'visibility': 'hidden'
});
flickrGame.numImagesLoaded = 0;
preloadImages();
});
Here we hide the button, reveal the #gamediv, hide the #attributionsdiv, reset the numImagesLoaded variable, and call preloadImages() which grabs the next 12 images.
You can test the game now and should be able to play through all the levels. We will wire up the #newgame_btn in the coming steps.
Step 10: Starting a New Game
You can begin a new game at any time, but after all the levels have been played that is the only option. In this step we will wire up the #newgame_btn.
Add the following beneath the code for the #nextlevel_btn you added in the step above:
$("#newgame_btn").on("click", function (e) {
$("#gamediv").css({
'visibility': 'visible'
});
$("#leveldiv").css({
'visibility': 'hidden'
});
$("#attributionsdiv").css({
'visibility': 'hidden'
});
$("#searchdiv").css({
'visibility': 'visible'
});
$("#nextlevel_btn").css({
'visibility': 'hidden'
});
flickrGame.imageNum = 0;
flickrGame.numImagesLoaded = 0;
flickrGame.imageArray = new Array();
flickrGame.currentLevel = 0;
flickrGame.numberLevels = 0;
addKeyPress();
});
Here we reveal the #gamediv, hide the #leveldiv and #attributionsdiv, reveal the #searchdiv, and hide the #nextlevel_btn. We then reset some variables, and call addKeyPress() so the user can search again.
If you test now you should be able to start a new game at any time, as well as when all levels have been played.
The game is complete as far as gameplay is concerned, but we need to show a splash screen. We’ll do this in the next step.
Step 11: Splash Screen
We need to make some changes to our CSS file. Specifically, we need to set the #gamediv visibility to hidden, and set the #introscreen to visible. Open styles/game.css and make those changes now:
#gamediv {
position:absolute;
left:150px;
width:600px;
height:375px;
border: 1px solid black;
padding:10px;
color:#FF0080;
visibility:hidden;
background: #FFFFFF url('../pattern.png');
}
#introscreen{
position:absolute;
left:150px;
width:600px;
height:375px;
border: 1px solid black;
padding-top:10px;
color:#FF0080;
visibility:visible;
background: #FFFFFF url('../pattern.png');
padding-left:80px;
}
Next we need to change the addKeyPress() function. Remove everything from addKeyPress() and replace it with the following:
function addKeyPress() {
$(document).on("keypress", function (e) {
if (e.keyCode == 13) {
if (!flickrGame.gameStarted) {
hideIntroScreen();
} else {
doSearch();
}
flickrGame.gameStarted = true;
}
});
}
Here we check if the user has pressed the Enter key, then we check whether the game has started. If it hasn’t we call hideIntroScreen(); otherwise, we call doSearch(); either way, we mark the game as having started. This means that the first time the user presses Enter it will call hideIntroScreen(), and the next time the user presses the Enter key it will call doSearch().
Now we need to code the hideIntroScreen() function. Add the following beneath the addKeyPress() function:
function hideIntroScreen() {
$("#gamediv").css({
'visibility': 'visible'
});
$("#introscreen").css({
'visibility': 'hidden'
});
}
If you test the game now you should see the splash screen; press Enter and you can play the game as before.
Step 12: A Better Alert
Right now if enough images are not returned for a game, we pop up an alert. Although this works, we can make it look a little nicer by using jQuery UI’s dialog.
We need to edit index.html, so open it and add the following right inside the #gamediv:
<div id="gamediv">
<div id="dialog" title="Sorry">
<p>Not enough images were returned, please try a different keyword.</p>
</div>
Now we need tie it in. Add the following beneath the hideIntroScreen() function in the JS file:
$("#dialog").dialog({
autoOpen: false
});
This code converts the #dialog div into a dialog; we disable the auto-open feature.
We want to trigger this dialog to open instead of the alert we had before, so remove the alert from the setImages() function and replace it with the following:
} else {
$("#progressdiv").css({
'visibility': 'hidden'
});
$("#dialog").dialog('open');
addKeyPress();
}
flickrGame.numberPhotosReturned = flickrGame.imageArray.length;
flickrGame.numberLevels = Math.floor(flickrGame.numberPhotosReturned / 12);
}
Now, if not enough images are returned we get a nice looking dialog, instead of using an alert reminiscent of webpages from the ’90s.
Don’t forget to change this line, from preloadImages():
tempImage.src = "cardFront.jpg";
…back to this:
tempImage.src = flickrGame.tempImages[i].imageUrl;
…otherwise, the game will be a bit too easy!
Now test the final game. If anything’s not quite right, you can always compare your source to mine, or ask a question in the comments.
Conclusion
We have coded a fun little game using images from the Flickr API, and given it a decent layer or two of polish. I hope you enjoyed this tutorial and learned something worthwhile. Thanks for reading and have fun!



View full post on Activetuts+
Jun 26, 2012
Posted on Jun 26, 2012 in Hints and Tips | 10 comments
The web moves fast – so fast that our original EaselJS tutorial is already out of date! In this tutorial, you’ll learn how to use the newest CreateJS suite by creating a simple Pong clone.
Final Result Preview
Let’s take a look at the final result we will be working towards:
Click to play
This tutorial is based on Carlos Yanez’s Create a Pong Game in HTML5 With EaselJS, which in turn built on his Getting Started With EaselJS guide. The graphics and sound effects are all taken from the former tutorial.
Step 1: Create index.html
This will be our main index.html file:
<!DOCTYPE html>
<html>
<head>
<title>Pong</title>
<style>/* Removes Mobile Highlight */ *{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style>
<script src="http://code.createjs.com/easeljs-0.4.2.min.js"></script>
<script src="http://code.createjs.com/tweenjs-0.2.0.min.js"></script>
<script src="http://code.createjs.com/soundjs-0.2.0.min.js"></script>
<script src="http://code.createjs.com/preloadjs-0.1.0.min.js"></script>
<script src="http://code.createjs.com/movieclip-0.4.1.min.js"></script>
<script src="assets/soundjs.flashplugin-0.2.0.min.js"></script>
<script src="Main.js"></script>
</head>
<body onload="Main();">
<canvas id="PongStage" width="480" height="320"></canvas>
</body>
</html>
As you can see, it’s pretty short and consists mainly of loading the CreateJS libraries.
Since the release of CreateJS (which basically bundles all the separate EaselJS libraries) we no longer have to download the JS files and host them on our website; the files are now placed in a CDN (Content Delivery Network) which allows us to load these files remotely as quickly as possible.
Let’s review the code:
<style>/* Removes Mobile Highlight */ *{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style>
This line removes the mobile highlight which may appear when you trying to play the game on mobile. (The mobile highlight causes the canvas object to get highlighted and thus ignore your finger movements.)
Next up, we have the loading of the CreateJS libraries:>
<script src="http://code.createjs.com/easeljs-0.4.2.min.js"></script>
<script src="http://code.createjs.com/tweenjs-0.2.0.min.js"></script>
<script src="http://code.createjs.com/soundjs-0.2.0.min.js"></script>
<script src="http://code.createjs.com/preloadjs-0.1.0.min.js"></script>
<script src="http://code.createjs.com/movieclip-0.4.1.min.js"></script>
This code loads the JS files from the CreateJS CDN and it basically allows us to use any of the CreateJS functions in our code
Next, we will load the SoundJS Flash plugin, which provides sound support for browsers that don’t support HTML5 Audio. This is done by using a SWF (a Flash object) to load the sounds.
<script src="assets/soundjs.flashplugin-0.2.0.min.js"></script>
In this case we will not use the CDN; instead, we’ll download the SoundJS library from http://createjs.com/#!/SoundJS/download and place the soundjs.flashplugin-0.2.0.min.js and FlashAudioPlugin.swf files in a local folder named assets.
Last among the JS files, we’ll load the Main.js file which will contain all the code to our game:
<script src="Main.js"></script>
Finally, let’s place a Canvas object on our stage.
<body onload="Main();">
<canvas id="PongStage" width="480" height="320"></canvas>
</body>
Now we can start working on the game code.
Step 2: The Variables
Our game code will be inside a file named Main.js, so create and save this now.
First of all, let’s define variables for all the graphic objects in the game:
var canvas; //Will be linked to the canvas in our index.html page
var stage; //Is the equivalent of stage in AS3; we'll add "children" to it
// Graphics
//[Background]
var bg; //The background graphic
//[Title View]
var main; //The Main Background
var startB; //The Start button in the main menu
var creditsB; //The credits button in the main menu
//[Credits]
var credits; //The Credits screen
//[Game View]
var player; //The player paddle graphic
var ball; //The ball graphic
var cpu; //The CPU paddle
var win; //The winning popup
var lose; //The losing popup
I’ve added a comment for each variable so that you’ll know what we’ll be loading in that variable
Next up, the scores:
//[Score]
var playerScore; //The main player score
var cpuScore; //The CPU score
var cpuSpeed=6; //The speed of the CPU paddle; the faster it is the harder the game is
We’ll, need variables for the speed of the ball:
// Variables
var xSpeed = 5;
var ySpeed = 5;
You can change these values to whatever you want, if you’d like to make the game easier or harder.
If you’re a Flash developer, you know that Flash’s onEnterFrame is very useful when creating games, as there are things that need to happen in every given frame. (If you’re not familiar with this idea, check out this article on the Game Loop.)
We have an equivalent for onEnterFrame in CreateJS, and that is the ticker object, which can run code every fraction of a second. Let’s create the variable that will link to it:
var tkr = new Object;
Next we have the preloader, which will use the new PreloadJS methods.
//preloader
var preloader;
var manifest;
var totalLoaded = 0;
preloader – will contain the PreloadJS object.
manifest – will hold the list of files we need to load.
totalLoaded – this variable will hold the number of files already loaded.
Last but not least in our list of variables, we have TitleView, which will hold several graphics within in order to display them together (like a Flash DisplayObjectContainer).
var TitleView = new Container();
Let’s move on to the Main function…
Step 3: The Main() Function
This function is the first function that runs after all the JS files from the index.html are loaded. But what’s calling this function?
Well, remember this line from the index.html file?
<body onload="Main();">
This code snippet states that once the HTML (and JS libraries) are loaded, the Main function should run.
Let’s review it:
function Main()
{
/* Link Canvas */
canvas = document.getElementById('PongStage');
stage = new Stage(canvas);
stage.mouseEventsEnabled = true;
/* Set The Flash Plugin for browsers that don't support SoundJS */
SoundJS.FlashPlugin.BASE_PATH = "assets/";
if (!SoundJS.checkPlugin(true)) {
alert("Error!");
return;
}
manifest = [
{src:"bg.png", id:"bg"},
{src:"main.png", id:"main"},
{src:"startB.png", id:"startB"},
{src:"creditsB.png", id:"creditsB"},
{src:"credits.png", id:"credits"},
{src:"paddle.png", id:"cpu"},
{src:"paddle.png", id:"player"},
{src:"ball.png", id:"ball"},
{src:"win.png", id:"win"},
{src:"lose.png", id:"lose"},
{src:"playerScore.ogg", id:"playerScore"},
{src:"enemyScore.ogg", id:"enemyScore"},
{src:"hit.ogg", id:"hit"},
{src:"wall.ogg", id:"wall"}
];
preloader = new PreloadJS();
preloader.installPlugin(SoundJS);
preloader.onProgress = handleProgress;
preloader.onComplete = handleComplete;
preloader.onFileLoad = handleFileLoad;
preloader.loadManifest(manifest);
/* Ticker */
Ticker.setFPS(30);
Ticker.addListener(stage);
}
Let’s break down each part:
canvas = document.getElementById('PongStage');
stage = new Stage(canvas);
stage.mouseEventsEnabled = true;
Here we link the PongStage Canvas object from the index.html file to the canvas variable, and then create a Stage object from that canvas. (The stage will allow us to place objects on it.)
mouseEventsEnabled enables us to use mouse events, so we can detect mouse movements and clicks.
/* Set The Flash Plugin for browsers that don't support SoundJS */
SoundJS.FlashPlugin.BASE_PATH = "assets/";
if (!SoundJS.checkPlugin(true)) {
alert("Error!");
return;
}
Here we configure where the Flash sound plugin resides for those browsers in which HTML5 Audio is not supported
manifest = [
{src:"bg.png", id:"bg"},
{src:"main.png", id:"main"},
{src:"startB.png", id:"startB"},
{src:"creditsB.png", id:"creditsB"},
{src:"credits.png", id:"credits"},
{src:"paddle.png", id:"cpu"},
{src:"paddle.png", id:"player"},
{src:"ball.png", id:"ball"},
{src:"win.png", id:"win"},
{src:"lose.png", id:"lose"},
{src:"playerScore.ogg", id:"playerScore"},
{src:"enemyScore.ogg", id:"enemyScore"},
{src:"hit.ogg", id:"hit"},
{src:"wall.ogg", id:"wall"}
];
In the manifest variable we place an array of files we want to load (and provide a unique ID for each one
preloader = new PreloadJS();
preloader.installPlugin(SoundJS);
preloader.onProgress = handleProgress;
preloader.onComplete = handleComplete;
preloader.onFileLoad = handleFileLoad;
preloader.loadManifest(manifest);
Here we configure the preloader object using PreloadJS. PreloadJS is a new addition to the CreateJS libraries and quite a useful one.
We create a new PreloadJS object and place it in the preloader variable, then assign a method to each event (onProgress, onComplete, onFileLoad). Finally we use the preloader to load the manifest we created earlier.
Ticker.setFPS(30);
Ticker.addListener(stage);
Here we add the Ticker object to the stage and set the frame rate to 30 FPS; we’ll use it later in the game for the enterFrame functionality.
Step 4: Creating the Preloader Functions
function handleProgress(event)
{
//use event.loaded to get the percentage of the loading
}
function handleComplete(event) {
//triggered when all loading is complete
}
function handleFileLoad(event) {
//triggered when an individual file completes loading
switch(event.type)
{
case PreloadJS.IMAGE:
//image loaded
var img = new Image();
img.src = event.src;
img.onload = handleLoadComplete;
window[event.id] = new Bitmap(img);
break;
case PreloadJS.SOUND:
//sound loaded
handleLoadComplete();
break;
}
}
Let’s review the functions:
handleProgress – In this function you’ll be able to follow the percentage of the loading progress using this parameter: event.loaded. You could use this to create for example a progress bar.
handleComplete – This function is called once all the files have been loaded (in case you want to place something there).
handleFileLoad – Since we load two types of files – images and sounds – we have this function that will handle each one separately. If it’s an image, we create a bitmap image and place it in a variable (whose name is the same as the ID of the loaded image) and then call the handleLoadComplete function (which we’ll write next); if it’s a sound then we just call the handleLoadComplete immediately.
Now let’s discuss the handleLoadComplete function I just mentioned:
function handleLoadComplete(event)
{
totalLoaded++;
if(manifest.length==totalLoaded)
{
addTitleView();
}
}
It’s a pretty straightforward function; we increase the totalLoaded variable (that holds the number of assets loaded so far) and then we check if the number of items in our manifest is the same as the number of loaded assets, and if so, go to the Main Menu screen.
Step 5: Creating the Main Menu
function addTitleView()
{
//console.log("Add Title View");
startB.x = 240 - 31.5;
startB.y = 160;
startB.name = 'startB';
creditsB.x = 241 - 42;
creditsB.y = 200;
TitleView.addChild(main, startB, creditsB);
stage.addChild(bg, TitleView);
stage.update();
// Button Listeners
startB.onPress = tweenTitleView;
creditsB.onPress = showCredits;
Nothing special here. We place the images of the Background, Start Button and Credits Button on the stage and link onPress event handlers to the Start and Credits buttons.
Here are the functions that display and remove the credits screen and the tweenTitleView which starts the game:
function showCredits()
{
// Show Credits
credits.x = 480;
stage.addChild(credits);
stage.update();
Tween.get(credits).to({x:0}, 300);
credits.onPress = hideCredits;
}
// Hide Credits
function hideCredits(e)
{
Tween.get(credits).to({x:480}, 300).call(rmvCredits);
}
// Remove Credits
function rmvCredits()
{
stage.removeChild(credits);
}
// Tween Title View
function tweenTitleView()
{
// Start Game
Tween.get(TitleView).to({y:-320}, 300).call(addGameView);
}
Step 6: The Game Code
We’ve reached the main part of this tutorial which is the code of the game itself.
First of all, we need to add all the required assets to the stage, so we do that in the addGameView function:
function addGameView()
{
// Destroy Menu & Credits screen
stage.removeChild(TitleView);
TitleView = null;
credits = null;
// Add Game View
player.x = 2;
player.y = 160 - 37.5;
cpu.x = 480 - 25;
cpu.y = 160 - 37.5;
ball.x = 240 - 15;
ball.y = 160 - 15;
// Score
playerScore = new Text('0', 'bold 20px Arial', '#A3FF24');
playerScore.x = 211;
playerScore.y = 20;
cpuScore = new Text('0', 'bold 20px Arial', '#A3FF24');
cpuScore.x = 262;
cpuScore.y = 20;
stage.addChild(playerScore, cpuScore, player, cpu, ball);
stage.update();
// Start Listener
bg.onPress = startGame;
}
Again, a pretty straightforward function that places the objects on the screen and adds a mouseEvent to the background image, so that when the user clicks it the game will start (we will call the startGame function).
Let’s review the startGame function:
function startGame(e)
{
bg.onPress = null;
stage.onMouseMove = movePaddle;
Ticker.addListener(tkr, false);
tkr.tick = update;
}
Here, as you can see, in addition to adding an onMouseMove event that will move our paddle. We add the tick event, which will call the update function in each frame.
Let’s review the movePaddle and reset functions:
function movePaddle(e)
{
// Mouse Movement
player.y = e.stageY;
}
/* Reset */
function reset()
{
ball.x = 240 - 15;
ball.y = 160 - 15;
player.y = 160 - 37.5;
cpu.y = 160 - 37.5;
stage.onMouseMove = null;
Ticker.removeListener(tkr);
bg.onPress = startGame;
}
In movePaddle, we basically place the user’s paddle at the mouse’s y-coordinate.
In reset, we do something similar to addGameView, except here we don’t add any graphic elements since they are already on the screen.
Using the alert function we’ll display the winning and losing popup:
function alert(e)
{
Ticker.removeListener(tkr);
stage.onMouseMove = null;
bg.onPress = null
if(e == 'win')
{
win.x = 140;
win.y = -90;
stage.addChild(win);
Tween.get(win).to({y: 115}, 300);
}
else
{
lose.x = 140;
lose.y = -90;
stage.addChild(lose);
Tween.get(lose).to({y: 115}, 300);
}
}
Step 7: The Game Loop
Now, for the last part of our tutorial we’ll work on the update function (which occurs in every frame of the game – similar to Flash’s onEnterFrame):
function update()
{
// Ball Movement
ball.x = ball.x + xSpeed;
ball.y = ball.y + ySpeed;
// Cpu Movement
if(cpu.y < ball.y) {
cpu.y = cpu.y + 4;
}
else if(cpu.y > ball.y) {
cpu.y = cpu.y - 4;
}
// Wall Collision
if((ball.y) < 0) { ySpeed = -ySpeed; SoundJS.play('wall'); };//Up
if((ball.y + (30)) > 320) { ySpeed = -ySpeed; SoundJS.play('wall');};//down
/* CPU Score */
if((ball.x) < 0)
{
xSpeed = -xSpeed;
cpuScore.text = parseInt(cpuScore.text + 1);
reset();
SoundJS.play('enemyScore');
}
/* Player Score */
if((ball.x + (30)) > 480)
{
xSpeed = -xSpeed;
playerScore.text = parseInt(playerScore.text + 1);
reset();
SoundJS.play('playerScore');
}
/* Cpu collision */
if(ball.x + 30 > cpu.x && ball.x + 30 < cpu.x + 22 && ball.y >= cpu.y && ball.y < cpu.y + 75)
{
xSpeed *= -1;
SoundJS.play('hit');
}
/* Player collision */
if(ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75)
{
xSpeed *= -1;
SoundJS.play('hit');
}
/* Stop Paddle from going out of canvas */
if(player.y >= 249)
{
player.y = 249;
}
/* Check for Win */
if(playerScore.text == '10')
{
alert('win');
}
/* Check for Game Over */
if(cpuScore.text == '10')
{
alert('lose');
}
}
Looks scary, doesn’t it? Don’t worry, we’ll review each part and discuss it.
// Ball Movement
ball.x = ball.x + xSpeed;
ball.y = ball.y + ySpeed;
In each frame, the ball will move according to its x and y speed values
// Cpu Movement
if((cpu.y+32) < (ball.y-14)) {
cpu.y = cpu.y + cpuSpeed;
}
else if((cpu.y+32) > (ball.y+14)) {
cpu.y = cpu.y - cpuSpeed;
}
Here we have the basic AI of the computer, in which the computer’s paddle simply follows the ball without any special logic. We just compare the location of the center of the paddle (which is why we add 32 pixels to the cpu Y value) to the location of the ball, with a small offset, and move the paddle up or down as necessary.
if((ball.y) < 0) { //top
ySpeed = -ySpeed;
SoundJS.play('wall');
};
if((ball.y + (30)) > 320) { //bottom
ySpeed = -ySpeed;
SoundJS.play('wall');
};
If the ball hits the top border or the bottom border of the screen, the ball changes direction and we play the Wall Hit sound.
/* CPU Score */
if((ball.x) < 0)
{
xSpeed = -xSpeed;
cpuScore.text = parseInt(cpuScore.text + 1);
reset();
SoundJS.play('enemyScore');
}
/* Player Score */
if((ball.x + (30)) > 480)
{
xSpeed = -xSpeed;
playerScore.text = parseInt(playerScore.text + 1);
reset();
SoundJS.play('playerScore');
}
The score login is simple: if the ball passes the left or right borders it increases the score of the player or CPU respectively, plays a sound, and resets the location of the objects using the reset function we’ve discussed earlier.
/* CPU collision */
if(ball.x + 30 > cpu.x && ball.x + 30 < cpu.x + 22 && ball.y >= cpu.y && ball.y < cpu.y + 75)
{
xSpeed *= -1;
SoundJS.play('hit');
}
/* Player collision */
if(ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75)
{
xSpeed *= -1;
SoundJS.play('hit');
}
Here we deal with collisions of the ball with the paddles; every time the ball hits one of the paddles, the ball changes direction and a sound is played
if(player.y >= 249)
{
player.y = 249;
}
If the player’s paddle goes out of bounds, we place it back within the bounds.
/* Check for Win */
if(playerScore.text == '10')
{
alert('win');
}
/* Check for Game Over */
if(cpuScore.text == '10')
{
alert('lose');
}
In this snippet, we check whether either of the players’ score has reached 10 points, and if so we display the winning or losing popup to the player (according to his winning status).
Conclusion
That’s it, you’ve created an entire pong game using CreateJS. Thank you for taking the time to read this tutorial.



View full post on Activetuts+
Jun 24, 2012
Posted on Jun 24, 2012 in Hints and Tips | 10 comments
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. Check back later today for a look at what we could do to improve the game! This tutorial is going to focus on the code and math required to build this demo.
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);
addEventListener(Event.ENTER_FRAME, move);
rSpeed = speed;
}
// runs every frame
public function move(e:Event):void
{
this.y += rSpeed;
//rotation speed is linked to moving speed
this.rotation += rSpeed / 8;
}
}
}
Step 3: The StageController Class
This class will eventually control most of the aspects of our game, including the player movement and the game loop.
For now, though, we’ll just use it as a place to store a reference to the stage.
Create the class:
package
{
import flash.display.Stage;
public class StageController
{
public static var STAGE:Stage;
public function StageController(stg:Stage)
{
// we will pass the stage from the Main class
STAGE = stg;
}
}
}
We’re going to pass a reference to the stage to this class from our Main class (which is automatically created by FlashDevelop as the starting class for our game). This will allow us to add display objects to the display list from this class.
Step 4: Update The Main Class
We’ll now create an instance of StageController within Main and pass it a reference to the stage:
package
{
import flash.display.Sprite;
import flash.events.Event;
[SWF(width = "550", height = "600")]
public class Main extends Sprite
{
private var stageController:StageController;
public function Main():void
{
stageController = new StageController(stage);
}
}
}
Step 5: Introducing a Manager Class
To avoid the StageController 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
{
public var energy:Energy;
// this Vector will store all instances of the Energy class
private var energyList:Vector.<Energy>
public function EnergyManager()
{
energyList = new Vector.<Energy>;
}
}
}
So far the class contain no other functions; we will add them in later.
Step 6: Creating Energy
Add below function for creating energy, this is just a function, we will be calling the function later from StageController Class:
public function createEnergy(number:int):void
{
for (var i:int = 0; i < number; i++) {
energy = new Energy(4);
StageController.STAGE.addChild(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 directly to the stage via the StageController, add it to the Vector of all energy objects that we just created, and set its position to a random point within certain bounds.
Editor’s Note: I’m a little uncomfortable with adding a display object directly to the stage like that, although of course it does work. One alternative would be to create a function within StageController that handles this for us.
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.
Step 7: Spawning Energy
Let’s set a timer that defines the interval for each spawning. This code goes in StageController‘s constructor function:
energyM = new EnergyManager;
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 StageController to add the player to the screen:
// in the variable definitions
public var player:Player;
// in the constructor function
player = new Player;
STAGE.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:
Step 9: Moving the Player
There are basically two ways to apply movement:
- 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.
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:
- Create two Boolean variables, one for moving right and one for moving left.
private var moveRight:Boolean = false;
private var moveLeft:Boolean = false;
- Toggle the Boolean when keys are pressed or released:
STAGE.addEventListener(Event.ENTER_FRAME, update);
STAGE.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
STAGE.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 (space == true) {
space = false;
}else if (space == false) {
space = true;
}
}
}
private function KeyUpHandler(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.RIGHT) {
moveRight = false;
}
if (e.keyCode == Keyboard.LEFT) {
moveLeft = false;
}
}
- 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.display.Stage;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.ui.Keyboard;
import flash.utils.Timer;
import flash.events.KeyboardEvent;
public class StageController
{
public static var STAGE:Stage; // A variable that store Stage class type.
public var player:Player;
private var energyM:EnergyManager;
private var moveRight:Boolean = false;
private var moveLeft:Boolean = false;
private var space:Boolean = true;
private var returnedPower:int = 0;
private var scoreText:Text;
private var totalScore:int=0;
private var score:Text;
public function StageController(stg:Stage) // Passing the stage from calling.
{
STAGE = stg; // store "stage" passed to STAGE (we will pass from Main class).
scoreText = new Text("Score :");
STAGE.addChild(scoreText);
energyM = new EnergyManager;
var spawnTimer:Timer = new Timer(3000, 0);
spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
spawnTimer.start();
player = new Player;
STAGE.addChild(player);
player.x = 275;
player.y = 450;
STAGE.addEventListener(Event.ENTER_FRAME, update);
STAGE.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
STAGE.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 (space == true) {
space = false;
}else if (space == false) {
space = 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: 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 StageController.
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) {
StageController.STAGE.removeChild(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 Pythagorus.
- 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 StageController.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:
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 Pythagorus’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:
- Find the difference in x and y between the ship and a given crystal.
- Find the angle between them, in radians.
- Find the distance between them, using Pythagorus.
- Check whether object is within the ship’s gravitational field.
- If so, calculate the gravitational force, and…
- …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 StageController – but before that, we will need to use a Boolean function to toggle between the two functions:
private var space:Boolean = true; //called space because hitting space toggles it
We are going to use true for ‘Push’ and false for ‘Pull’.
Inside KeyDownHandler():
if (e.keyCode == Keyboard.SPACE) {
if (space == true) {
space = false;
} else if (space == false) {
space = true;
}
}
Afterwards, you will have to check the Boolean each frame. Add this to update():
if (space == true) {
energyM.gravityPull(player);
}
if (space == 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 to the constructor:
addEventListener(Event.ENTER_FRAME, updatePower);
Here’s the actual updatePower() function:
private function updatePower(e:Event):void
{
// 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;
}
// 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.
Step 19: Make Energy Increase Power
When the ship collides with an energy object, we want it to increase its power.
In StageController.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 StageController class:
private var scoreText:Text;
private var totalScore:int = 0;
private var score:Text;
In the constructor, add this code:
scoreText = new Text("Score :");
STAGE.addChild(scoreText);
if (!score) {
STAGE.removeChild(score);
score = null;
}
score = new Text(String(totalScore));
STAGE.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);
this.addEventListener(Event.ENTER_FRAME, moveDown);
speed = speed1;
}
private function moveDown(e:Event):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.



View full post on Activetuts+
Jun 22, 2012
Posted on Jun 22, 2012 in Hints and Tips | 10 comments
There are several methods used to produce menus within Unity, the main two being the built in GUI system and using GameObjects with Colliders that respond to interactions with the mouse. Unity’s GUI system can be tricky to work with so we’re going to use the GameObject approach which I think is also a bit more fun for what we’re trying to achieve here.
Final Result Preview
Please view the full post to see the Unity content.
Step 1: Determine Your Game Resolution
Before designing a menu you should always determine what resolution you are going to serve it to.
Open the Player settings via the top menu, Edit > Project Settings > Player and enter your default screen width and height values into the inspector. I chose to leave mine as the default 600x450px as shown below.
You then need to adjust the size of your Game view from the default "Free Aspect" to "Web (600 x 450)", else you could be positioning your menu items off the screen.
Step 2: Choosing a Menu Background
As you will have seen in the preview, our menu scene is going to have our game environment in the background so that when you click Play you enter seamlessly into the game.
To do this you need to position your player somewhere in the scene where you like the background and round up the Y rotation value. This is so it’s easier to remember and to replicate later, so that the transition can be seamless from the menu into the game.
Let’s now get on with the creation of the menu scene!
Step 3: Creating the Menu Scene
Make sure your scene is saved and is called "game" – you’ll see why later.
Select the game scene within the Project view and duplicate it using Ctrl/Command + D, then rename the copy to "menu" and double-click it to open it.
Note: You can confirm which scene is open by checking the top of the screen, it should say something like "Unity – menu.unity – ProjectName – Web Player / Stand Alone". You don’t want to start deleting parts accidently from your game scene!
Now select and delete the GUI and PickupSpawnPoints GameObjects from the Hierarchy. Expand the "Player" and drag the "Main Camera" so that it’s no longer a child of the Player, then delete the Player.
Next, select the terrain and remove the Terrain Collider Component by right-clicking and selecting Remove Component.
Finally, select the "Main Camera" and remove the MouseLook Component by right-clicking and selecting Remove Component.
If you run the game now nothing should happen and you shouldn’t be able to move at all. If you can move or rotate then redo the above steps.
Step 4: Adjusting the Build Settings
Currently when you build or play your game the only level included within that build is the "game" scene. This means that the menu scene will never appear. So that we can test our menu, we’ll adjust the build settings now.
From the top menu select File > Build Settings and drag the menu scene from your Project View into the Build Settings’ "Scenes In Build" list as shown below
(Make sure you rearrange the scenes to put "menu.unity" at the top, so that it’s the scene that’s loaded first when the game is played.)
Perfect!
Step 5: Adding the Play Button
We’re going to use 3D Text for our menu, so go ahead and create a 3D Text GameObject via the top menu: GameObject > Create Other > 3D Text, then rename it "PlayBT". Set the Y rotation of the PlayBT text to match the Y rotation value of your Main Camera so that it’s facing directly at it and therefore easily readable.
With the PlayBT selected, change the Text Mesh text property from Hello World to "Play", reduce the Character Size to 0.1 and increase the Font Size to 160 to make the text crisper.
Note: If you want to use a font other than the default, either select the font before creating the 3D Text or drag the Font onto the 3DText’s TextMesh’s Font property and then drag the Fonts "Font Material" onto the Mesh Renderers Materials list, overwriting the existing Font Material. Quite a hassle I know!
Finally, add a Box Collider via the top menu: Component > Physics > Box Collider. Resize the Box Collider to fit the text if it doesn’t fit it nicely.
At this point in the tutorial you really need to have both the Scene and Game Views open at the same time since you are now going to move the PlayBT within the Scene View so that it’s centred within your Game View as shown below. I recommend first positioning it horizontally using a top down view and then revert to using a perspective view to position it vertically using the axis handles.
So that’s our Play button all set up. Now let’s make it play!
Step 6: The Mouse Handler Script
Create a new JavaScript script within your scripts folder, rename it "MenuMouseHandler" and add it as a Component of the PlayBT GameObject by either dragging in directly onto PlayBT or by selecting PlayBT and dragging the script onto it’s Inspector.
Replace the default code with the following:
/**
Mouse Down Event Handler
*/
function OnMouseDown()
{
// if we clicked the play button
if (this.name == "PlayBT")
{
// load the game
Application.LoadLevel("game");
}
}
We’re using the MonoBehaviour OnMouseDown(…) function, invoked every time the BoxCollider is clicked by the mouse. We check whether the button clicked is called "PlayBT", and if so we use Application.LoadLevel(…) to load the "game" scene.
Enough talk – go run it and watch your game come to life when you click Play!
Note: If you click Play and have found yourself with a build settings error, don’t fret; you just need to check your build settings – revisit Step 4.
Step 7: Ending the Game
So the menu to start the game is great but the game technically never ends since when the timer runs out nothing happens… let’s fix that now.
Open the CountdownTimer script and at the bottom of the Tick() function add the following line:
Application.LoadLevel("menu");
Now re-run your game and when the timer runs out you’ll be taken back to the menu! Easy Peasy!
There we go – a basic menu added to our game. Now let’s make it a little more user friendly with a help screen to explain how to play.
Step 8: Adding the Help Button
The help button is identical to the PlayBT in practically every way, so go ahead and duplicate the PlayBT, rename it to HelpBT and position it below the Play button. Adjust the text property to say "Help" rather than "Play" and perhaps make the Font Size a little smaller as shown below – I used 100.
Now open the MenuMouseHandler script and add the following else if block to your existing if statement.
// if we clicked the help button
else if (this.name == "HelpBT")
{
// rotate the camera to view the help "page"
}
If you check the preview you’ll see that when you click Help the camera rotates around to show the help menu. So, how do we do that?
Step 9: God Save iTween
Our camera rotation can all be done nice and cleanly in one line, thanks to iTween. Without iTween life wouldn’t be nearly as fun. As the name may give away it’s a tweening engine, built for Unity. It’s also free.
Go ahead and open iTween within the Unity Asset store, then click Download/Import and import it all into your project. Once it’s imported you need to move the iTween/Plugins directory into the root of your Assets folder.
You’re now all set to tween your life away!
Step 10: Rotating the Camera
Grab a piece of paper and a pen (or open a blank document) and make a note of your Main Camera’s Y rotation value, as circled below.
Within the scene view rotate the camera around in whichever direction you like around the Y axis so that the Play and Help text are out of view and so that you’ve got a decent background for your help page. You can see mine below: I rotated from -152 to -8.
Return to your MenuMouseHandler script and add the following line within the else if statement:
iTween.RotateTo(Camera.main.gameObject, Vector3(0, -8, 0), 1.0);
We use Camera.main to retrieve the main camera (defined by the "MainCamera" tag) from the scene and use iTween.RotateTo(…) to rotate the camera to a specific angle – in my case -8.
(You need to replace the -8 within the above line with your camera’s current rotation.)
Now go back to your scene and return your camera back to its original rotation that you wrote down at the start of this section, so that it’s facing the PlayBT. Run your game, click Help and the camera should spin around. Woo!
Note: If you get an error about iTween not existing then you haven’t imported it properly – revisit Step 9.
Now let’s build our Help page.
Step 11: Building the Help Page
Rotate your camera back to the Y rotation of your help page – in my case -8.
Now we’re going to add a little explanation text as well as some more text to explain the different pickups and their scores. Finally, we’ll add a Back button to return to the main menu. You can arrange your page in whatever way you wish so feel free to get creative. Here we go…
Duplicate the HelpBT, rename it HelpHeader, set its rotation to that of your camera, change the Anchor value to "upper center" and reduce the Font Size – I used 60.
Next, copy and paste the below paragraph into the text property:
"Collect as many Cubes as you can within the time limit.
Watch out though, they change over time!
Note: It’s worth noting that you can’t type multiline text into the text property; you have to type it in another program and then copy and paste it since pressing enter/return assigns the field.
Finally remove the Box Collider and MenuMouseHandler Components within the Inspector since this text won’t need to be clickable. Hopefully you end up with something like this:
Now drag a pickup prefab into the scene and position it on the screen. I put mine as shown below.
Next, duplicate the HelpHeader, rename it to HelpPowerups, change the Anchor to "upper-left" and copy and paste the below paragraph into the text field.
"Green: + 2 Points
Pink: +/- Random Points
Blue: Random Speed Boost"
Reposition it so you have something like the below.
All that’s left now is to add a Back button to return to the main menu.
Step 12: The Help Page Back Button
Duplicate the HelpBT, rename it BackBT, change its text to "Back", set its rotation to that of your camera and use the Scene View to reposition it within the Game View. I placed mine in the bottom corner as shown here:
Now we just need to update our MenuMouseHandler script to handle mouse clicks from the BackBT as well. Add the following else if block to the bottom of the OnMouseDown() if statements:
// if we clicked the Back button
else if (this.name == "BackBT")
{
// rotate the camera to view the menu "page"
iTween.RotateTo(Camera.main.gameObject, Vector3(0, -152, 0), 1.0);
}
This is nearly identical to the previous iTween statement, the only difference being the angle the camera is rotated to – -152 in my case. You need to change this number to the original Y rotation of your camera was (the one you wrote down, remember?)
Now all you need to do it set your camera back to its original rotation – the value you just added to the iTween statement – so that it’s facing the main menu again.
Run the game and your camera should spin round to reveal the help page and spin back round to the main menu. Congratulations, you’ve finished!
Conclusion
I hope you’ve enjoyed this Getting Started with Unity Session!
In this part we’ve covered using GameObjects as menu items and the incredibly powerful tweening library, iTween.
If you want an extra challenge, try using iTween to change the text colour on MouseOver and then back again on MouseExit. (You’ll find a list of Mouse handlers on this page.)
Or add an iTween CameraFade and then fade it out when the timer runs out, then load then menu – rather than abruptly ending the game. You could then delay the call to Application.LoadLevel(...) using yield WaitForSeconds(...).
Let me know how you get on in the comments!



View full post on Activetuts+
May 20, 2012
Posted on May 20, 2012 in Hints and Tips | 10 comments
Interested in game design? This weekend, we feature a set of four interactive lectures: games that are about game design, by Pixelate.
Play the Games
Bub and Bob, two little 8-bit guys, will talk you through the basic concepts of video games. The games themselves are more like interactive tutorials, with smaller games interspersed throughout to help make certain points, and great bit tunes throughout.
Episode 1
Click to play.
The first episode deals with rules, interactivity, representation, and simulation in games.
Episode 2
Click to play.
The second episode is about motivating the player to stay in the game, and making sure they have fun.
Episode 3
Click to play.
The third episode looks at one of my favourite topics: learning in video games.
Episode 4
Click to play.
Finally, the fourth episode is about identification.



View full post on Activetuts+
Page 1 of 2012345...1020...»Last »