logo
468x60-2-495


  • Home
  • Privacy Policy
  • About
search
Oct 31, 2011 Posted on Oct 31, 2011 in Hints and Tips | 10 comments

Best of Tuts+ in October

Each month, we bring together a selection of the best tutorials and articles from across the whole Tuts+ network. Whether you’d like to read the top posts from your favourite site, or would like to start learning something completely new, this is the best place to start!


    Psdtuts+ — Photoshop Tutorials

  • Photo Effects Week: Create a Fantasy Miniature World in Photoshop

    Photo Effects Week: Create a Fantasy Miniature World in Photoshop

    This week we are celebrating the launch of PhotoDune, Envato’s new stock photography website with a series of photo effect and photo manipulation tutorials that showcase the images from our new marketplace. In this tutorial we’ll demonstrate how to create a miniature world using some interesting techniques. Many of the photos used in this tutorial are available for free for Psd Premium Members. Let’s get started!

    Visit Article

  • Photo Effects Week: Create a Cutout Photograph in Photoshop

    Photo Effects Week: Create a Cutout Photograph in Photoshop

    This week we are celebrating the launch of PhotoDune, Envato’s new stock photography website with a series of photo effect and photo manipulation tutorials that showcase the images from our new marketplace. In this tutorial we will demonstrate how to create a cutout photo using simple selections and advanced transformations. The photos used in this tutorial are available for free for Psd Premium Members. Let’s get started!

    Visit Article

  • Create a Stitched Text Effect for an iPad Wallpaper

    Create a Stitched Text Effect for an iPad Wallpaper

    In this tutorial we will show you how to create a custom stitched text effect for an iPad Wallpaper. Let’s get started!

    Visit Article


  • Nettuts+ — Web Development Tutorials

  • Stop Nesting Functions! (But Not All of Them)

    Stop Nesting Functions! (But Not All of Them)

    JavaScript is over fifteen years old; nevertheless, the language is still misunderstood by what is perhaps the majority of developers and designers using the language. One of the most powerful, yet misunderstood, aspects of JavaScript are functions. While terribly vital to JavaScript, their misuse can introduce inefficiency and hinder an application’s performance.

    Visit Article

  • The Intro to Rails Screencast I Wish I Had

    The Intro to Rails Screencast I Wish I Had

    Isn’t it funny how most “introduction to Ruby on Rails” screencasts are overly simplistic, and rely on generators like scaffolding? The teacher typically follows up the tutorial by stating that most Rails developer don’t use scaffolding generators. Well that’s not much help then! I’d like to give you the tutorial I wish I had. Along the way, we’ll also rely heavily on test-driven development to build a simple app.

    Visit Article

  • The Best Way to Learn PHP

    The Best Way to Learn PHP

    Learning something from scratch is almost always an arduous affair — you simply have no idea as to where to start, or not to start, to kick things off. I loathed learning about the idiosyncrasies of C++’s syntax when all I wanted to learn were some darn programming concepts. As I’m sure you can agree, this is a less than ideal situation.

    Visit Article


  • Vectortuts+ — Illustrator Tutorials

  • 250+ Free, Vintage Graphics: Flourish Vector Ornaments

    Free, Vintage Graphics: Flourish Vector Ornaments

    Wow, if you’re looking for high quality free vector graphics, then you’ve landed on the right article. We’ve roundup up a massive collection of free vector flourishes. These graphics are composed of a wonderful mix of vintage elements, floral ornaments, swirly design mixes, and are all made of beautifully curved vector art.

    Visit Article

  • Beginners Guides to InDesign

    Beginners Guides to InDesign

    InDesign is a powerful design program with so many tools and features it can a bit tricky to find a topic to begin with. With this in mind, we’ve put together a collection of beginner guides on various InDesign topics like the best way to create a new document, how to import text and images and even useful advice on what to do when a document is corrupted and how to make comments and track changes.

    Visit Article

  • How to Color a Cute Character using Graphic Styles

    How to Color a Cute Character using Graphic Styles

    Coloring a character sketch can sometimes take much longer than anyone expects. With a few layer tricks and Graphic Styles, I will show you how to create a character that is quick to ink, easy to edit and a breeze to re-color. Let’s get started!

    Visit Article


  • Webdesigntuts+ — Web Design Tutorials

  • Design a Static Admin Bar in Photoshop

    Design a Static Admin Bar in Photoshop

    Let’s whip up a simple, yet effective ‘static admin bar’ in Photoshop. We’ll take a selection of UI elements, and design their various states, ready for building in HTML and CSS.

    Visit Article

  • A Smarter Twitter Page in Under 15 Minutes

    A Smarter Twitter Page in Under 15 Minutes

    Today we’ll design a smart, vintage modern background to welcome visitors to your Twitter page. We’ll go over some layout considerations, then dive into Photoshop. Have fifteen minutes spare? Let’s go then!

    Visit Article

  • Build An Innovative Portfolio Site Using Alternative UI/UX

    Build An Innovative Portfolio Site Using Alternative UI/UX

    Paul J Noble’s awwward winning, uniquely designed portfolio site has caught the eye of many people, and not just clients either. Today he’s going to follow up on the design stage of this tutorial, and demonstrate how it’s coded up.

    Visit Article


  • Phototuts+ — Photography Tutorials

  • Strapping Up: A Look at Camera Straps

    Strapping Up: A Look at Camera Straps

    Ever stop to think about what is holding your camera when your hands aren’t? Lots of photography tutorials focus on cameras, lenses, and lighting. Even bags and filters get a lot of press. However, there is one important piece of equipment that gets neglected and choosing the wrong one can be a literal pain in the neck. So, we’re going to take a look at various camera straps and how they indirectly impact your photography.

    Visit Article

  • 100 Fantastic Photos of Reptiles and Amphibians

    Fantastic Photos of Reptiles and Amphibians

    Today’s photo collection is a tribute to all things scaly, slimy, or perhaps even both. We have gathered one hundred impeccable examples of reptile and amphibian photography. Whether these creatures are swimming in ponds or slithering underfoot, numerous talented photographers have found them to be the perfect subjects for many beautiful compositions.

    Visit Article

  • Finishing Your Photographs: Picking Your Medium

    Finishing Your Photographs: Picking Your Medium

    Photographers spend a great deal of energy capturing the best image possible and ensuring the image or print is faithfully reproduced. We may not, however, spend as much energy thinking about how to finish a photograph – print, frame or store it – and archive the image.

    Visit Article


  • Cgtuts+ — Computer Graphics Tutorials

  • The Making Of “Yuki Machi”

    The Making Of “Yuki Machi”

    This is a walk through from start to finish of how I made my “Yuki Machi” scene. This tutorial is intended for beginners and students who are making the switch from creating and building assets to creating whole scenes and environments. Ill take you through the processes and techniques I use and show you the challenges l face when making larger sets.

    Visit Article

  • Freebie: An Amazingly Detailed Dodge Tire Model

    Freebie: An Amazingly Detailed Dodge Tire Model

    Need some sweet rims for your next vehicle model? Well you’re in luck! Because Ivan Momchilov is giving away this epic Dodge tire model, complete with a set of highly detailed brakes. For you 3d Studio Max users out there, Ivan has included scene files for 2010,2011 and 2012! And for the non Max users, we have it available in .obj format as well, making it super easy to import it into your software package of choice. This model’s free to all, so download it today!

    Visit Article

  • Modeling and Animating An Xpresso Driven Clock In Cinema 4D

    Modeling and Animating An Xpresso Driven Clock In Cinema 4D

    Today we’ll take some time (did you get it?) to model and animate a clock in Cinema 4D using only Xpresso. We’ll model the clock from a basic cylinder and add some simple materials and lighting to the scene. Once we have the model complete, we’ll begin animating the clock with Xpresso and add some user data to have more control over our final animation.

    Visit Article


  • Aetuts+ — After Effects Tutorials

  • How To Create And Rig A Realistic Puppet Overview

    How To Create And Rig A Realistic Puppet Overview

    This is a quick overview of Aetuts+’s “How To Create And Rig A Realistic Puppet” Series. We will be posting a new chapter every day or so for the entire month of October. There are 17 parts total so check it regularly!

    Visit Article

  • Use Real Lights To Motivate Simulated Lights in After Effects – AE Premium

    Use Real Lights To Motivate Simulated Lights in After Effects – AE Premium

    This demonstration is about shooting a translucent object, in this case a crystal illuminated by a match, and compositing that object with stock footage of dramatic fire. Finally, we’ll be simulating similar lighting effects in After Effects to reveal a logo.

    Visit Article

  • Create And Composite A Mobile Phone App Demo Template

    Create And Composite A Mobile Phone App Demo Template

    In this tutorial you will learn the workflow on how to set up a scene for an animated pack shot of a phone in CINEMA 4D and composite it in After Effects. Perhaps you have developed a revolutionary iPhone app that you want to show off to the world, or maybe you just want to learn the basic workflow of compositing 3D passes in After Effects. Either way I hope this tutorial will help you along the way.

    Visit Article


  • Audiotuts+ — Audio & Production Tutorials

  • 5 Of My Current Favourite iOS Apps

    Of My Current Favourite iOS Apps

    As you may have already realised Im a pretty big fan of all things Apple. Not only do I utilise Apple computers in my production process but I also lean pretty heavily on IOS-based devices in the studio.

    Visit Article

  • Vocal Loop Effect in Reason

    Vocal Loop Effect in Reason

    In electronic dance music, DJ’s often loop tracks to cheer up the crowd. In your music productions, you can also use this effect to create an uplifting effect for what’s to come. This tutorial shows you how to create such a loop effect on vocals, using Reason 4.0.

    Visit Article

  • Adding Flavor to Chords – Major and Minor 7ths – Basix

    Adding Flavor to Chords – Major and Minor 7ths – Basix

    Today we are going to cover how to add some flavor to your chords and compositions using 7ths in both major and minor. It is surprising how many people know how to play them but do not really understand how they are built and function (guitarists I am talking to you!).

    Visit Article


  • Activetuts+ — Flash, Flex & ActionScript Tutorials

  • Create a Flexible XMPP Chat for a Member-Based Website With Flash and PHP

    Create a Flexible XMPP Chat for a Member-Based Website With Flash and PHP

    We’ll be looking at how to create a XMPP chat application that can be used in many different scenarios. You’ll learn how to integrate an external database with Ignite Realtime’s Openfire Jabber Server and how to use the XIFF library to create custom XMPP extensions that can be used to send custom data across a network.

    Visit Article

  • UI Design for Developers: Introduction

    UI Design for Developers: Introduction

    Designers vs. developers – it is an argument as old as computers. The truth is, though, neither can live without the other. A brilliant UI design is as worthless without functionality as is the best piece of code with an ugly, unusable frontend. In this first post on UI Basics for developers, I am going to try and lay out some simple ground rules that devs can follow to make sure their apps, templates and prototypes are as beautiful as the code itself – and usable to boot.

    Visit Article

  • AS3 101: Events – Basix

    AS3 101: Events – Basix

    For this chapter of AS3 101, we will be diving into the mechanics of the Flash event system. If you’ve been following along so far, you’ll have seen events in use, dating all the way back to the first episode of the series. The editor and I felt that it was time to write up something to be formally included in the curriculum, so if you’ve ever seen those lines of code about adding event listeners or dispatching events, and not quite caught on, then this is the tutorial for you.

    Visit Article


  • Wptuts+ — WordPress Tutorials

  • WordPress Cheat Sheets: Theme Anatomy Model

    WordPress Cheat Sheets: Theme Anatomy Model

    Next in line for our WordPress Cheat Sheet series, The Basic WordPress Theme Anatomy Model! If you haven’t seen the first posts in this series, this is a new batch of these quick pocket guides that you guys n’ gals can download, save to your phones for a fast reference, or even print out and keep next to your desk while you’re working on customizing WordPress to do your bidding.

    Visit Article

  • WordPress Theme Development Training Wheels: Day One

    WordPress Theme Development Training Wheels: Day One

    Ready to learn how to make your first WordPress theme? This tutorial series will take a step by step approach, making use of a "learning theme" affectionately known as WordPress Training Wheels, to help teach the subject. This series will take the absolute WordPress newbie through the basic steps necessary to convert any HTML template into a fully functional WordPress theme.

    Visit Article

  • WordPress 3.3 is On the Horizon! Beta 2 Release Notes

    WordPress 3.3 is On the Horizon! Beta 2 Release Notes

    WordPress is evolving quite faster than ever, and every update gets all excited (especially those who make a living on it). WordPress has released it’s 3.3, Beta 2 version just 2 days ago for testing. This update is focused on more improvements, refining and making things faster and better. Today, we’re going to round up what’s coming in the next big version.

    Visit Article


  • Mobiletuts+ — Mobile Development Tutorials

  • First Look: iOS 5 SDK

    First Look: iOS 5 SDK

    iOS 5 has been officially released, and iOS developers are eager to begin making use of the many new features available in the iOS 5 SDK. In this article, industry gurus Brandon Trebitowski and Collin Ruffenach reflect on the opportunities, efficiencies, and most exciting features of the latest SDK. This post is a must read for all iOS SDK developers!

    Visit Article

  • iOS 5 for Web Devs: Safari Mobile Updates

    iOS 5 for Web Devs: Safari Mobile Updates

    Native iOS developers aren’t the only ones with something to be excited about when it comes to developing for iOS 5. A new version of Safari Mobile was released alongside the latest operating system, and mobile web developers now have many new features to experiment with. Get up to speed on the changes in this article!

    Visit Article

  • iOS 5: Fixed Positioning and Content Scrolling

    iOS 5: Fixed Positioning and Content Scrolling

    Two of the most celebrated enhancements to Safari on iOS 5 are fixed positioning and content scrolling support. This tutorial will teach you how to take advantage of this change and what the implications are for stop-gap JavaScript libraries like iScroll.

    Visit Article


  • FreelanceSwitch — Articles and Resources for Freelancers

  • Keys to Setting Your Rate Based on Experience

    Keys to Setting Your Rate Based on Experience

    There is no one set strategy for setting your rates, which is why the process can be so confusing for freelancers. Basing your rates off regional competitors’ prices is a very smart tactic, but I think many freelancers forget about something important when putting together rates, and that is their value.

    Visit Article

  • 5 Rarely Remembered Rules for Building Your Freelance Brand

    5 Rarely Remembered Rules for Building Your Freelance Brand

    Having a strong brand can be a game-changer for your freelance business.
    Good brands command respect and establish a reputation. They establish your presence in the marketplace. When questions arise like “where can I find a good freelance writer” or “where do I go to get my website redesigned” … strong brands immediately come to mind.
    So how do you build your brand? What rules of branding should you follow?

    Visit Article

  • 7 Ways to Tell a Client He’s Wrong

    Telling a client that he is, in fact, wrong can be the hardest thing you ever have to do in your freelance career. It’s not something that we generally consider to be a healthy step: it can lose you a client pretty quickly if not handled properly.
    Even if a client accepts that he is incorrect about something, it may still be harder to work with him in the long run.

    Visit Article



View full post on Activetuts+

Oct 30, 2011 Posted on Oct 30, 2011 in Hints and Tips | 10 comments

HTML5 Avoider Game Tutorial: Multiple Moving Enemies

This entry is part 2 of 2 in the series HTML5 Avoider Game Tutorial

In the first part of this series, you learned the basics of using JavaScript and the canvas element to make a very simple HTML5 avoider game. But it’s too simple – the single enemy doesn’t even move – there’s no challenge! In this tutorial, you’ll learn how to create a never-ending stream of enemies, all falling from the top of the screen.


Refresher

In the first part of the tutorial we covered quite a few concepts: drawing images to the screen, interacting between HTML and JavaScript, detecting mouse actions, and the if statement. You can download the source files here if you want to dive in to this part of the tutorial, though I recommend reading all parts in order.

Our game’s HTML page contains a canvas element, which triggers a JavaScript function called drawAvatar() when it is clicked. That function is inside a separate file called main.js, and it does two things:

  • Draws a copy of avatar.png to the canvas.
  • Sets up an event listener to call another function, called redrawAvatar(), whenever the mouse moves over the canvas.

The redrawAvatar() function is also inside main.js; unlike drawAvatar() it accepts a parameter – called mouseEvent – which is automatically passed to it by the event listener. This mouseEvent contains information about the mouse’s position. The function does four things:

  • Clears the canvas.
  • Draws a copy of avatar.png to the canvas, at the mouse’s position.
  • Draws a copy of enemy.png to the canvas, at a specified position.
  • Checks to see whether the avatar and enemy are close enough to each other to be overlapping, and displays an alert() if so.

All clear? If not, try the warm up challenge.


Warm Up Challenge

If it’s been a while since you read the first part of the series (or if you just want to check that you understand what’s going on), have a go at these little exercises. They’re completely optional and separate to the actual tutorial, so I recommend working on a copy of your project rather than the original. You can complete all of these exercises using only information from the first part of the series.

Easy

Remember that drawImage() works like a potato stamp. Use it to create an unbroken ring of enemies around the edge of your canvas, like this:

HTML5 avoider game tutorial

(If you get bored of copying and pasting all those statements, feel free to make it a smaller ring – you could resize the canvas, too, if you like.)

Medium

Make the “you hit the enemy” alert appear whenever the avatar hits the edge of the ring. (To test this, remember that you can hit Enter to dismiss the alert; you don’t have to click OK.)

Hard

That alert will come up when you try to move your mouse from outside the canvas to inside it, which is really annoying if you’ve already clicked the canvas. Make it possible to move into the canvas without triggering the alert – but once inside, make the alert appear whenever the avatar touches the ring of enemies.


Make the Enemy Move

We’re going to make the enemy fall down from the top of the screen. For now, we’ll focus on making it move rather than on detecting a collision, so “comment out” the lines in redrawEnemy() that deal with collisions, like so:

//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
//	alert("You hit the enemy!");
//}

Remember: two forward slashes tell the browser “ignore everything on this line from here on”. Earlier on we used this to create comments – little reminders of what certain bits of code do – but here we’re using it for another purpose: stopping certain bits of code from running without completely deleting them. This makes it easy for us to put the code back in later.

At the moment, the enemy is redrawn, in the same position, whenever we move the mouse:

gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);

Do you remember the Math.random() function from the first part of the tutorial? It returns a random number between zero and one; multiplying it by 300 (the height of the canvas) would give us a number between 0 and 300. What happens if we draw the enemy at a random y-position between 0 and 300 every time the mouse was moved? Let’s try it out; modify that line like so:

gameCanvas.getContext("2d").drawImage(enemyImage, 250, Math.random() * 300);

Try it out here!

It looks like the enemy is moving randomly up and down a certain line, but only when the mouse is moved. Of course, it’s not actually moving; it’s “teleporting” from one position to the next, but this gives the illusion of movement.

We’d get a better illusion if it only moved in one direction. We can achieve this by making sure the enemy’s y-position only increases, and never decreases.

Consider the following code:

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	var enemyY = 0;	

	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);

	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);

	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
	//	alert("You hit the enemy!");
	//}
}

See what I’m doing? I set the value of enemyY to 0 at the top of the function, then increased it by one pixel before drawing the enemy. In this way, I’m aiming to make the enemy’s y-position increase by one pixel every time redrawAvatar() is run.

However, there’s a flaw in my logic. The line var enemyY = 0; will reset the enemyY variable to 0 every time redrawAvatar() is run, which means that it’ll always be drawn at a y-position of 1 (because it’ll be increased at line 12).

We need to only set it to 0 once. What if we do that in drawEnemy()? After all, that function is only run once:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyY = 0;

	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);

	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();

	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);

	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);

	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
	//	alert("You hit the enemy!");
	//}
}

Try it out here!

Unfortunately, this doesn’t work at all. The problem lies in a concept called scope. If you use the var keyword to define a variable within a function, then the variable will only be accessible within that function. This means that our redrawAvatar() function cannot access the same enemyY variable that was defined in drawAvatar().

However, if we define a variable outside of all functions, it can be accessed by any one of them! So, try this:

var enemyY = 0;

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();

	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);

	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();

	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);

	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);

	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
	//	alert("You hit the enemy!");
	//}
}

Try it out here!

It works – the enemy slides down the screen. However, it only does so while we’re moving the mouse. That’s an interesting game mechanic, but it’s not what I was aiming for.


Make the Enemy Move on Its Own

It’d be much better if the enemy appeared to move of its own accord – meaning, it moves regardless of whether or not the player is moving the mouse. We can do this by triggering its movement (its “teleportations”) based on time rather than on mouse movement.

We can do this by using the setInterval() function. It works like this:

setInterval(functionName, period);

Here, functionName is the name of a function we want to run over and over again, and period is the amount of time (in milliseconds) we want to pass between each call to that function.

Let’s see how this looks:

var enemyY = 0;

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();

	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);

	gameCanvas.addEventListener("mousemove", redrawAvatar);
	setInterval(redrawEnemy, 1000);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();

	avatarImage.src = "img/avatar.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);

	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
	//	alert("You hit the enemy!");
	//}
}

function redrawEnemy() {
	var enemyImage = new Image();
	enemyImage.src = "img/enemy.png";

	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
}

I’ve moved all the code that deals with moving and drawing the enemy to the new redrawEnemy() function, and I’ve set it to be called every 1,000 milliseconds (every second) using a setInterval() call in drawAvatar(). (Unlike when using an event listener, no parameters automatically get passed to redrawEnemy() when we call it from setInterval().)

Try it out here! Click the canvas, then don’t move your mouse.

HTML5 avoider game tutorial

There are a few things wrong with this:

  • The enemy leaves a trail – this is because the canvas isn’t cleared in redrawEnemy().
  • The enemy moves really slowly – perhaps 1000 milliseconds is too long to wait.
  • When the avatar is moved, the enemy disappears – this is because the enemy is only drawn in redrawEnemy(); in redrawAvatar() the canvas is cleared and the avatar is redrawn, but not the enemy.

Let’s fix these one at a time. First, we’ll clear the canvas in redrawEnemy():

function redrawEnemy() {
	var enemyImage = new Image();
	enemyImage.src = "img/enemy.png";

	gameCanvas.width = 400;		//this erases the contents of the canvas

	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
}

Try it out here!

Hm. Now the avatar disappears whenever the enemy is drawn, and vice-versa. Of course, this makes sense; we clear the canvas in both redrawEnemy() and redrawAvatar(), but never draw both the enemy and the avatar at the same time.

What if we moved the enemy in redrawEnemy() – by increasing the value of enemyY – but actually drew it in redrawAvatar()?

var enemyY = 0;

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();

	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);

	gameCanvas.addEventListener("mousemove", redrawAvatar);
	setInterval(redrawEnemy, 1000);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	enemyImage.src = "img/enemy.png";

	avatarImage.src = "img/avatar.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);	

	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
	//	alert("You hit the enemy!");
	//}
}

function redrawEnemy() {
	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
}

Try it out here!

It sort of works, but we’re back to that problem where the enemy only moves while you’re moving the mouse. However, this time it’s slightly different; to make this more obvious, we can increase the enemy’s speed by reducing the period. Set it to 25 (that’s 1/40th of a second, meaning redrawEnemy() will run 40 times per second):

setInterval(redrawEnemy, 25);

Try it out here!

Compare this with the earlier version where the enemy only moved when the mouse was moving. See the difference? In the new one, the enemy’s position keeps changing, but it does so “behind the scenes”; the actual image of the enemy only moves when the mouse is moved. If you wait a second or so before moving the mouse, the enemy image jumps down the screen to catch up with its actual position.

Separating the enemy’s actual position from the enemy’s image’s position like this is going to let us solve our problem.

Before we move on, are you getting confused by the function names? I am. redrawEnemy() isn’t actually drawing the enemy at all. Let’s rename them to something a bit easier to keep track of.

  • drawAvatar() is run when we start the game, and it sets everything up, so let’s rename it to setUpGame()
  • redrawAvatar() is run whenever the mouse moves, so let’s rename it to handleMouseMovement()
  • redrawEnemy() is run every fraction of a second; it’s as if there’s a clock that ticks 40 times a second, and each tick triggers the function. So, let’s rename it to handleTick()
  • Don’t forget you have to rename all the references to the functions as well, in the event listener and the setInterval(). Here’s what it’ll look like:

    var enemyY = 0;
    
    function setUpGame() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var avatarImage = new Image();
    
    	avatarImage.src = "img/avatar.png";
    	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
    
    	gameCanvas.addEventListener("mousemove", handleMouseMovement);
    	setInterval(handleTick, 25);
    }
    
    function handleMouseMovement(mouseEvent) {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var avatarImage = new Image();
    	var enemyImage = new Image();
    	enemyImage.src = "img/enemy.png";
    
    	avatarImage.src = "img/avatar.png";
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);	
    
    	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
    	//	alert("You hit the enemy!");
    	//}
    }
    
    function handleTick() {
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    }
    

    (You’ll also need to change the HTML page, so that the canvas’s onclick attribute is "setUpGame();" rather than "drawAvatar();".

    I think this makes it easier to see what’s going on:

    • When the mouse moves, we move the avatar’s position, draw the avatar in its current position, and draw the enemy in its current position.
    • When the clock ticks, we move the enemy’s position.
    • We need to draw the enemy and the avatar at the same time (i.e. in the same function).
    • If we only draw the enemy when the mouse moves, then the enemy’s movement is not smooth.

    This makes it easier in turn to see a possible solution:

    • When the mouse moves, move the avatar’s position.
    • When the clock ticks, move the enemy’s position, draw the avatar in its current position, and draw the enemy in its current position.

    Let’s implement that. All we need to do is move the drawing code from handleMouseMovement() to handleTick(), right? Like this:

    var enemyY = 0;
    
    function setUpGame() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var avatarImage = new Image();
    
    	avatarImage.src = "img/avatar.png";
    	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
    
    	gameCanvas.addEventListener("mousemove", handleMouseMovement);
    	setInterval(handleTick, 25);
    }
    
    function handleMouseMovement(mouseEvent) {
    	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
    	//	alert("You hit the enemy!");
    	//}
    }
    
    function handleTick() {
    	var avatarImage = new Image();
    	var enemyImage = new Image();
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    
    	enemyImage.src = "img/enemy.png";
    	avatarImage.src = "img/avatar.png";
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    }
    

    Hmm. That’s not right. We’ve got nothing left in handleMouseMovement(). Ah – but that’s because we haven’t separated the avatar’s image’s position from the avatar’s actual position, like we did with the enemy. So let’s do that:

    var enemyY = 0;
    var avatarX = 0;
    var avatarY = 0;
    
    function setUpGame() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var avatarImage = new Image();
    
    	avatarImage.src = "img/avatar.png";
    	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
    
    	gameCanvas.addEventListener("mousemove", handleMouseMovement);
    	setInterval(handleTick, 25);
    }
    
    function handleMouseMovement(mouseEvent) {
    	avatarX = mouseEvent.offsetX;
    	avatarY = mouseEvent.offsetY;
    
    	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
    	//	alert("You hit the enemy!");
    	//}
    }
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var avatarImage = new Image();
    	var enemyImage = new Image();
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    
    	enemyImage.src = "img/enemy.png";
    	avatarImage.src = "img/avatar.png";
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    }
    

    We have to create new variables to store the avatar’s actual x- and y-positions, and define those variables outside of any function, so that we can access them from anywhere.

    Try it out here!

    This works! (If it’s a little jerky, then try closing some tabs or restarting Chrome; that worked for me.) We now have a moving enemy. Took a while to get there, but the actual code we’ve ended up with isn’t too complex, I hope you’ll agree.

    If you want a challenge, try re-introducing the collision detection alert box. Don’t worry if you have troubles; we’ll go through this again a bit later.

    In the mean time, we’ll look at a problem you probably haven’t come across yet…


    Loading the Images From a Server

    As I mentioned in the first part of this series, if you put your game onto a web server as it is now, it won’t work correctly, even though they work fine when running from your computer. My demos work because I’ve made a slight modification to the code; here’s how the game runs without that code:

    Try it out here.

    What’s going on? Well, it’s to do with the images. Every time the clock ticks, we create a new image and set its source to point to an actual image file. This doesn’t cause problems when the image file is on your hard drive, but when it’s on the Internet, the page might try to download the image before drawing it – leading to the flickering that we can see in the demo.

    Perhaps you can already guess at a solution, based on what we’ve done in this tutorial so far. Just like with the enemy’s and avatar’s positions, we can move the enemy’s and avatar’s images outside of the functions, and re-use them over and over again, without having to define them and set their values in the handleTick() function each time.

    Take a look:

    var enemyY = 0;
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    function setUpGame() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	avatarImage = new Image();
    	enemyImage = new Image();
    	enemyImage.src = "img/enemy.png";
    	avatarImage.src = "img/avatar.png";
    
    	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
    
    	gameCanvas.addEventListener("mousemove", handleMouseMovement);
    	setInterval(handleTick, 25);
    }
    
    function handleMouseMovement(mouseEvent) {
    	avatarX = mouseEvent.offsetX;
    	avatarY = mouseEvent.offsetY;
    
    	//if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
    	//	alert("You hit the enemy!");
    	//}
    }
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    }
    

    Try it out here – no flickering!

    In case you’re wondering: we could have moved lines 9-12 outside of the functions as well. I chose to put them in setUpGame() simply because they seemed to be more about, well, setting up the game.


    Make Another Enemy

    It’s actually really easy to make another enemy appear on the screen. Remember that images are like potato stamps; that means there’s nothing stopping us from drawing the enemy image onto the canvas in two different places within the same tick:

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 100, enemyY);
    }
    
    HTML5 avoider game tutorial
    Click to try it out.

    Simple!

    You can put them at different heights, like so:

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 100, enemyY - 50);
    }
    
    HTML5 avoider game tutorial
    Click to try it out.

    This is a bit messy, though. Instead, how about just creating an enemyY2 variable?

    var enemyY = 0;
    var enemyY2 = -50;
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    //...
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    	enemyY2 = enemyY2 + 1;
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 100, enemyY2);
    }
    

    Now you can set the initial positions of enemyY and enemyY2 to whatever you want, without having to change the code in handleTick().


    Make Five Enemies

    Try extending what we’ve just done so that there are five enemies, all with different starting points. Take a look at my code if you need to. Here’s a hint: you only need to add code outside of the functions and inside the handleTick() function – no need to touch setUpGame() or handleMouseMovement().

    var enemyY = 0;
    var enemyY2 = -50;
    var enemyY3 = -75;
    var enemyY4 = -120;
    var enemyY5 = -250;
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    //...
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    
    	enemyY = enemyY + 1;    //increase enemyY variable by one pixel. If enemyY is 10, then enemyY + 1 is 11, etc.
    	enemyY2 = enemyY2 + 1;
    	enemyY3 = enemyY3 + 1;
    	enemyY4 = enemyY4 + 1;
    	enemyY5 = enemyY5 + 1;
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 130, enemyY2);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 300, enemyY3);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 50, enemyY4);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 190, enemyY5);
    }
    
    HTML5 avoider game tutorial
    Click to try it out.

    Make Ten Enemies

    Oh, this is going to get tedious, right? Maintaining all those enemies, and adding three lines of code for each one. Yuck.

    Allow me to introduce arrays. Take a look at this:

    var enemyYPositions = [0, -50, -75, -120, -250];
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    //...
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    
    	enemyYPositions[0] = enemyYPositions[0] + 1;
    	enemyYPositions[1] = enemyYPositions[1] + 1;
    	enemyYPositions[2] = enemyYPositions[2] + 1;
    	enemyYPositions[3] = enemyYPositions[3] + 1;
    	enemyYPositions[4] = enemyYPositions[4] + 1;
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyYPositions[0]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 130, enemyYPositions[1]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 300, enemyYPositions[2]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 50, enemyYPositions[3]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 190, enemyYPositions[4]);
    }
    

    This gives us the exact same result as before, but:

    • All of the enemies’ y positions are defined in a single line, and
    • We get an easy way to refer to any of these positions: enemyYPosition[enemyNumber].

    This type of variable is called an array; it’s a way of holding a list of values (or even of other variables), and lets us retrieve any item from that list using a number. Note that the first element of an array is number 0, the second value is number 1, and so on – we call arrays “zero-based” for this reason.

    Looping

    Now take a look at this section of code:

    	enemyYPositions[0] = enemyYPositions[0] + 1;
    	enemyYPositions[1] = enemyYPositions[1] + 1;
    	enemyYPositions[2] = enemyYPositions[2] + 1;
    	enemyYPositions[3] = enemyYPositions[3] + 1;
    	enemyYPositions[4] = enemyYPositions[4] + 1;
    

    We’re doing the same thing, over and over again, to different items in the array. Each line of code is the same as all of the others, except that the number inside the square brackets changes. This is great, because we can write code to say “do this same thing five times, but changing one number each time”. For example:

    var currentNumber = 0;
    while (currentNumber < 5) {
    	alert(currentNumber);
    	currentNumber = currentNumber + 1;
    }
    

    If you put this in your JS file (in setUpGame(), for example), it would make the page display five alert boxes: the first would say “0″; the second would say “1″; and so on up to “4″. In other words, it’s equivalent to doing this:

    var currentNumber = 0;
    alert(currentNumber);
    currentNumber = currentNumber + 1;
    alert(currentNumber);
    currentNumber = currentNumber + 1;
    alert(currentNumber);
    currentNumber = currentNumber + 1;
    alert(currentNumber);
    currentNumber = currentNumber + 1;
    alert(currentNumber);
    currentNumber = currentNumber + 1;
    

    This is because the while statement acts like a repeated if statement. Remember, if works like this:

    if (condition) {
    	outcome;
    }
    

    “If condition is true, then run outcome.”

    while works like this:

    while (condition) {
    	outcome;
    }
    

    “As long as condition remains true, keep running outcome.”

    It’s a subtle difference, but a really important one. An if block will run just once, if the condition is true; a while block will run over and over again until the condition stops condition stops being true.

    For this reason, the outcome – the code that’s run inside the while block – usually contains some code that will, eventually, cause condition to stop being true; if it didn’t the code would just repeat itself forever. In our alert box example, we increased the value of currentNumber until it “currentNumber < 5" was no longer true (when currentNumber reached 5, it was no longer less than 5, which is why we never see an alert box containing the number 5).

    Running code over and over again like this is called "looping", and the while block is called a "loop". Let's now take this code:

    	enemyYPositions[0] = enemyYPositions[0] + 1;
    	enemyYPositions[1] = enemyYPositions[1] + 1;
    	enemyYPositions[2] = enemyYPositions[2] + 1;
    	enemyYPositions[3] = enemyYPositions[3] + 1;
    	enemyYPositions[4] = enemyYPositions[4] + 1;
    

    ...and put it into a loop:

    	var currentEnemyNumber = 0;
    	while (currentEnemyNumber < 5) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    	}
    

    Great! Or is it?

    Actually, that's not quite right: we're not changing the value of currentEnemyNumber. This means that we'll just increase the value of enemyYPositions[0] over and over again, forever, without ever changing the other enemies' y-positions or ever exiting the loop.

    So, we need to do this:

    	var currentEnemyNumber = 0;
    	while (currentEnemyNumber < 5) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    

    Now it's great.

    Can we apply the same thinking to our other repetitive code? I'm referring to this:

    	gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyYPositions[0]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 130, enemyYPositions[1]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 300, enemyYPositions[2]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 50, enemyYPositions[3]);
    	gameCanvas.getContext("2d").drawImage(enemyImage, 190, enemyYPositions[4]);
    

    Unfortunately, something like this won't work:

    	var currentEnemyNumber = 0;
    	while (currentEnemyNumber < 5) {
    		gameCanvas.getContext("2d").drawImage(enemyImage, 250, enemyYPositions[currentEnemyNumber]);
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    

    ...because not all enemies have an x-position of 250. But we can make it work, if we move all the enemies x-positions to another array:

    var enemyXPositions = [250, 130, 300, 50, 190];
    var enemyYPositions = [0, -50, -75, -120, -250];
    
    //...
    
    var currentEnemyNumber = 0;
    while (currentEnemyNumber < 5) {
    	gameCanvas.getContext("2d").drawImage(enemyImage, enemyXPositions[currentEnemyNumber], enemyYPositions[currentEnemyNumber]);
    	currentEnemyNumber = currentEnemyNumber + 1;
    }
    

    This has the added benefit of keeping all the enemies' x- and y-positions in one neat location, rather than spread out across several lines.

    Let's look at the code in context:

    var enemyYPositions = [0, -50, -75, -120, -250];
    var enemyXPositions = [250, 130, 300, 50, 190];
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    //...
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    
    	while (currentEnemyNumber < 5) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    
    	currentEnemyNumber = 0;
    	while (currentEnemyNumber < 5) {
    		gameCanvas.getContext("2d").drawImage(enemyImage, enemyXPositions[currentEnemyNumber], enemyYPositions[currentEnemyNumber]);
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    }
    

    Note that, on line 22 above, I've reset currentEnemyNumber to 0; if I didn't, the loop for drawing the enemy images wouldn't run even once, as condition would already be false from the earlier loop that moves the enemies. Also note that, when I do this, the loop that draws the enemies doesn't immediately detect that condition is now true again and start moving all the enemies.

    It all works just as it did before.

    HTML5 avoider game tutorial
    Click to try it out.

    The biggest benefit to this is in how easy it is to add another five enemies. We only need to change four lines of code:

    var enemyYPositions = [0, -50, -75, -120, -250, -280, -305, -330, -340, -400];
    var enemyXPositions = [250, 130, 300, 50, 190, 200, 220, 60, 100, 110];
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    //...
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    
    	while (currentEnemyNumber < 10) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    
    	currentEnemyNumber = 0;
    	while (currentEnemyNumber < 10) {
    		gameCanvas.getContext("2d").drawImage(enemyImage, enemyXPositions[currentEnemyNumber], enemyYPositions[currentEnemyNumber]);
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    }
    
    HTML5 avoider game tutorial
    Click to try it out.

    Simple!


    Make Fifteen Enemies

    Here's another exercise for you: modify the code so that it creates fifteen enemies. Again, you only have to alter four lines of code. Take a look at my code if you're not sure:

    var enemyYPositions = [0, -50, -75, -120, -250, -280, -305, -330, -340, -400, -425, -450, -500, -520, -550];
    var enemyXPositions = [250, 130, 300, 50, 190, 200, 220, 60, 100, 110, 30, 300, 150, 190, 90];
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    //...
    
    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    
    	while (currentEnemyNumber < 15) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    
    	currentEnemyNumber = 0;
    	while (currentEnemyNumber < 15) {
    		gameCanvas.getContext("2d").drawImage(enemyImage, enemyXPositions[currentEnemyNumber], enemyYPositions[currentEnemyNumber]);
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    }
    

    Obviously we could continue on like this. But I'm already finding it irritating to change lines 14 and 23 above, and have forgotten to do so a couple of times.

    Fortunately we can automate this, in a way. The number - 5, 10, 15, or whatever - is equal to the number of items in either the enemyXPositions[] or enemyYPositions[] array. We call this the array's length, and can retrieve it from either array by using the .length property - like so:

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    
    	while (currentEnemyNumber < enemyXPositions.length) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    
    	currentEnemyNumber = 0;
    	while (currentEnemyNumber < enemyXPositions.length) {
    		gameCanvas.getContext("2d").drawImage(enemyImage, enemyXPositions[currentEnemyNumber], enemyYPositions[currentEnemyNumber]);
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    }
    

    Or, to be a bit neater:

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    	var numberOfEnemies = enemyXPositions.length;
    
    	while (currentEnemyNumber < numberOfEnemies) {
    		enemyYPositions[currentEnemyNumber] = enemyYPositions[currentEnemyNumber] + 1;
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    
    	gameCanvas.width = 400;		//this erases the contents of the canvas
    	gameCanvas.getContext("2d").drawImage(avatarImage, avatarX, avatarY);
    
    	currentEnemyNumber = 0;
    	while (currentEnemyNumber < numberOfEnemies) {
    		gameCanvas.getContext("2d").drawImage(enemyImage, enemyXPositions[currentEnemyNumber], enemyYPositions[currentEnemyNumber]);
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    }
    

    Now you can make as many enemies as you want, just by adding new numbers to the enemyXPositions[] and enemyYPositions[] arrays.


    Re-Introduce Collision Detection

    Remember how collision detection worked? We've had the code sitting in handleMouseMovement() (though commented out) for a while:

    	if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
    		alert("You hit the enemy!");
    	}
    

    It's basically checking whether two rectangles - one that moves with the cursor, and one that sits still on the canvas - are overlapping. But it's hard to understand from that code, so let's take a fresh look.

    First, let's look at it in terms of horizontal overlap:

    HTML5 avoider game tutorial

    Here, the avatar and the enemy are not overlapping. We have: avatarX < avatarX + 30 < enemyX < enemyX + 30

    HTML5 avoider game tutorial

    Here, the avatar and the enemy are overlapping. We have: avatarX < enemyX < avatarX + 30 < enemyX + 30

    HTML5 avoider game tutorial

    Still overlapping. We have: enemyX < avatarX < enemyX + 30 < avatarX + 30

    HTML5 avoider game tutorial

    No longer overlapping. We have: enemyX < enemyX + 30 < avatarX < avatarX + 30

    Taking all these together, we can see that the enemy and avatar are overlapping horizontally if:

    avatarX < enemyX and enemyX < avatarX + 30

    ...or:

    enemyX < avatarX and avatarX < enemyX + 30

    In other words, for horizontal overlap, this condition must be true:

    (avatarX < enemyX && enemyX < avatarX + 30) || (enemyX < avatarX && avatarX < enemyX + 30)

    (Remember, && means "and"; || means "or".)

    It's not hard to come up with a similar condition for vertical overlap:

    (avatarY < enemyY && enemyY < avatarY + 33) || (enemyY < avatarY && avatarY < enemyY + 30)

    (We use 33 here because the avatar is 33 pixels tall, but only 30 pixels wide.)

    For the enemy and avatar to be overlapping, they must be overlapping both horizontally and vertically - so we use the && operator to combine these two conditions:

    ( (avatarX < enemyX && enemyX < avatarX + 30) || (enemyX < avatarX && avatarX < enemyX + 30) ) && ( (avatarY < enemyY && enemyY < avatarY + 33) || (enemyY < avatarY && avatarY < enemyY + 30) )

    That's a long condition! But it's actually quite simple, now that we've broken it down. Let's put it into our code. First, delete the old collision detection code from handleMouseMovement(); we'll put this in handleTick(), after we've moved and redrawn the enemy and avatar, so that it seems fairer.

    To start with, we'll just check for a collision between the avatar and the first enemy:

    function handleTick() {
    
    	//...
    
    	if ( ( (avatarX < enemyXPositions[0] && enemyXPositions[0] < avatarX + 30) || (enemyXPositions[0] < avatarX && avatarX < enemyXPositions[0] + 30) ) && ( (avatarY < enemyYPositions[0] && enemyYPositions[0] < avatarY + 33) || (enemyYPositions[0] < avatarY && avatarY < enemyYPositions[0] + 30) ) ) {
    		alert("You hit the first enemy!");
    	}
    }
    

    It looks messy (so you should probably add a comment to remind yourself of how it works later), but it's got everything we need. Does it work?

    Try it out here!

    It does work! Now we should make it work for all the enemies - and of course we can use a loop to do that:

    	currentEnemyNumber = 0;
    	while (currentEnemyNumber < numberOfEnemies) {
    		if ( ( (avatarX < enemyXPositions[currentEnemyNumber] && enemyXPositions[currentEnemyNumber] < avatarX + 30) || (enemyXPositions[currentEnemyNumber] < avatarX && avatarX < enemyXPositions[currentEnemyNumber] + 30) ) && ( (avatarY < enemyYPositions[currentEnemyNumber] && enemyYPositions[currentEnemyNumber] < avatarY + 33) || (enemyYPositions[currentEnemyNumber] < avatarY && avatarY < enemyYPositions[currentEnemyNumber] + 30) ) ) {
    			alert("You hit an enemy!");
    		}
    		currentEnemyNumber = currentEnemyNumber + 1;
    	}
    

    Note that this goes inside handleTick(), at the end, so we have to reset currentEnemyNumber to 0. We also need to change the alert box text, since it might not be the first enemy that causes the alert to appear.

    Try it out here!

    All right, this is really shaping into a game! Okay, sure, the alert box is kind of annoying, but it serves our purposes for now.

    There's one more big addition I'd like us to make in this part...


    Make Infinitely Many Enemies

    We can add more and more enemy positions to our arrays - a hundred, a thousand, whatever - but eventually the supply will run out, and the player will have no more enemies to dodge. We need to be able to create new enemies and add their positions to the arrays while the game is running.

    When we want to change the value of a specific item inside enemyXPositions, it's easy: we just write enemyXPositions[3] = 100, or whatever. But how can we add something to the array? Writing enemyXPositions = [100] (or whatever) will just replace the array with a new one, containing just one item.

    The answer is in the arrays' .push() function; this allows us to add an item to an array without creating a new one. To demonstrate this, let's delete all the items from our arrays, and then use .push() to add new ones:

    var enemyYPositions = [];	//empty square brackets means new empty array
    var enemyXPositions = [];
    var avatarX = 0;
    var avatarY = 0;
    var avatarImage;
    var enemyImage;
    
    function setUpGame() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	avatarImage = new Image();
    	enemyImage = new Image();
    	enemyImage.src = "img/enemy.png";
    	avatarImage.src = "img/avatar.png";
    
    	enemyYPositions.push(0);
    	enemyXPositions.push(250);
    
    	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
    
    	gameCanvas.addEventListener("mousemove", handleMouseMovement);
    	setInterval(handleTick, 25);
    }
    
    HTML5 avoider game tutorial
    Click to try it out.

    It works fine; the enemy still moves and the collision detection still works. It's exactly the same as if we'd started the code with:

    var enemyYPositions = [0];
    var enemyXPositions = [250];
    

    So what happens if we push the new values onto the arrays inside handleTick(), rather than inside setUpGame()?

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    	var numberOfEnemies = enemyXPositions.length;
    
    	enemyYPositions.push(0);
    	enemyXPositions.push(250);
    
    HTML5 avoider game tutorial
    Click to try it out.

    Hm. It's creating new enemies in the same positions at such a fast rate that they're overlapping. (The one at the top of the screen appears to be above all of the others because that's the last one to get drawn.)

    Let's try to fix this by creating the enemies at random starting x-positions. Remember that Math.random() gets us a random number between 0 and 1, so to get a random number between 0 and 400 - the width of the canvas - we can use Math.random() * 400:

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    	var numberOfEnemies = enemyXPositions.length;
    
    	enemyYPositions.push(0);
    	enemyXPositions.push(Math.random() * 400);
    
    HTML5 avoider game tutorial
    Click to try it out.

    Argh!

    All right, so maybe they're still coming in at too fast a rate...

    Less Enemies Per Second, Please

    Right now, the enemies are being created at a rate of one new enemy per tick - and since a tick is 25ms, there are 40 ticks per second, and therefore 40 new enemies per second.

    Let's reduce this to something more manageable: about two enemies per second.

    Since that's 1/20th of our current rate, we could achieve this by keeping track of how many ticks have passed, and creating a new one on tick number 20, tick number 40, tick number 60, and so on. But I think it'll be more fun if instead we make there be a 1/20 chance of a new enemy being creates on any given tick. This way, sometimes we'd create more than two new enemies in one second, and sometimes we'd create less, but it'd average out to two per second. The uncertainty involved would make the game a little more exciting (though perhaps "exciting" is a poor choice of words at this early stage of the game's development...).

    How can we do this, then? Well, we know that Math.random() create a random number between 0 and 1. Since these random numbers are evenly spread out between 0 and 1, that means there's a 1/20 change of the number generated being somewhere between 0 and... well, 1/20.

    In other words, the chance of Math.random() < 1/20 being true is 1/20.

    So, let's change our code to make use of this fact:

    function handleTick() {
    	var gameCanvas = document.getElementById("gameCanvas");
    	var currentEnemyNumber = 0;
    	var numberOfEnemies = enemyXPositions.length;
    
    	if (Math.random() < 1/20)
    	{
    		enemyYPositions.push(0);
    		enemyXPositions.push(Math.random() * 400);
    	}
    
    HTML5 avoider game tutorial
    Click to try it out.

    Much better! Feel free to experiment with that condition to find a value that works for you.


    Wrapping Up

    That's it for this part of the series. We've now built a rudimentary game - not a polished game, not a particularly fun game, but a game nonetheless.

    If you'd like to challenge yourself before the next part, have a go at making these changes:

    • Easy: The enemies 'pop' onto the top of the canvas; make them slide in, instead.
    • Easy: Some of the enemies are created partially off the side of the canvas; stop this happening.
    • Medium: The enemies all move at exactly the same speed, which is pretty dull; allow them to have different speeds.
    • Hard: The avatar can move off the right edge of the canvas, making it impossible for any enemies to touch it (assuming you've completed the second easy challenge). Make sure the avatar stays inside the boundaries.

    Enjoy!



    View full post on Activetuts+

Oct 28, 2011 Posted on Oct 28, 2011 in Hints and Tips | 10 comments

Activetuts+ Quiz #5: Web App Acronyms

It’s quiz time! This month, let’s see how well you know your acronyms. AS3, OOP, HTTP, OMG!


Let’s Get Quizzy


Just So You Know…

This quiz was built with the jQuizzy Quiz Engine by Siddharth, ace reviewer for Envato. jQuizzy is available for purchase over on Codecanyon :)



Thanks also to Orman Clark and MediaLoot for their graphical contributions to the Activetuts+ Coffee Break Quizzes.


What Would You Like To Be Tested On?

If you’ve got an idea for an Activetuts+-related quiz subject, let us know in the comments!



View full post on Activetuts+

Oct 27, 2011 Posted on Oct 27, 2011 in Hints and Tips | 10 comments

Fantastic Prizes Up for Grabs in the Tuts+ Survey!

We love the community of readers we have at Tuts+ and your opinion is incredibly valuable. This week, we’re giving you the chance to have your say about Tuts+, and win a few fantastic prizes at the same time! Read on to find out how to get involved and stand a chance of winning a copy of Adobe Creative Suite…


The Prizes!

We have a few fantastic prizes up for grabs, and the winning entries will be chosen at random when the survey closes in one week. Here’s what you stand a chance of winning:


1st Prize: 1 x Adobe Creative Suite 5.5 Web Premium

This prize has been kindly donated by Business Catalyst. Adobe Creative Suite 5.5 Web Premium software provides everything you need to create and deliver standards-based websites with HTML5, jQuery Mobile, and CSS3 support. Design immersive digital experiences and apps across desktops, smartphones, tablets, and televisions.

You’ll find plenty of incredible software inside, including Photoshop CS5 Extended, Illustrator CS5, Flash Professional CS5.5, Dreamweaver CS5.5, and Fireworks CS5. It’s the perfect accompaniment to everything we teach at Tuts+!


Runner-Up Prize: 4 x Six Month Tuts+ Premium Memberships

Four lucky runners up will receive a six month subscription to our Tuts+ Premium membership programme, completely free of charge! This is a brilliant way to expand your knowledge in different creative areas, and access a regular selection of incredibly high-quality tutorials and resources. You’ll be a pro in no time!


Competition Sponsored by Business Catalyst

Business Catalyst is a Adobe’s new hosted service for building business websites, replacing 5+ separate tools with one integrated solution.

Incorporating web hosting, content management, eCommerce features, email marketing and built in customer management tools, Business Catalyst can help you accelerate your projects and increase your profit margins. Try it out for free at businesscatalyst.com.


Complete the Survey

It just takes a few minutes to complete the survey, and we really value your opinion. We’ll be using the information from our readers to make the Tuts+ network better than ever, so this is your opportunity to let us know what you’d like to see change on the sites!

Take the Survey & Enter the Competition


Competition Rules

  • Please don’t enter more than once – if you do, none of your entries will count.
  • The winners will be picked randomly and contacted by email.
  • The competition closes in exactly one week. Any entries after that time period won’t count.
  • We’d love to hear your honest feedback, so feel free to say exactly what you think!

Thanks for taking the time to share your thoughts about the Tuts+ network. We really appreciate it, and look forward to hearing what you have to say!



View full post on Activetuts+

Oct 27, 2011 Posted on Oct 27, 2011 in Hints and Tips | 10 comments

AS3 101: Events – Basix

For this chapter of AS3 101, we will be diving into the mechanics of the Flash event system. If you’ve been following along so far, you’ll have seen events in use, dating all the way back to the first episode of the series. The editor and I felt that it was time to write up something to be formally included in the curriculum, so if you’ve ever seen those lines of code about adding event listeners or dispatching events, and not quite caught on, then this is the tutorial for you.

There already exists an Activetuts+ tutorial on the basics of Events, so the focus of this tutorial will be on dispatching events from your own classes, including creating custom event types and objects.

To be successful with this tutorial, you should feel comfortable with writing and using your own classes in ActionScript 3, as well as feeling secure with using the existing events provided by Flash, such MouseEvent.CLICK or Event.ENTER_FRAME. We will be focusing primarily on dispatching custom events from custom classes.


Preview

We’ll spend a lot of time on the theory for this tutorial, but in the end we’ll build a simple slider control that dispatches its own events:


Step 1: Why Use Event Dispatching?

This example is actually a rather simple example of why you’d want to dispatch your own events. When you write your own classes, you are ideally keeping them in their own black boxes and encapsulated. But you still need to have the various objects interoperate in order to create a useful program.

The event model provided by ActionScript 3 is a rather good and convenient way to facilitate communication between your classes, while maintaining a separation of responsibilities in your classes. So if we write our own custom class, such as the ActiveSlider class showcases above, we have a need to enable other objects to be aware of when the slider changes its value. If the slider can dispatch its own change event, then other objects that need to know that information can easily subscribe and be notified.

Personally, I find the need to dispatch my own events in my classes so common that my class template sets up each new class with the boilerplate it needs to be able to do so. As you learn to keep objects discrete, you’ll turn to event dispatching as the most common technique to do so.


Step 2: How to Dispatch Your Own Events

I have good news: dispatching your own events is actually very simple. It is one of the core tenets of ActionScript 3, built in to the Flash Player, and as such there is only one thing you need to do in order to gain the ability to dispatch events. This one thing is:

Extend EventDispatcher

That’s it: when writing your class, use the line:

public class MyClass extends EventDispatcher {

Of course, you need to import EventDispatcher, which is in the flash.events package. You will most likely need other classes in the package, so it might be most convenient to simply import the package with a wildcard.

import flash.events.*;

Step 3: Dispatch

Now you’re set up to dispatch an event. All you need to do now is call a method provided by EventDispatcher named dispatchEvent. Easy to grasp, no?

When you call dispatchEvent, you must provide at least one argument, an Event object. All built-in Event objects are in the flash.events package, so here’s where that wildcard import comes in handy. Each type of Event object will have its own requirements, but most often you simply need to pass it just one argument, as well. This argument is the event type, which is a String that names the event, like "click" or "complete". These are more commonly written as MouseEvent.CLICK or Event.COMPLETE, but the end result is the same; it’s an identifier that separates one type of event from another, and allows one Event object to manage multiple event types.

So, putting it all together, if you wanted to dispatch a "complete" event, you could do so like this:

dispatchEvent(new Event(Event.COMPLETE));

Just drop that line (or one like it) in whichever method it’s appropriate in your class. Your class will then utilize its inherited event dispatching system and any listeners will be notified for you. Speaking of listeners, let’s take a brief look at those, as well.


Step 4: Listen

Any other object in your application can listen for your custom events now. More good news: this is no different than registering for events for the built-in classes. In the previous step, we set up our hypothetical class to dispatch a COMPLETE event. To listen for that event, we could write this line somewhere else in our program:

var myObject:MyClass = new MyClass();
myObject.addEventListener(Event.COMPLETE, myCompleteHandler);
function myCompleteHandler(e:Event):void {
    trace("My object completes me.");
}

And that’s it. This should look familiar to anyone who has hooked up a COMPLETE listener to a Loader, for instance, so I won’t dwell any further on this.


Step 5: Where to Dispatch

Where you actually place the dispatchEvent line of code requires some consideration. Typically, it should be the last line of code of the method in which it is written. This is so that any other code that also runs in that method can set properties or otherwise update the internal state of the object. By dispatching after this internal update is complete, the object is in a “clean” state at the time of the dispatch.

Consider, for example, our working example. Let’s say the COMPLETE event is all about the processing of some data; a bunch of data so large that it will take several seconds to completely process, so the object’s purpose is to handle the processing asynchronously so as not to block the UI. And we’re dispatching the COMPLETE event as a way of saying that the data has been processed.

Now suppose that the main method in question looks something like this:

private function processDataChunk():void {
    _data += someDataProcess();
    if (done()) {
        closeData();
    }
}

OK, not very realistic, but it illustrates the point. We keep building up the internal data until some other internal logic determines we’re done, at which point we then write out some final bits of data to close the operation.

Now, let’s add the dispatchEvent call:

private function processDataChunk():void {
    _data += someDataProcess();
    if (done()) {
        dispatchEvent(new Event(Event.COMPLETE));
        closeData();
    }
}

What’s the issue with this approach? Any code that executes within listeners for the COMPLETE event will run before the closeData method is called. Therefore, the state of the dispatcher changes more than once within the span of the processDataChunk method, and is not “stable” until after the closeData call. Yet, we tell all of our listeners that we’re complete before that call. This could lead to some hard-to-track-down bugs where one object claims to be COMPLETE but really isn’t. The obvious solution is to switch some lines around:

private function processDataChunk():void {
    _data += someDataProcess();
    if (done()) {
        closeData();
        dispatchEvent(new Event(Event.COMPLETE));
    }
}

Step 6: Custom Events

You’re all set up to dispatch your own events. Now, what should you dispatch? There are a few options to consider:

  1. Simply reuse an event object and event type already provided by the Flash Player
  2. Reusing an existing event object, but provide a custom event type
  3. Re-Dispatch an existing event
  4. Create a custom event object
  5. Push vs. pull

This first option we’ve already seen in our previous examples. We have a need to dispatch an event related to the completion of some process, and as it happens Flash provides an event type (COMPLETE) associated with an event object (Event) that fits our criteria. We have no need to provide additional data with the event. Dispatching an Event.COMPLETE event is all we need.

We’ll explore these other options in the forthcoming steps.


Step 7: Custom Event Types

As hinted at back in the “Dispatch” step, event types are simply String identifiers. They can technically be any String you like. It’s usually sufficient to make it a single word (like “complete” or “click”) or very short phrase (like “ioError” or “keyFocusChange”); it only has to be unique within a given event dispatcher’s realm of available events.

In addition, Event objects (including subclasses, like MouseEvent or ProgressEvent) don’t really care what event type they are given when instantiated. An EventDispatcher will gladly dispatch events of any type identifier and of any class (as long as it’s the Event class or a subclass).

The upshot of this is that you can make up your own event type String, dispatch it, and set up listeners with it, and everything will be just fine. This is helpful when you want to dispatch an event but can’t necessarily find a good representation of the nature of the event in the built-in classes.

As an example, you might have a class that acts as a coordinator for several things at once: load some XML, load some images based on the XML data, and create a layout based on the loaded images’ sizes, ready for an initial animation, at which point you’d like to dispatch an event. While the COMPLETE event might be suitable, you may feel that a “ready” event more appropriately encapsulates the meaning.

This is as simple as deciding on the String to use, and then using it. Use it both when adding listeners, and when dispatching the event. If the String matches, the event will get to where it needs to go. For example, this is a partial listing of a hypothetical class:

public class MyClass extends EventDispatcher {

    // ... A bunch of other stuff not shown.

    private function determineReadiness():void {
        if (everythingIsReady) {
            dispatchEvent(new Event("ready"));
        }
    }

}

And code from elsewhere in the same program:

var myObject:MyClass = new MyClass();
myObject.addEventListener("ready", onObjectReady);

function onObjectReady(e:Event):void {
    // Do stuff now that it's ready.
}

And that would work.

However, it’s worth mentioning while we’re here that typing in matching Strings all over the place is not a good practice. The possibility for error is high, and the event system won’t tell you that you’ve typed "raedy" instead of "ready". The fact that the event system is flexible and simple to use – just pass it any old String for the event type – is also something of a weakness. Your dispatcher will gladly accept a listener for anything, even a "raedy" event. It doesn’t really reconcile what event types are registered against what event types are actually dispatched.

To help prevent this, the standard approach is to simply put the String you want to use in a static constant somewhere, and then never use that literal String again. Only use the constant. Of course, the possibility of typos is just a great as before, but if you’re using a READY constant and not the "ready" literal String, a mistype will trigger a compiler warning. You’ll be able to correct your error quickly and easily. A mistype with the literal Strings produces no compiler error, nor does it produce a run-time error. The only thing that happens is that the SWF does not seem to work properly, because the event listener doesn’t fire.

With this in mind, it’s most common to store these constants on the related Event class. We’ll get to custom Event classes in just a few steps. But in the situation outlined in this step (i.e., we’re reusing an Event class but not an event type), I find it more convenient to simply store that constant on the dispatcher class. So we might choose to do this:

public class MyClass extends EventDispatcher {

    public static const READY:String = "ready";

    // etc.

    private function determineReadiness():void {
        if (everythingIsReady) {
            dispatchEvent(new Event(READY));
        }
    }

}

And:

var myObject:MyClass = new MyClass();
myObject.addEventListener(READY, onObjectReady);

function onObjectReady(e:Event):void {
    // Do stuff now that it's ready.
}

This gives us the safety of storing event types in constants, while not forcing the inconvenience of creating a whole Event class that we don’t need. I must stress that this is a stylistic choice, and you may feel free to use this technique or not. I felt it warranted explanation, so that you could make your own informed decision. In either regard, you should definitely store your custom event type Strings in static constants. Where those static constants are defined is up to you.


Step 8: Re-Dispatching Events

There are several times when one class (let’s call it ClassX) owns a property that is typed as another class (we’ll call that one ClassY), while itself being owned by a third class (how about ClassZ?). ClassX is listening for an event from ClassY, but not only do we want to have ClassX respond to the event, we also want to consider that ClassX should dispatch a similar (or even the same) event so that ClassZ can also take further action.

As a more concrete example, we have a class (this will be “ClassX“) that is a sort of data manager. It loads an XML document, parses it, and stores data from the XML in its own properties. So it has an URLLoader object (this would be “ClassY“), and listens for the Event.COMPLETE event for when the XML document is loaded.

Then we have a main document class that owns the data manager (the document class is “ClassZ“). It’s coordinating the data loading with other UI elements, so it wants to know when the data is loaded and ready, so it can proceed to create and layout UI elements based on the data.

public class DataManager extends EventDispatcher {
    private var _xmlLoader:URLLoader;
    public function DataManager() {
        _xmlLoader = new URLLoader(new URLRequest("some.xml"));
        _xmlLoader.addEventListener(Event.COMPLETE, onLoadComplete);
    }
    // ... A bunch of other stuff
    private function onLoadComplete(e:Event):void {
        // ... XML parsing
        // With the XML parsed, we'd like to dispatch another event to signal being done.
    }
}

We could do this:

dispatchEvent(new Event(Event.COMPLETE));

But we could also do this:

dispatchEvent(e);

Here we simply re-dispatch the existing event. Not only do we reuse the event type and the Event class, but we’re actually reusing the entire Event object as it was passed in to our own listener.

It’s not rocket science, but it is a handy little technique that is surprisingly not so obvious.

“But wait,” you must be thinking, “if we redispatched an event that originated from the URLLoader object, wouldn’t the target of the event still be _xmlLoader when it gets back out to the document class?” And you would have a very good and thoughtful point, and I would be proud of you for thinking so studiously, but you would be wrong.

A rather magical thing happens when redispatching events. The target property gets set to the current dispatcher. You can find a working example of the code in this step in the download package, entitled redispatch.

Actually, it’s not all that magical. When calling dispatchEvent, if the Event object that is passed in already has a target set, then the clone method is called on the Event, creating an identical but discreet copy of the original Event, except for the value contained in target.


Step 9: Custom Event Objects

Everything mentioned so far is something you will want to know. But there will come a point when the best thing to do is to dispatch your own custom event. Not just a custom event type, but a whole custom Event class.

The process for doing this is straightforward, you just need to follow a few steps. We’ll discuss these in due course. Note that quite a bit of this is boilerplate code, and you could easily create a template for an Event subclass and change just a few key pieces and be off and running. The general steps, in shortened-as-if-you-knew-what-I-was-talking-about form:

  1. Subclass Event
  2. Call super(...)
  3. Store event types in public static constants
  4. Declare private properties to hold custom data
  5. Create public getters to provide read-only access to the custom info
  6. (Optional) Override the clone method
  7. (Optional) Override the toString method

To explain these process more deeply, we’ll get a start on our slider project and create the SliderEvent we will need for that. So we need to start our project before we can write some code, so a quick diversion in the next step, then we’ll start writing a custom Event class.


Step 10: Create the Project Structure

We’ll keep things pretty simple for this one, but we’ll nonetheless create packages for our classes.

Start by creating a folder for the entire project. Mine will be called slider.

Inside of this, create a com folder, and inside of that, an activetuts folder.

Now create two folders inside of activetuts: events and ui. Your final folder structure should look something like this:

  • slider
    • com
      • activetuts
        • events
        • slider

Now back to our Event class.


Step 11: Subclass Event

First, create a new text file in the slider/com/activetuts/events folder, and call it SliderEvent.as. We’ll pop in the boilerplate for any class first:

package com.activetuts.events {

    public class SliderEvent {

        public function SliderEvent() {

        }

    }

}

There should be nothing surprising here, and if you have ActionScript templates for your text editor, you shouldn’t even have to type that much in.

Now, we’ll modify this so that it extends Event.

package com.activetuts.events {

    import flash.events.Event;

    public class SliderEvent extends Event {

        public function SliderEvent() {

        }

    }

}

As you can see, we simply import the Event class, add extends Event to the class definition.


Step 12: Call super

Our superclass can handle a lot for us, which is great, but we do need to make sure we initialize the superclass properly when we initialize our subclass. We need to set up the constructor with arguments matching those found on Event‘s constructor, and pass those along with a call to super.

package com.activetuts.events {

    import flash.events.Event;

    public class SliderEvent extends Event {

        public function SliderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) {
            super(type, bubbles, cancelable);
        }

    }

}

This is, so far, basic subclassing techniques. In fact, depending on your editor’s prowess with templates, you may be able to specify a super class when you create the file and have all of this done for you. Flash Builder, for example, is able to do this.


Step 13: Store Event Types in Public Static Constants

Presumably, there will be one or more event types associated with this event class. Just like the COMPLETE event is associated with the Event class, and the CLICK even with the MouseEvent class, our custom event class will likely have custom event types.

This is as simple as writing a line like the following for every event type you would like to add:

public static const EVENT_TYPE:String = "eventType";

Let’s do that now for the SliderEvent class.

package com.activetuts.events {

    import flash.events.Event;

    public class SliderEvent extends Event {

        public static const CHANGE:String = "sliderChange";

        public function SliderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) {
            super(type, bubbles, cancelable);
        }

    }

}

We could theoretically use our class now. We can use the SliderEvent in dispatchEvent, and listen for and create events with the SliderEvent.CHANGE event type.

But we won’t stop there. There is more to consider. But before we do more code-writing, we need to take another detour into theory.


Step 14: Push vs. Pull

When an event is dispatched, sometimes it’s enough to simply know that the event has occurred. For example, most times that you are interested in Event.ENTER_FRAME, Event.COMPLETE, or TimeEvent.TIMER events, you probably just want to know that the event happened. There are other times, though, when you probably want to know more. When listening to MouseEvent.CLICK, you might be interested in whether the Shift key was held down, or the coordinates of the mouse at the time of the click. If you’re listening to ProgressEvent.PROGRESS, you will most likely want to know the actual progress of the load; that is, how many bytes have loaded and how many there are to load in total.

The difference between these two methodologies is sometimes known as “push” and “pull.” Those terms refer to how the event listener gets data related to the event. If the data is “pushed” then there is data stored within the event object, and in order to get the data the listener merely need to use properties on the event object. If data is to be “pulled,” though, generally the event object has very little information contained within – just the necessities: the type, the target, etc. This target, though, is indispensable, as it provides access to the event dispatcher to the event listener, allowing the listener to get the data it needs from the dispatcher.

In other words, you can either push a bunch of data to the listener inside the event object, or you can require the listener to pull the data out of the dispatcher as needed.

The pros and cons of each technique are somewhat balanced, in my opinion, and the path you choose for your event object depends on the situation at hand, and not a little bit on personal preference.

Exhibit A:

  Pros Cons
Push
  • Data is easily accessible in the event object
  • You may be pushing data that is unneeded. Bloating the event object with a bunch of data that is rarely used could lead to memory and/or performance issues.
Pull
  • Very easy to write. You probably don’t need a custom Event class to execute a pull event.
  • Very easy to use. If it’s just an Event class, the only required argument is the event type.
  • If data commonly pulled out of the dispatcher is expensive to compute and return, you may be taking a hit on performance by requiring the dispatcher to continually hand out that information.
  • Some data might be difficult to pull, e.g. the KeyboardEvent has a keyCode property to detail the key that was pressed to trigger the event.

This might be a good discussion for the comments; I’m sure many of you reading have passionate feelings about which methodology is better. Personally, I try to find the method that works best for the situation.

Having said that, it’s worth noting that to this point our SliderEvent class is rather “pull-ish.” For the sake of illustration, and because it’s not a terrible idea (though I did come up with several of those), we’ll continue on with making this an event that pushes data along with it; namely the value of the slider when it was changed.


Step 15: Declare Private Properties to Hold Custom Data

To implement a push event, we need to have a place to store the data being pushed. We’ll add a private property for that purpose.

You should still have SliderEvent open (if not… what are you waiting for?). Add the highlighted line:

package com.activetuts.events {

    import flash.events.Event;

    public class SliderEvent extends Event {

        public static const CHANGE:String = "sliderChange";

        private var _sliderValue:Number;

        public function SliderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) {
            super(type, bubbles, cancelable);
        }

    }

}

Next we’ll modify the constructor so that we can accept a value parameter, and set the private property with that:

public function SliderEvent(type:String, sliderValue:Number, bubbles:Boolean=false, cancelable:Boolean=true) {
    _sliderValue = sliderValue;
    super(type, bubbles, cancelable);
}

This way we can easily create the SliderEvent and set up its push data in one line.

Why use private properties? In this case, we want to protect the data. In my opinion the data related to an event is immutable, so long as it’s associated with the event. Being able to change the data of an event object is like editing a history textbook. To be fair, this is my opinion and the standard used by Adobe with their built-in classes is to use writable properties (technically they use private properties and public getters and setters, but the end result is the same).


Step 16: Create Public Getters for the Custom Data

So the next step would be to make sure we can access the data being pushed. A private property by itself is not useful to this purpose. Therefore, we need to write a public getter for the _sliderValue property. We will choose to not write a setter, so that the property becomes read-only (as discussed in the last step).

Add this method to the class:

public function get sliderValue():Number {
    return _sliderValue;
}

This adds a getter so we can access the sliderValue in property-like fashion. I’m choosing not to add the matching setter. You can add one if you feel it’s worthwhile.


Step 17: Override the clone method

I mentioned the clone method a little while ago. You probably won’t call clone much yourself, but it’s not a bad idea to override the clone method so that your custom event plays nicely with the event system.

Add this method to your class:

override public function clone():Event {
    return new SliderEvent(type, sliderValue, bubbles, cancelable);
}

First, notice the signature of this method. We’re using override because this method is declared in Event, and we’re inheriting it. It also returns an object of type Event. Make sure, when writing your clone override, that you put the correct return type in. It’s easy to forget and put the type of your class there, but that will cause an incompatible override error, because the return types need to match.

All we’re really doing in the meat of the event is creating a new SliderEvent and passing in the same values that we have stored in the current event object. This creates an identical but discreet copy: a clone.

This is an optional step, but it’s a quick win and ensures that your custom event plays well with the rest of the event system.


Step 18: Override the toString method

One last thing, and again this is optional. But it’s also very useful as a debug tool, so it usually pays for itself within a few uses.

In case you haven’t been told yet, the toString method exists on all objects (it’s declared and defined in Object, the über-class from which all other classes inherit, whether you like it or not). It can be called explicitly, but the handy thing is that it get called automatically in a number of cases. For example, when you pass object to the trace function, any object that is not already a String will have toString called on it to make sure it is formatted nicely for the Output panel. It even gets called when working with Objects together with Strings, as with concatenation. For example, if you write this:

"The answer to life, the universe, and everything is " + 42;

ActionScript is smart enough to convert 42 into a String representation of the Number before concatenating the String. Trying to add a String and a Number is bad news, but converting a Number to a String and then concatenating it with another String is just fine.

So when you write your own classes, you can provide a toString method, which takes no arguments and returns a String, and return whatever String you like.

In the case of Event objects, Adobe helpfully provides a formatToString method to help all Events look similar when traced. We’ll use it in the method we’re about to add to our class:

override public function toString():String {
    return formatToString("SliderValue", "type", "sliderValue");
}

First, note the method signature. Again, it’s an override so we have that keyword. It’s public, it takes no parameters, and returns a String (which should be obvious).

Next, note the single line in the method body. We call formatToString, which is defined in Event, so it’s easy to use. The first argument we pass to it is the String name of the class. After that, the arguments are open-ended. You can pass in one, 15, or none. We’re passing in two. No matter how many you pass in, they should all be Strings, and they should match property names on your class. "type" is defined by Event, but "sliderValue" is defined by our own class. Either way, what happens is that the name of the property is printed, followed by an equals sign, which is followed by the actual value of that property. In short, it will end up looking like this:

[language="text"]
[SliderValue type="sliderChange" sliderValue=0.34146341463414637]

This is entirely non-functional but very useful. It can provide a quick glimpse into the event when things aren’t working the way you think they should.


Step 19: Building the Slider

At this point, we’ve been through the key concept of this tutorial: writing a custom Event class. But we really need to put it to the test. We’ll spend the remainder of our time building the simple slider application that was previewed at the beginning of the tutorial.

We already have a project folder structure; we just need a few more files. We’ll start with the FLA file.

Create a new Flash file (ActionScript 3.0, of course) and save it as ActiveSlider.fla in the root of your project folder. I’m going to assume that you don’t need step-by-step details on how to put this simple FLA together, and instead I’ll lay out the key elements. You can use the FLA file found in the start folder of the download package for reference, as well, or even just copy that FLA to your project folder and call this step done.

There are three main objects on the stage.

  1. The slider track. This is a long, narrow strip that indicates to where the slider can be moved. The slider moves “in” the track.
    • Needs to be a Movie Clip
    • For easiest math, should have artwork arranged so that the registration point is at the top left corner
    • Name it track_mc
    • Place in the upper center; it should take up most of the width of the stage and have space below it.
  2. The slide grip. This is a button-sized element that indicates the current position of the slider. It’s the piece that moves along the track and responds to the mouse.
    • Needs to be a Movie Clip.
    • Again, for math, should have the registration point at the top left
    • Name it grip_mc
    • Place it over the track, so that it is vertically centered with the track, and somewhere within the left and right ends of the track
    • It should be stacked on top of the track, so that the grip obscures the track (put it on a layer higher)
  3. The output field. This is a text field that, for our own demonstration purposes, displays the current value of the slider.
    • Needs to be a dynamic Text Field.
    • Name it output_tf
    • Fonts are inconsequential; set it to whatever you like and embed as necessary
    • Place it in the lower portion of the stage, so that it doesn’t conflict with the space required by the slider.
The stage of our FLA

Other than hooking up the document class, which we’ll write in two steps, the FLA is ready for business.


Step 20: The ActiveSlider Class

The main UI class with which we’ll work is the ActiveSlider class. This will extend EventDispatcher, target the two Movie Clips on the stage, and set up mouse interactivity for slider behavior. Most exciting of all, it will dispatch a SliderEvent.

Start by making a new class file called ActiveSlider.as in the com/activetuts/slider folder of your project. This class isn’t too intense (at least, not for our purposes here. A slider class could get much more involved), and I’ll just present the code in full and discuss as we go:

package com.activetuts.slider {

    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

Nothing exciting, just setting up the package and imports.

    public class ActiveSlider extends EventDispatcher {

        private var _track:Sprite;
        private var _grip:Sprite;
        private var _grabOffset:Point;

We’ll need these three properties. The first two keep track of the Sprites (or MovieClips) that make up the slider. The third is used while dragging the slider grip; it helps keep the grip’s position offset from the mouse by an amount relative to where the grip was clicked in the first place.

        public function ActiveSlider(track:Sprite, grip:Sprite) {
            _track = track;
            _grip = grip;
            if (_grip.parent != _track.parent) {
                throw new Error("The track and the grip Sprites are not in the same container.")
            }

            _grip.addEventListener(MouseEvent.MOUSE_DOWN, onDown);

            if (_grip.stage) {
                addStageListener();
            } else {
                _grip.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            }
        }

This is the constructor. It accepts two Sprite arguments, which get passed on to the first two of those properties for storage. It then does a simple check to make sure the two Sprites are in the same coordinate space by checking that their parent properties reference the same object. If they don’t, then our math for placing the grip might be unreliable, so we throw an error as a way of alerting the developer. The rest of the constructor is devoted to adding two event listeners. The first is a MOUSE_DOWN event and straight forward. But the second is trying to add a MOUSE_UP event to the stage, which might or might not exist depending on whether the grip Sprite is on the display list or not. The next two methods might make this a little clearer:

        private function onAddedToStage(e:Event):void {
            _grip.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            addStageListener();
        }

        private function addStageListener():void {
            _grip.stage.addEventListener(MouseEvent.MOUSE_UP,   onUp);
        }

The onAddedToStage method is an event listener for the ADDED_TO_STAGE event, which was set up in the constructor, but only if the grip Sprite did not already have a reference to the stage. The addStageListener method simply adds the MOUSE_UP event listener to the stage. So, if there is a stage reference in the constructor, we call addStageListener directly. If there is not a stage reference, we set up the ADDED_TO_STAGE event, and when the grip is added to the display list, and thus has a stage reference, the onAddedToStage method fires which then in turn calls addStageListener. It also removes the ADDED_TO_STAGE event listener, because we only need to do this once.

        private function onDown(e:MouseEvent):void {
            _grabOffset = new Point(e.localX, e.localY);
            _grip.addEventListener(Event.ENTER_FRAME, onFrame);
        }

        private function onUp(e:MouseEvent):void {
            _grip.removeEventListener(Event.ENTER_FRAME, onFrame);
        }

Next we have our two mouse event listeners. In onDown, the key line is to then add an ENTER_FRAME event listener. In onUp, we remove that listener. Also in onDown, we make note of where on the grip the mouse click actually happened, and store that in _grabOffset. This will play into our onFrame method next.

        private function onFrame(e:Event):void {
            _grip.x = _grip.parent.mouseX - _grabOffset.x;

            var gripBounds = _grip.getBounds(_grip.parent);
            var trackBounds = _track.getBounds(_grip.parent);

            if (gripBounds.x &lt; trackBounds.x) {
                _grip.x = _track.x;
            } else if (gripBounds.right &gt; trackBounds.right) {
                _grip.x = trackBounds.right - gripBounds.width
            }

            trace(this.value);
        }

This is the main meat of our slider logic. This method fires repeated on an ENTER_FRAME event, but only when the mouse has been pressed down on the grip, and only for as long as the mouse remains pressed.

First, we set the grip’s x property to match the mouse position, only we need to offset it based on the original mouse position, so that it moves smoothly and doesn’t jump so that its left edge is at the mouse.

The next two lines calculate the bounding rectangles of both the grip and track Sprites. We’ll use these rectangles in the upcoming math, so we’ll keep things tidier by pre-calculating the rectangles and storing them in variables.

Then there is the if block. This just constrains our slider to within the track. It’s a simple check to see if the x of the grip, as calculated in the first line of the method, is lower than (to the left of) the x of the track. If it is, it would be too far, so we need to move the grip to that minimum value. Similarly, we check to see if the grip’s right edge is greater than (to the right of) the track’s right edge, and if so we need to reel it back in to that maximum value.

Finally, we have a reliable grip position, and for now we just trace the current slider value, which is calculated in the final bit of code for the class:

        private function get value():Number {
            return (_grip.x - _track.x) / (_track.width - _grip.width);
        }

    }

}

This is a simple getter, although the math being used for the return value might be a little confusing. It determines the current grip position as a percentage of the range of motion of the grip. It would be more obvious if it were just this:

return _grip.x / _track.width;

…which is reasonable but doesn’t take into account that the grip doesn’t actually travel the entire width of the track. It goes all the way to the left edge, but only as far right as the right edge of the track minus the width of the grip. So this is more accurate:

return _grip.x / (_track.width - _grip.width);

This makes the width by which we divide the range of motion. However, there may still be a gotcha in that the track may be offset to the left or right from its container, meaning that the values we get aren’t quite right. We need to neutralize that by subtracting the x position of the track from the grip’s x, and we end up with this:

return (_grip.x - _track.x) / (_track.width - _grip.width);

For reference, here is the complete class, with my ramblings left out:

package com.activetuts.slider {

    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

    public class ActiveSlider extends EventDispatcher {

        private var _track:Sprite;
        private var _grip:Sprite;
        private var _grabOffset:Point;

        public function ActiveSlider(track:Sprite, grip:Sprite) {
            _track = track;
            _grip = grip;
            if (_grip.parent != _track.parent) {
                throw new Error("The track and the grip Sprites are not in the same container.")
            }

            _grip.addEventListener(MouseEvent.MOUSE_DOWN, onDown);

            if (_grip.stage) {
                addStageListener();
            } else {
                _grip.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            }
        }

        private function onAddedToStage(e:Event):void {
            _grip.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            addStageListener();
        }

        private function addStageListener():void {
            _grip.stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
        }

        private function onDown(e:MouseEvent):void {
            _grabOffset = new Point(e.localX, e.localY);
            _grip.addEventListener(Event.ENTER_FRAME, onFrame);
        }

        private function onUp(e:MouseEvent):void {
            _grip.removeEventListener(Event.ENTER_FRAME, onFrame);
        }

        private function onFrame(e:Event):void {
            _grip.x = _grip.parent.mouseX - _grabOffset.x;

            var gripBounds = _grip.getBounds(_grip.parent);
            var trackBounds = _track.getBounds(_grip.parent);

            if (gripBounds.x &lt; trackBounds.x) {
                _grip.x = _track.x;
            } else if (gripBounds.right &gt; trackBounds.right) {
                _grip.x = trackBounds.right - _grip.width
            }

            trace(this.value);
        }

        private function get value():Number {
            return (_grip.x - _track.x) / ((_track.width - _grip.width) - _track.x);
        }

    }

}

We have not added in our SliderEvent class yet; we’ll take a separate step to do that. But first, we need our document class so we can actually use the ActiveSlider.


Step 21: The Document Class

We need one more file to make it work: our document class. Make a new class file named SliderDemo in the project root folder. Add in the following code:

package  {

    import flash.display.*;
    import flash.events.*;
    import com.activetuts.slider.ActiveSlider;

    public class SliderDemo extends Sprite {

        private var _slider:ActiveSlider;

        public function SliderDemo() {
            _slider = new ActiveSlider(track_mc, grip_mc);
        }

    }

}

This is much simpler that our ActiveSlider class. It really just sets up an ActiveSlider into the property named _slider.

Go back to the FLA file, and enter SliderDemo into the document class field, and you should be able to try this out. The slider should be able to move back and forth, and constrain itself to the width of the track.

Now for one last task. We need to dispatch, and listen for, a SliderEvent.CHANGE event. We’ll do that next.


Step 22: Dispatching the SliderEvent

Go back to the ActiveSlider class, and make a single-line change to the onFrame method:

private function onFrame(e:Event):void {
    _grip.x = _grip.parent.mouseX - _grabOffset.x;

    var gripBounds = _grip.getBounds(_grip.parent);
    var trackBounds = _track.getBounds(_grip.parent);

    if (gripBounds.x &lt; trackBounds.x) {
        _grip.x = _track.x;
    } else if (gripBounds.right &gt; trackBounds.right) {
        _grip.x = trackBounds.right - _grip.width
    }

    dispatchEvent(new SliderEvent(SliderEvent.CHANGE, this.value));
}

We’ve removed the trace and replaced it with a real, live event dispatch. For this to work, though, we need to import the SliderEvent class:

package com.activetuts.slider {

    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import com.activetuts.events.SliderEvent;

Step 23: Listening For the SliderEvent

Finally, go back to the SliderDemo class, and change it so it listens for and reacts to the SliderEvent:

package  {

    import flash.display.*;
    import flash.events.*;
    import com.activetuts.slider.ActiveSlider;
    import com.activetuts.events.SliderEvent;

    public class SliderDemo extends Sprite {

        private var _slider:ActiveSlider;

        public function SliderDemo() {
            _slider = new ActiveSlider(track_mc, grip_mc);
            _slider.addEventListener(SliderEvent.CHANGE, onSliderChange);
        }

        private function onSliderChange(e:SliderEvent):void {
            trace(e);
            output_tf.text = e.sliderValue.toString();
        }

    }

}

We’re again importing the SliderEvent class, and after creating the ActiveSlider, adding a listener called onSliderChange to the slider. That method is the biggest addition, but still is a regular event listener. It’s much like any other event listener, only we’re making sure to type the event argument as SliderEvent, because that’s what we’re getting.

The first line of code is a bit superfluous, but I wanted to see what happens when you trace our SliderEvent object. You’ll see, when you run this, a typical-for-Flash formatting of the event object.

The event object represented as a String

The second line does what we were after to begin with. It simply grabs the sliderValue property, turns it into a String, then sticks that String into the TextField on the stage, so we can see the slider value in the movie.


Step 24: Wrapping Up

When you start rolling your own custom events, you start working with ActionScript 3 the way it was meant to be used. Events help you decouple classes from each other, and a well structured event flow in your application can really make the difference between something that is easy to work with and something that is buggy and temperamental. With this (theoretically) final instalment of AS3 101, you should be well on your way to becoming a ninja.

Thanks for reading, and I’ll see you back here on Activetuts+ before you know it!



View full post on Activetuts+

Page 1 of 512345»
search search search search search
Find an Article
Categories
  • Flash Video Training
  • Hints and Tips
  • Recommended
Please Support Our Sponsors
Recent Posts
  • Tuts+ Community Meetup in New York!
  • HTML5 Canvas Optimization: A Practical Example
  • Recreate the Cover Flow Effect Using Flash and AS3
  • Drawing Activetuts+ to a Close
  • Intro to Dart: Creating a Marquee
Tag Cloud
2011 ActionScript Active Activetuts+ Adobe animation Basic Basix Best Build Button Character Code Create Creating Critique Custom design Effect Effects Files Flash from Game Guide HTML5 Introduction Macromedia Motion Muzzle part Player Premium Professional Quick Silverlight Simple Text Tool Tutorial Tuts+ Using Video website Workshop
About Our Site:

Hey there and welcome to "Flash Video Training Source", a resource for anybody interested in learning more about Adobe's great tool. We feature educational videos, which will help you master Adobe Flash and help you get to know all of its features. We at "Flash Video Training Source" believe that video training and video... more

Why don't you follow us on Twitter and get the latest video tutorials twitted to your account. Just click on the floating twitter bar to your right!

Go Back In Time
October 2011
M T W T F S S
« Sep   Nov »
 12
3456789
10111213141516
17181920212223
24252627282930
31  
Pretty Blank Box
top

Blogroll

  • Development Blog
  • Documentation
  • Plugins
  • Suggest Ideas
  • Support Forum
  • Themes
  • WordPress Planet

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Archives

  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
Powered by WordPress  |  Designed by Elegant Themes  |  Lightning Fast Hosting by Site 5 Hosting