logo
468x60-2-495


  • Home
  • Privacy Policy
  • About
search
Jun 29, 2012 Posted on Jun 29, 2012 in Hints and Tips | 10 comments

Intro to Dart: Creating a Marquee

In this tutorial, I’ll introduce you to Dart and how to start using it. In the course of the article we’ll build a simple JavaScript-based image marquee without writing a single line of JavaScript – just Dart.

Note: This tutorial was originally published in March 2012, as a freebie for our Facebook fans.


Project Preview

We will be building the following simple marquee, a screenshot of which is shown below. Click on the image to launch a working example of the project.

Click the image to launch the project

Step 1: Install the Dart Editor

Let’s get started building out little marquee. From here on out, we’ll be much more hands-on, and I’ll take the time explain the new stuff along the way.

First things first; we can write Dart in any old text editor, really, but the most convenient way to get started and to immediately run your project in a browser (via JavaScript compilation) is to install the Dart Editor.

Head to http://www.dartlang.org/docs/getting-started/editor/, which should automatically detect your OS and present you with the appropriate download link. It’s not a small download, around 65 MB at this writing, so get it started before continuing to read.

The Dart Editor is rather bare-bones. It’s built on Eclipse, and I hope that eventually it will be offered as an Eclipse plug-in for those with an existing Eclipse installation. But for now, it’s a self-contained Eclipse modification that does Dart and not much else.

It offers a few of the features that Eclipse workspaces typically offer, such as language-aware completion. The big advantage it brings, though, is a fairly simple way to start and run a Dart project.

Once the download completes, extract the ZIP file and you’ll have a dart folder. You can place this wherever you like; I’ve moved mine to my Applications folder.


Step 2: Create a Dart Project

Let’s open up the Dart Editor application. You’ll find it just inside that dart folder you just unzipped.

Once it launches, you’ll be presented with a “Welcome” page, which provides a jumping-off point to some sample projects. These are certainly worth taking a look, but we’ll skip past them for now and first get a little more familiar with the language.

The first thing you'll see when opening Dart Editor

Go to the File menu and choose New Application… or click on the top-left icon in the toolbar:

The 'New Application' tool bar button

In the resulting window, enter a name for the project (I’m using DartMarquee). It will want to store the project in a folder named dart in your home directory, but you can change that by clicking on the Browse… button. Note that whichever folder you choose, Dart Editor will create a new folder in the selected folder, using the name you’ve given for the project. Inside of that there will be a few files created for you, also using the name of the project you supplied.

Also be sure the “Web Application” is selected, not “Server Application.”

The 'New Application' window

Step 3: Run the Hello World Example

The default project created for you is a simple Hello World example. You may as well see what happens before we start building our (slightly) more complicated project. Run the application by either choosing Tools > Run from the menu, pressing Command-R (Mac) or Control-R (PC), or by clicking on the green “play” button in the tool bar:

The 'Run' Button

You may expect this open up in your default browser, but – surprise! – Google’s Chromium browser will open (not to be confused with Chrome; Chromium has a blue-ish monochrome icon, not Chrome’s colorful icon). Chromium has built-in support the the Dart language.

Chromium

This is not the process I mentioned earlier where Dart files are compiled into JavaScript; this is the Dart VM running regular Dart code, which is cool, but not terribly useful for those of us currently building JavaScript applications. We’ll make the project compile to JavaScript next.


Step 4: Add a JavaScript Launch

If you change the run settings, then we can get Dart to compile to JavaScript. To change these settings, choose the Tools > Manage Launches… menu, press Command-Shift-M (Mac) or Control-Shift-M (PC), or click and hold the downward arrow next to the Run tool bar button, and choose Manage Launches… from the pop-up menu.

The Manage Launches option int he tool bar

In the window that appears, you’ll see the default launch created for you, which has the Chromium icon. To create a new launch, click on the new document icon, which will display a pop-up menu.

New Launch targets

Choose Dart Web Launch from the menu. In the top field at the right, give it a meaningful name, like DartMarquee JS or something to designate that we’re going for a JavaScript rendition in another browser.

Under Launch Target, click Browse… next to HTML file:. A window will open that presents all (one) HTML files present in your project. Click on DartMarquee.html and then click OK.

Under Browser you can choose to leave the default checked, or uncheck that option and then specify a browser with the Select… button. The browser choice shouldn’t matter too much, although I will be using some CSS3 tricks so a modern browser would be ideal.

Click Apply and then Close.

Now run the project again, but this time be sure to do it by clicking and holding on the Run tool bar button, and then selecting your new launch target. You should now get the same Hello World application in the browser of your choosing, which will be using JavaScript compiled from Dart. In fact, you’ll see a new file show up in your file list: DartMarquee.dart.js. This is the compiled JavaScript file.

Now that you’ve run the new launch once, future Runs will remember this decision and launch the JavaScript version.

But we’re not done yet. The HTML file is set up to include the Dart file, along with another JavaScript file that interprets Dart files in the browser (which is super-cool, but not the best for production applications). We need to edit the HTML file to use the compiled JavaScript file, not the Dart files.


Step 5: The HTML

Your new project should open with DartMaquee.dart in the main editor area. We’ll get to that soon enough, but let’s get our HTML page set up. Double-click on DartMarquee.html in the file list on the left, and it will open in a new tab in the editor.

Dart Editor is really only aware of the Dart language, which is too bad. You’ll notice that the HTML file opens without any syntax coloring or intelligence about the language. It’s good enough for our purposes now, but feel free to open this file (and any other non-Dart file) in the text editor of your choosing. We won’t be spending too much time in non-Dart files, so I’ll just be editing them in Dart Editor for this tutorial.

The body markup is not what we want, but first let’s update those <script> tags as mentioned in the last step. You can delete the first <script> tag altogether; that’s the once that includes the Dart file directly. Delete this line:

<script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>

(Hint: line numbers aren’t enabled by default, but that’s one of the few options available under Preferences).

The script is the in-browser runtime for Dart; one pretty nifty feature is that you can write Dart without compiling it to JavaScript, and have browsers run it anyway. You just need to include dart.js. Of course, this makes for some extra overhead and impacts performance. Pretty cool trick, though.

Now let’s change the remaining <script> tag to load our compiled JavaScript file. Change this:

<script type="application/dart" src="DartMarquee.dart"></script>

To this:

<script src="DartMarquee.dart.js"></script>

If you like, run the project again, and use the developer tool to ensure that the JavaScript file is loading, and the other two are not.

Now, change that <h2> tag into a <div>, and give it an id of marquee.

<div id="marquee"></div>

You can leave the <h1> if you like; sometimes it’s nice to have page identification.

Finally, we need to link to a CSS file (which we’ll create in the next step). In the <head> add a <link> tag:

<link rel="stylesheet" href="DartMarquee.css">

The application will not work, because we’ve removed the <h2> that was targeted by the Dart code, not to mention that we still need a CSS file. Let’s do that next.


Step 6: The CSS

We’ve linked to a non-existent CSS file, so let’s address that. In the Files area of Dart Editor, right-click, and choose New File: from the menu (you can also find New File… in the File menu).

In the resulting window, you may need to ensure that the DartMarquee project is selected in the middle area. Then enter DartMarquee.css for the file name, and click on Finish.

The New File window

This file will be ready to edit in the main editor area, but as with HTML files, CSS files aren’t intelligently supported with syntax by Dart Editor. Feel free to do your CSS editing in your preferred text editor. Or, since we’re really not here to delve into the CSS, just copy and paste form below into Dart Editor:

#marquee {
    width: 600px;
    height: 400px;
    background-color: #111;
}

.mainImage {
    height: 300px;
    background-color: #666;
    position: relative;
}
.mainImage img {
    display: block;
    position:absolute;
    left: 0px;
    top: 0px;
    -webkit-transition: opacity 0.6s ease-out;
       -moz-transition: opacity 0.6s ease-out;
        -ms-transition: opacity 0.6s ease-out;
         -o-transition: opacity 0.6s ease-out;
            transition: opacity 0.6s ease-out;
}
.mainImage img.fade_away {
    opacity: 0;
}

.thumbContainer {
    height: 100px;
    background-color: #DDD;
}

.button {
    width: 100px;
    height: 100px;
    background-color: #eee;
    position: relative;
    float: left;
}

.button .border {
    width: 90px;
    height: 90px;
    position: absolute;
    opacity: 0;
    border: 5px solid orange;
    -webkit-transition: opacity 0.3s ease-out;
       -moz-transition: opacity 0.3s ease-out;
        -ms-transition: opacity 0.3s ease-out;
         -o-transition: opacity 0.3s ease-out;
            transition: opacity 0.3s ease-out;
    cursor: pointer;
}
.button:hover .border {
    opacity: .5;
}
.button.selected .border {
    opacity: 1;
}

Again, we’re not here to discuss CSS. I’ll point out that I’m using CSS3 transitions for the button hovers and the main image changes. Otherwise, it should be fairly straightforward.

Run the project one more time, or simply reload from the browser; at this point there won’t be any JavaScript to re-compile. If you run from Dart Editor, be sure to switch back to the HTML or Dart file; Dart Editor doesn’t know what to do when you “Run” from a CSS file.

You should see a large dark rectangle. Doesn’t look like much yet, but you’re on the right tack.


Step 7: Preparing the Images

One more housekeeping task, and that’s to make our images readily accessible, so that we can see them when we’re ready to write that code.

In the download package, you’ll find a folder named images. Copy or move this folder from the download archive to your project folder, so that’s sitting at the same level as your other files. You’ll probably need to use the Finder/Explorer for this task, as Dart Editor doesn’t (yet) support importing or drag-and-drop of existing files. They’ll show up in your file list once you get them in place, though.

The project structure so far

Now we can get into some Dart code. That’s next!


Step 8: The main() Function

Open up the DartMarquee.dart file in the editor. You’ll see three main blocks of code:

The three main sections in the default Dart file

The third block is the main function, and this is a required part of your Dart project. Dart will look for this function as an entry point to execution. Contrast this with JavaScript where scripts are simply executed from top to bottom. You can certainly replicate this methodology in JavaScript, but the key difference is that you don’t have to, and if you do you have to call main() yourself; in Dart, it’s expected that you have the main function, as it will be called for you once Dart in ready to begin execution of your application.

This won’t be a foreign concept to you if you’ve programmed in C or Java, or even in ActionScript 3 and used the Document class. The nice thing about it is that there is a standardized, expected place to begin the execution of your code.


Step 9: Classes

Dart brings with it proper classes, which you may end up preferring to JavaScript’s class-ish-ness prototype system. Take a look at the second block of code in DartMarquee.dart. This is the meat of the program right now, and is a class with two methods declared. We’ll be ditching a large part of this code. We’ll get into the syntax as we go, but for now, hollow out this class so that it looks like this:

class DartMarquee {

    DartMarquee() {
    }

}

What this leaves is the class declaration and the constructor. The class declaration begins with class, which is followed by the name of the class. That this class is named DartMarquee is purely a function of the template used in the application creation process in DartEditor. It’s important to know that just because this file is named “DartMarquee.dart” does not mean that there has to be a class name DartMarquee inside. We’re not going to change it, because it makes sense, but Dart is like PHP or Ruby in that you can put as many class definitions as you like in a single file, and the naming doesn’t need to match the file name (as it does in ActionScript).

The class definition is then contained between the curly braces. Inside of that, we have a constructor. This is a function that is run when a new object is instantiated from this class. Typically one puts set-up code in a constructor. Note that the name of the constructor needs to match the name of the class, otherwise it’s not a constructor, and is a regular method instead.

Everything else you add to a class should go in between the two curly braces denoting the class.

You’ll notice that back in the main function, a DartMarquee object is instantiate with this line:

new DartMarquee().run();

This should look like object-oriented JavaScript. The .run() then calls the run method on the newly-created object. We just removed that method, so go ahead and change that line to this:

new DartMarquee();

Step 10: Imports

Something I’m pretty excited about with Dart, as someone coming from JavaScript, is the ability to easily import and use other code into your project. The first block of our default code uses a single import statement:

#import('dart:html');

This imports a built-in Dart library, one that deals specifically with HTML pages and giving us access to DOM manipulation functionality. We’ll be importing other libraries as we need them, including one that we’ll write ourselves.

When our Dart project is compiled to JavaScript, all of the disparate Dart code is converted and concatenated into a single JavaScript file. It’s smart enough to not include the same library twice, so you can import libraries from other files and not worry about them conflicting with or duplicating code in the final product.

Our DartMarquee.dart file should look something like this now:

#import('dart:html');

class DartMarquee {

    DartMarquee() {
    }

}

function main() {
    new DartMarquee();
}

Step 11: Add a Property to the Class

Let’s finally write code. We’re going to add a target property to the DartMarquee class, so that the main HTML element that we’re referencing is handy within the class.

Just after the class declaration, and before the constructor, add a property like so:

class DartMarquee {

    Element _target;

    DartMarquee() {
    }

}

Notice the syntax here: instead of var, we use a datatype to both declare a variable and give it a datatype all at once. This syntax is reminiscent of C and Java. The name of our property is _target, and the line ends with a semi-colon. You’ll find Dart much less forgiving about missing semi-colons.

An interesting thing about Dart type system is that it’s optional. If you specify a type, Dart will do what it can to adhere to typing rules. But we could also opt to leave typing off by writing that property like this:

var _target;

Dart will then not attempt to keep your types safe; you’ll have a dynamically-typed variable just like in JavaScript. What’s even more interesting than the fact that it’s optional is that you can mix strong and dynamic typing in the same code.

Personally, strong typing is one of the things that draws me to Dart, as it’s helpful to have that kind of accountability. This will be the last time I mention dynamic typing in Dart.

We’re not done with that property yet. This is an important property, so let’s set it in the constructor.

class DartMarquee {

    Element _target;

    DartMarquee(this._target) {
    }

}

This may look a little unexpected. This is a Dart idiom; it’s so common for a constructor to receive arguments, and then simply use the constructor’s body to stash those values into properties, that Google created a shortcut.

Normally, a method parameter looks like you’d expect it to: any variable name will do, but not something that looks like a property on another object. These parameters are normal parameters like you’re used to; they’re available by name within the body of the method.

This new syntax, however, will go ahead and assign the value passed in to this parameter to the property designated by the parameter name. In other words, the code above is identical to this code:

DartMarquee(target) {
    this._target = target;
}

Only we don’t have to write that boilerplate of a line.

Note that this shortcut is only available in constructors.


Step 12: DOM Queries

Now that we have a target property set up, we need to give it a value. Back in the main function, we need to select the marquee <div> and pass it in to the constructor.

Dart provides a method to find HTML elements by CSS selection, much like jQuery or any of the popular JavaScript libraries do. This is provided by that dart:html library imported at the top of the file, which also provides a top-level document variable which gives us global access to the HTML document.

Update the main function to look like this:

void main() {
    new DartMarquee(document.query('#marquee'));
}

It’s that simple: if you’ve used jQuery (or another library), this should be rather familiar. Simply call document.query and pass in the selector. Dart does the rest.


Step 13: Console Logging

If you’ve developed with JavaScript, chances are you’ve made heavy use of console.log to test and verify your code. Dart provides a print function that, when compiled to JavaScript, turns in to a call to console.log. Let’s try it out, and test our project so far at the same time.

In the DartMarquee constructor, let’s print the _target property to make sure it’s being set.

DartMarquee(this._target) {
    print(this._target);
}

And hit Run. In your browser, open up your console and you should see something like this:

The result of a print

Note that at the time of this writing, there is a bug with the Dart Editor that generates a warning stating that “print” is not a method. This is being tracked by Google and will probably be fixed soon, if not by the time you read this. But if you’re seeing that warning, just ignore it; it still compiles fine. This is an example of the bleeding edge on which Dart stands; the print warning was not happening when I started writing this tutorial, it’s only happened with the most recent build of the Editor (build 5104).


Step 14: DOM Manipulation

We’re going to create the needed HTML elements programmatically, and place them within our target <div>. Dart provides a very clean API for this kind of task.

First, let’s create a few more properties to hold some of the elements. Add these right below the first property you added:

class DartMarquee {

    Element _target;
    DivElement _mainImage;
    DivElement _thumbContainer;

    DartMarquee(this._target) {

Notice how we’re using underscores as a prefix? Not only this a common convention when naming private properties, it’s actually idiomatic Dart. An underscore prefix makes the property (or method, or class even) private. Otherwise, it’s public.

Also notice how we’ve typed them as DivElement? Another nice feature of Dart (as least for the web) is that it provides classes for the individual HTML elements, unlike the more generic approach usually taken in JavaScript. The upshot is that individual element types have the appropriate properties so it’s easy to manipulate them with Dart. For example, ImageElements have a src property that can be safely and easily accessed directly with Dart to modify the image’s source.

Now let’s create those elements. In the constructor:

DartMarquee(this._target) {
    _mainImage = new Element.tag('div');
    _mainImage.classes = ["mainImage"];
    _thumbContainer = new Element.tag('div');
    _thumbContainer.classes = ["thumbContainer"];
    target.nodes.add(_mainImage);
    target.nodes.add(_thumbContainer);
}

There’s a lot going on here; let’s break it down.

First we create a new DivElement. But notice that we don’t write new DivElement as you might expect (and believe me, I expected that, and continued to expect that for quite a while before I discovered the proper technique). Even though DivElement is a class, it doesn’t have a constructor that you can access. Instead, you use a named constructor on the Element class to create an element of a specific type.

Named constructors are just different constructors (kind of like method overloading, but it’s not really that) that can provide a different interface to the construction. In this case, we can specify by string the type of element. You can also write new Element.html('<div>...</div>'); to write out the HTML in string format. Two rather different approaches, so we have two constructors.

Once we have our _mainImage DivElement, we set its class. Element provides a classes property which lets us access the various classes that may applied. In this case, it’s a brand new element, so that property is empty. We set it to a single class name, "mainImage".

You might expect classes to be an Array (or List, in Dart parlance), but it’s actually a Set. A Set is similar to an Array in that it’s a collection of independent values, but the key difference is that the collection is unordered; there is no guarantee that the order of the contained values will be anything in particular, or even the same each time. This has a slight ramification in how we work with the classes property, but for now it’s a simple assignment to what looks like an Array containing a single String.

The next two lines are repeated almost verbatim, except that we’re assigning the _thumbContainer property, and assigning a different class.

The final two lines add these new Elements to the DOM, specifically, to the target div. As you can see, there is a nodes property on the Element, which as you’d expect is a List of child elements. Being a List (or Array), we can simply add (similar to JavaScript’s push) an Element into it. And at this point, the elements are in the DOM.

Go ahead and run the project again; because we’ve added classes to the new <div>s, and we have our CSS file ready to go, you should see a slight change to the page:

The HTML page as it currently stands

Step 15: Loading JSON

We need some content, not just grey boxes at which to look. We’ll drive our little marquee with a JSON file, so let’s look at how we make an HTTP request in Dart.

First, let’s create the JSON file. It’ll be pretty simple, and shouldn’t need any explaining in and of itself. Create a new file in your Dart project (File > New File…) and name it marquee.json. Add the following content:

{
    "images":[
        "scottwills_machinery3.jpg",
        "scottwills_machinery4.jpg",
        "scottwills_machinery5.jpg",
        "scottwills_machinery6.jpg",
        "scottwills_machinery7.jpg",
        "scottwills_machinery8.jpg"
    ]
}

Save, and turn back to DartMarquee.dart. We’ll add the code to load this file in the constructor, after we’ve created our extra Elements.

XMLHttpRequest request = new XMLHttpRequest();
String url = 'marquee.json';
request.open("GET", url, true);
request.on.load.add(onJSONLoad);
request.send();

And that’s how you do that.

Oh, all right, a little explanation. First, we create an XMLHttpRequest object. That will handle the loading of the data (and would also handle the sending of data if we were doing that sort of thing). The next line is a bit superfluous, but I wanted to show another variable being created. Notice that String types can be created with the quote literal, just like in JavaScript (and just about every other language). In Dart, there is no difference between single- and double-quotes, unlike PHP or Ruby.

Next we start working with the XMLHttpRequest object. First we open the connection, passing in the method ("GET"), the url we just created, and finally that we’re interested in an asynchronous request (true). That means that we need to add an event listener to know when the load completes. That brings us to the most interesting line:

request.on.load.add(onJSONLoad);

This is Dart’s event model. Objects that dispatch events have an on property which acts as “event central”, where you can go to plan your next party. There will also be properties on the on object that correspond to the various events dispatched by the object in question; in this case, load is one of the events. Each of these event properties is actually a collection of listeners, to which we can add a new listener (onJSONLoad in this case; this hasn’t been written yet in case you were wondering).

This syntax took a little getting used to, but now I really like it. It’s safer and cleaner than request.addEventListener('load', onJSONLoad), wouldn’t you agree?

The last line of our previous code block simply sets the request in motion; send it off to get our data.

For this to work, we need an onJSONLoad function. Let’s start doing that next.


Step 16: Methods and Event Listeners

Now we get to write a new method. This method also happens to be an event listener (for the XMLHttpRequest we set up in the last step), but regardless the syntax is the same. Find a spot in the DartMarquee class that’s after the close of the constructor but before the close of the class – it should be between two closing braces. Add the following:

void onJSONLoad(Event e) {
    print("onJSONLoad");
}

The syntax should be fairly obvious. It follows the property/variable syntax, in that we’ve replaced JavaScript’s function keyword with a datatype. The datatype is the type of the value returned by the function. In this case, void is actually the lack of type, as the function doesn’t return anything. And similar to properties, you can optionally leave the method untyped and use the function keyword instead of a type.

Now we can try out the application. Run it again, and check the console. You should get the message that our function has run, meaning the JSON file has loaded.

Success!

Step 17: Properly Bound “this”

Let’s pause in the action for a moment to talk theory. Don’t worry, you’ll learn something important along the way.

In the code that we just wrote to add an event listener, our event listener is properly bound to the scope of the object it belongs to. In JavaScript, this be bound to the object that dispatched the event. That is, if you write this in JavaScript:

myElement.addEventListener('click', onClick);
function onClick() { console.log(this); }

Then this refers to myElement, the object doing the event dispatching. In Dart, however, this will refer to the object to which the listener belongs. Try it out; change the print to this:

void onJSONLoad(Event e) {
    print(this);
}

And run it again. You should see this:

'this' is '[object Object]'

OK, that doesn’t exactly prove things very well. [object Object] could be anything. Let’s take a quick look at a useful trick for making your classes describe themselves.

Add a method to DartMarquee called toString. This method should return a String and take no arguments.

String toString() {
    return "DartMarquee";
}

Run it one more time and now you end up with this:

Our toString method getting called implicitly

This should illustrate that “this” refers to the DartMarquee object. JavaScript does not behave this way without workarounds. This means that you don’t have to worry about binding functions to their scope when adding event listeners, such as with jQuery’s bind method and other similar solutions.


Step 18: Generics

Let’s move on and parse our JSON now that the JSON file is loaded. We’re going to parse it and stuff those URLs into a property, so first let’s trot back to the top of the class and add a _urls property:

Element _target;
DivElement _mainImage;
DivElement _thumbContainer;
List<String> _urls;

This syntax will look odd if you’re not coming from Java. The variable name is _urls, and the datatype is List<String>. We could just write List _urls, and that would work, but we can also take advantage of something that Dart provides. Back towards the beginning, I described reified generics, and the <String> part of the datatype is the generic. That is, the elements within the List are typed as Strings. The point of this step is pretty much to introduce this syntax. We’ll see it again soon.

If you’ve programmed ActionScript 3, you’ll find the syntax similar to Vectors, and in fact Dart Lists and AS3 Vectors are essentially the same thing.


Step 19: Parsing JSON

Now let’s get to parsing. Remove the print statement from onJSONLoad and add this:

void onJSONLoad(Event e) {
    XMLHttpRequest request = e.target;
    Map<String, Object> result = JSON.parse(request.responseText);
    print("JSON: " + result);
    int i = 0;
    _urls = result['images'];
    _urls.forEach((url) {
        print("url $i: $url");
        i++;
    });
}

This code really isn’t so bad. Here’s how it breaks down.

Line 2: This is just casting the source of the event (found in e.target) to an XMLHttpRequest so we can more safely work with properties on it.

Line 3: This one gets a little gnarly. Skip to the second half of the line. We’re getting responseText out of the XMLHttpRequest object, which gives us the raw text found in our file. And we pass that into the parse method of the JSON class. That’s all there is to parsing JSON; it’s essentially built-in! Now, to make sure we can work with the data, we need to store it in a variable. This variable is result. Because I’m advocating strong typing, it also has a type. This type is Map<String, Object>, which might be a little frightening.

A Map is basically what we call an Object in JavaScript; it’s a collection, and stores its values by a String key.

Because Map is a collection, it can be generified (see last step), but because there are technically two things we can specify (the key and the value), we supply two types. Somewhat oddly, you can’t use anything other than String for the key type, so I’m not sure why it needs specified. It may be possible that Dart eventually allows the use of any type as the key. But for now, it’s a String key. Because our JSON data is an Object at it’s outermost, we specify Object as the value type. We have a little flexibility, depending on the JSON structure.

Line 4: Now that we have our JSON parsed, let’s just print it out to verify the result.

Line 5: Initialize a counter. Note that Dart supports an int type.

Line 6: Get the images property out of the main JSON object, which should be an Array/List, and store that in our _urls property that we set up in the last step.

Line 7: Loop over that List, using forEach and an anonymous function. Note the syntax for anonymous functions: (url) {...}. If there is no return type, we can leave it off completely and just start with the parameter list. It feels a little odd at first, but ultimately leads to less code written, which is kind of nice.

Line 8: Now we can print out the URL along with its index. Here we can see that Dart has String interpolation, which lets you expand variables within a String, and avoid breaking out of a String in order to include the value of a variable. The use of the dollar sign indicates that what follows is actually a variable, and Dart should interpolate it. Again, this is less code written and leads to much more readable code than String concatenation.

Line 9: Hopefully this line of code doesn’t need explanation.

Run the application, and…uh oh. That console doesn’t look pretty.

Big old error

Read on for the fix.


Step 20: Importing More Libraries

The fix is, thankfully, rather simple. Dart is structured into libraries, and it turns out that JSON capability isn’t part of the HTML library. We simply need to add the following line at the very top of the file:

#import('dart:json');

Run the project again, and you should get a console full of output:

The JSON data being logged

What I find odd is that this seems like something the JavaScript compiler catches, but it’s only a warning. The compiler recognizes that you’re using a class called JSON but doesn’t know where to find that class…that seems like an important thing to catch. The lesson here, aside from where the JSON library is, is to check the Problems panel in Dart Editor. It got kind of buried amidst the false print warnings, but it was there:

The Problems panel telling us that we should have imported the JSON library

Also, when you run the project, the Console panel takes over in that space, so you may have missed the warnings altogether. Just something to be on the look out for. This kind of thing will probably improve with time.


Step 21: Writing External Classes

As we continue to explore Dart’s capabilities, we’re going to write a new class to handle a single thumbnail image. We’ll ultimately instantiate a number of these, one for each thumbnail.

While it’s possible to insert a second class definition into the same file, let’s see what happens when we decide to write an external class. In Dart Editor, create a new file for our project and name it MarqueeButton.dart. You’ll be presented with the following template:

class MarqueeButton {

}

Again, there is no requirement that we name the class after the file, or vice versa, but it does make sense, so we’ll leave well enough alone and just start filling in the details.

For now, let’s just get this functional by providing a simple constructor that prints a message so we can see it working. Add a constructor to the class:

class MarqueeButton {

    MarqueeButton(index, image) {
        print("$index: $image");
    }
}

Nothing we haven’t been over already; this is a simple constructor that uses String interpolation.

But to use it, we need to make sure the DartMarquee class is aware of the MarqueeButton class. At the top of DartMarqee, where there are two #import statement, add a third line to include our new class:

#import('dart:html');
#import('dart:json');
#source('MarqueeButton.dart');

You were expecting another #import, weren’t you? #source is a bit simpler than #import. #import is for libraries, which need to be declared as such and can link to other files. #source simply includes the targeted file. One thing to note is the #sourced files cannot, themselves, link to other files. Even #importing the built-in libraries will cause a compiler error. As such, this is a simple way to collect a few files into another script, but for more complex structures you may want to consider creating a library.

Now that we’re linking to our new class, let’s use it. Down in onJSONLoad, we’ll replace the existing print with some instantiation:

void onJSONLoad(Event e) {
    XMLHttpRequest request = e.target;
    Map<String, Object> result = JSON.parse(request.responseText);
    print("JSON: " + result);
    int i = 0;
    _urls = result['images'];
    _urls.forEach((url) {
        MarqueeButton btn = new MarqueeButton(i, "images/thumbs/" + url);
        i++;
    });
}

If you run the project again, you’ll get more or less the same thing, only now it’s logging from within the MarqueeButton class.


Step 22: Fill In the “MarqueeButton” Class

At this point, we can fill in most of the MarqueeButton class without running into much that’s new. I’ll present almost the full body of the class here, and discuss it briefly below.

class MarqueeButton {

    DivElement _target;
    String _image;
    int _index;
    Function _onClick;

    MarqueeButton(this._index, this._image) {
        _target = new Element.tag('div');
        _target.classes = ["button"];
        DivElement border = new Element.tag('div');
        border.classes = ["border"];
        _target.nodes.add(border);

        _target.style.backgroundImage = 'url("'+_image+'")';

        _target.on.click.add(onClick);
    }

    void onClick(Event e) {
        _target.classes.add('selected');
        _onClick(this);
    }

}

We start the class off with a handful of properties, all private and typed. It may be interesting to note the Function type. We’ll get to this in a moment, but this illustrates that functions are fully-fledged objects in Dart, and can be passed around by reference rather easily.

The constructor is mostly about building up the HTML elements for the button. We start from scratch; the only things passed in to the constructor are the index of the button and the image URL. We’ve seen this before, creating and adding new elements. Line 15, however, present something new, although I’d imagine you can figure out what it does. Elements have a style property which lets you set CSS styles rather easily. The properties available to the style object follow the CSS style names, only removing the hyphen and turning the name camel-case. Note that the value might be a String or in the case of numeric values, it can just be a number.

The last line of the constructor adds a click event listener to the button, following the convention we saw with the XMLHttpRequest events.

Then we have our onClick method, the listener for that click event. For style purposes we’ll add the .selected class to the element, then we call the _onClick function. This, you’ll recall, is the property we declared earlier. This is a poor man’s event dispatching, and what happens is that DartMarquee will set this property to a function of its own, so that MarqueeButton can call it. We’ll get to the setting in a moment, and we haven’t written the relevant DartMarquee code. But because functions are first-class citizens of the Dart world, it’s easy to pass that function around, and execute it somewhat arbitrarily.


Step 23: Setters and Getters

We’ll finish off the class with some getters and a setter. For the uninitiated, setters and getters are special functions that simply return a value (getters), or receive a value (setters). They’re common enough, and most object-oriented languages provide some method for creating implicit setters and getters, which are functions that are called as if they were properties.

Dart has this, as well, and throws some syntactic sugar on top of it, to boot. Add this to the end of the class (before the closing curly brace, but after the onClick method):

DivElement get target() => _target;
int get index() => _index;

Function get click() => _onClick;
void set click(Function fn) {
    _onClick = fn;
}

You can see the sugar in the three getters. Each one follows this pattern:

Type get name() => expression;

The type is nothing new; it’s the return type of the function. The get keyword signifies that this is an implicit getter function. name() is just the name of the method. Next is the => operator, which basically says “return the value that is expressed on my right.” In the case of _target, we’re simply accessing the value stored in the _target property and returning that. In other words, a basic getter method, written with a little less code than normal.

The expression can actually get a little more complicated than that, such as a boolean check or some simple one-liner math. If it’s going to require more than one line of code, it needs to be written as a regular getter, which is just like a regular method except for the get keyword:

DivElement get target() {
    return _target;
}

We’re done with the MarqueeButton class now, so we’ll turn back to the DartMarquee class and start using it.


Step 24: Displaying Thumbnails

To display the buttons, we need to go back to the DartMarquee class and revisit the onJSONLoad method. Specifically, we need to add to that loop.

_urls.forEach((url) {
    MarqueeButton btn = new MarqueeButton(i, "images/thumbs/" + url);
    _thumbContainer.nodes.add(btn.target);
    btn.click = onThumbClick;
    i++;
});

Another nodes.add(), this time on the _thumbContainer div and adding the target of the MarqueeButton object.

Then we set the click property to a method we have yet to write, but will do so now:

void onThumbClick(MarqueeButton btn) {
    print("onThumbClick");
}

We’ll work on this next, but for now we should be able to run the application, see the thumbnails, and click on them to see the log message.

The thumb click works

We’re almost there. We’ll work on getting that click to mean something in the next two steps.


Step 25: Handling the Click

The logic involved in displaying a larger image isn’t terribly complex, and at this point we’ve had a pretty extensive tour of the Dart language. I’ll start listing the method here, and then discuss what’s going on.

First we need two properties declared. At the top of the class, with the other properties, add these lines:

MarqueeButton _currentButton;
ImageElement _currentImage;

Then update onThumbClick:

void onThumbClick(MarqueeButton btn) {
    if (_currentButton != null) {
        _currentButton.target.classes.remove('selected');
    }
    _currentButton = btn;
    ImageElement image = new Element.tag('img');
    image.width = 600;
    image.height = 300;
    image.src = "images/" + _urls[btn.index];
    _mainImage.nodes.add(image);
}

The first thing to notice is that we’re checking for the existence of a value in _currentButton. If it does, then we remove the .selected class. Then we set the _currentButton property to the button that was clicked, for next time.

It’s worth nothing that Dart handles Booleans a little differently than you may be used to. Seth Ladd has a write-up on Booleans in Dart, in which we explains:

Dart has a true boolean type named bool, with only two values: true and false (and, I suppose, null). Due to Dart’s boolean conversion rules, all values except true are converted to false. Dart’s boolean expressions return the actual boolean result, not the last encountered value.

Therefore, when checking for the existence of a value within a variable, it’s wise to write if (variable != null) as opposed to the shorthand if (variable), as that could actually report false even through the variable has a valid value stored in it.

Next we create an image element, set its size, the src, and then add it as a child.

You should be able to try this out now. We won’t get a nice fade between the images, but you should now be able to use the marquee to switch images.


Step 26: Working with the Transition

Let’s work on that fade. Add the highlighted code below to the onThumbClick method. Note that Line 11 is a change from how it was before (it uses insertAdjacentElement), and the lines after that are new.

void onThumbClick(MarqueeButton e) {
    if (_currentButton != null) {
        _currentButton.target.classes.remove('selected');
        print(_currentButton.target.classes);
    }
    _currentButton = e;
    ImageElement image = new Element.tag('img');
    image.width = 600;
    image.height = 300;
    image.src = "images/" + _urls[e.index];
    _mainImage.insertAdjacentElement('afterBegin', image);

    if (_currentImage != null) _currentImage.classes.add('fade_away');
    _currentImage = image;
    image.on.transitionEnd.add((evt) {
        ImageElement img = evt.target;
        img.remove();
    });
}

The change to line 53 introduces another way to add children elements. Element.nodes.add() is fine for appending at the end, but if we want to insert in a specific place, in this case at the beginning, then nodes doesn’t give us enough options. insertAdjacentElement does provide options, although its interface isn’t as clean as it could be. In fact, it’s lifted from the Windows Internet Explorer API. I try not to get too opinionated in a tutorial, but this is an odd decision.

Regardless, it’s the API we have if we want to do more than append to the child elements. We want to add our new image to the beginning, so we pass in "afterBegin" to insertAdjacentElement, which does exactly that. This method is documented at MSDN if you’d like a description of the various valid arguments to that parameter.

The rest of the code involves itself with the CSS3 transition; by adding a .fade_away class to the old image (after checking to be sure it’s not null) we set it’s opacity to 0, invoking the transition. Then _currentImage is set to the new image, to get set for the next transition.

Finally, another event listener is added to the current image so that when the transition happens, and is finished, we can run a bit of code. All we do is get the event target and cast it as an ImageElement (not strictly necessary, but it’s something that I find useful to do in general). Then by calling remove() on the ImageElement, we remove it from the DOM. In other words, once it fade away completely, we can remove it altogether to keep our DOM tidy.

Note also that we’re using another anonymous function as the event listener in this case. Either way would work, but since this is practically a one-line function, making it anonymous is rather convenient.

Run the application, click on one thumb to load an image, then another thumb and watch it in silent awe.

A still image rendition of the fade in action

Step 27: The Final Touch

Our Dart application is rather functional now, but you’ve probably noticed that it has one minor flaw: there is not image loaded up right away. This is a simple fix.

In Marquee.dart, find the onJSONLoad method and add the highlighted line of code toward the bottom:

void onJSONLoad(Event e) {
    XMLHttpRequest request = e.target;
    Map<String, Object> result = JSON.parse(request.responseText);
    print("JSON: " + result);
    int i = 0;
    _urls = result['images'];
    _urls.forEach((url) {
        MarqueeButton btn = new MarqueeButton(i, "images/thumbs/" + url);
        _thumbContainer.nodes.add(btn.target);
        btn.click = onThumbClick;
        if (i == 0) btn.onClick(null);
        i++;
    });
}

In effect, if we’re on the first iteration, take that MarqueeButton and call its onClick method. You’ll remember that as the event listener for the click event within the MarqueeButton. We’ll just call it directly, to sort of simulate a click on the first button, so as to trigger the setting of the styles and putting content in the right place. Since the method expects an event parameter, but isn’t really used, we can supply null to the method call to satisfy the compiler.

Run it once more, and you should now have the first image selected and ready in the main area.


Step 28: Where To Go From Here

We’ve just scratched the surface of Dart, but the cool thing is that if you know JavaScript, you already know Dart in one sense. You’re already familiar with what you can do with an HTML page, and generally how to do it. Dart for the web doesn’t really add any capabilities or fancy frameworks, it’s just another language in the same problem domain. If you want to learn more, you can do worse than to simply write applications in Dart. Maybe dig out a smallish/simple bit of JavaScript you’ve done and port it over to Dart.

If you like scouring the web for more resources, Google is certainly your friend, although the name “Dart” can lead to many unrelated hits that are about the game of darts, rather than the language. Many times I’ve had to specify “dart language” in my searches or get a little more specific than just “dart events”. There is quite a bit of information floating around.

First, the official Dart website is at dartlang.org. You’ll find a small tutorial there that goes into some of the unique language features, along with the nifty Dartboard widget that lets your write and execute dart code in the browser you can even use the widget on your own site).

If you think you know what you need to do, just don’t know the right method name or class, the API documentation is good place to start, at api.dartlang.org. Sometimes the docs are a little bare or even wrong, but you should probably begin any quest for an answer here.

I’ve already mentioned the mailing list, located at groups.google.com/a/dartlang.org/group/misc/topics. It’s very active and I had a few questions answered in a matter of minutes there. The Google engineers are very involved on the list, as well.

The Dart site also has a pretty nice JavaScript-to-Dart comparison chart, located at synonym.dartlang.org, which takes common JavaScript code snippets and shows the equivalent Dart code right beside it.

Moving away from Google’s own resources, there are a few Dart-centric blogs that kept coming up in searches. One of the most prolific is Japh(r) by Chris Strom, at japhr.blogspot.com/search/label/dartlang, who is also writing a book on Dart.

The Dartosphere (dartosphere.org aggregates several different blogs about Dart, and can be a gold mine of information.

Seth Ladd works at Google, and his blog at blog.sethladd.com has been recently devoted to Dart.

DartWatch, at dartwatch.com, is another Dart-centric blog that has plenty of content to keep you busy.

One problem, however, is that Dart is a bit of a moving target currently, and some of the older posts on blogs might be out-of-date by the time you get to them. Just keep that in mind. The mailing list is the best place to go if you can’t find a solution through a web search.

One last resource: if this tutorial sparks some interest amongst Tuts+ readers, then we’ll probably find a few more tutorials to write that delve deeper into the world of Dart.


Step 29: Regarding Events

In this tutorial, we learned how to attach event listeners to object, for example:

someElement.on.click.add(myClickListener);
someHTTPRequest.on.load.add(myLoadListener);

You may have noticed that we did not leverage this model when we needed to have the MarqueeButton object communicate to the DartMarquee object. We went for a more lo-fi event listener, where we simply pass a Function in to the object, and then call that Function from within the object. You may ask yourself, why did we do that? Why didn’t we use the on property to dispatch an event? Where does that highway lead to?

The answer is that Dart doesn’t provide this event mechanism outside of its own objects. Not only that, that event system is only available to objects in the HTML libraries. This feels like an area where Google might be able to open up. It sure would be nice to have our own classes become event dispatchers by simply extending an EventDispatcher class or similar, and with a little bit of code getting that mechanism for free.

It’s possible to build your own system that mimics the built-in mechanism, but for the purposes of this tutorial, I went the lo-fi route. There may be some future Dart tutorials that go deeper.


Conclusion

Is Dart the future? Some say yes, some say no. I say, “I don’t know”. I’m certainly intrigued by the possibilities, and as long as it compiles to usable JavaScript today, then maybe it doesn’t matter if Dart isn’t interpreted natively by all of the browsers.

For now, I would say that if CoffeeScript is something that’s been catching on, then the Dart-to-JavaScript technique certainly has the same opportunity. Unlike CoffeeScript, though, you end up with some overhead JavaScript, which may not be appropriate for a vast majority of JavaScript-enabled web pages today. For instance, our DartMarquee project compiles into a JavaScript that’s over 100 KB. That’s a bit much for such a simple marquee. One should be able to write that in regular JavaScript, aided by jQuery or a similar library, for well under that weight limit. And the niceties provided by Dart, with classes, typing, and imports, aren’t enough for this small application to really justify the size.

But for larger applications, like Google Docs, 280 Slides, or Mockingbird, then you can very easily justify the overhead. You’ll have hundreds of KB of JavaScript anyway, so a little extra for the compilation process in exchange for a more structured set of classes will definitely appeal to some programmers.

That’s all for this introduction to Dart. Thanks for reading. I hope it was enlightening for you!



View full post on Activetuts+

Jun 24, 2012 Posted on Jun 24, 2012 in Hints and Tips | 10 comments

Creating “Flux”: A Simple Flash Game With a Gravity Mechanic

In this tutorial, I’ll explain the major steps and workflow for creating a simple space survival game, based on the gravity mechanic explained in a previous tutorial. This game is written in AS3 using FlashDevelop.


Play the Game

Use the left and right arrow keys to manoeuvre your ship, the up and down arrow keys to increase or reduce the size of the magnetic field it produces, and the space bar to reverse the polarity. Collect the white crystals to increase your fuel supply – but avoid the red ones, because they use it up. Don’t hit a rock, or it’s game over!

In this tutorial, we won’t actually create the full game displayed above; we’ll just get started on it, by making a very simple version with primitive graphics and just one type of object. However, by the end, you should have learned enough to be able to add the other features yourself!

The game itself is very simple in its current state. Check back later today for a look at what we could do to improve the game! This tutorial is going to focus on the code and math required to build this demo.


Let’s Get Started!

Set up a new AS3 project in FlashDevelop, and set its dimensions to 550x600px.

 package
{
	[SWF(width = "550", height = "600")]

	public class Main extends Sprite
	{

	}
}

Step 1: Identifying the Game Objects

There are six objects in particle that you can identify from playing the game above:

  • Energy supply – represented by an white oval shape object
  • Asteroid – represented by a rock-like object
  • Energy consumer – represented by a red star bounded with green light.
  • Stars – the background
  • Range indicator – represented by a white circle
  • Ship – player object

Of course you can add in any other object to make the game more interactive or add a new feature. For this tutorial we’ll just make


Step 2: The Energy Class

From the objects we identified, four of them actually work in exactly the same way: by falling from top to bottom.

They are:

  • Stars
  • Energy supply
  • Energy consumer
  • Asteroid

In this tutorial, we’re only going to make the “energy supply” objects, out of the four above. So let’s begin by creating these objects and making them fall down, with a random spawning position and speed.

Start by creating an Energy class:

	package
	{
		import flash.display.MovieClip;
		import flash.events.Event;

		public class Energy extends MovieClip
		{
			private var rSpeed:Number = 0;

			public function Energy(speed:Number)
			{
				graphics.beginFill(0x321312);
				graphics.drawCircle(0, 0 , 8);

				addEventListener(Event.ENTER_FRAME, move);	

				rSpeed = speed;
			}

			// runs every frame
			public function move(e:Event):void
			{
				this.y += rSpeed;
				//rotation speed is linked to moving speed
				this.rotation += rSpeed / 8;
			}
		}
	}

Step 3: The StageController Class

This class will eventually control most of the aspects of our game, including the player movement and the game loop.

For now, though, we’ll just use it as a place to store a reference to the stage.

Create the class:

package
{
	import flash.display.Stage;

	public class StageController
	{
		public static var STAGE:Stage;

		public function StageController(stg:Stage)
		{
			// we will pass the stage from the Main class
			STAGE = stg;
		}
	}
}

We’re going to pass a reference to the stage to this class from our Main class (which is automatically created by FlashDevelop as the starting class for our game). This will allow us to add display objects to the display list from this class.


Step 4: Update The Main Class

We’ll now create an instance of StageController within Main and pass it a reference to the stage:

package
{
	import flash.display.Sprite;
	import flash.events.Event;

	[SWF(width = "550", height = "600")]

	public class Main extends Sprite
	{
		private var stageController:StageController;

		public function Main():void
		{
			stageController = new StageController(stage);
		}
	}
}

Step 5: Introducing a Manager Class

To avoid the StageController class becoming too much of a mess, we’ll use separate classes to manage each object.

Each manager class will contain all the functions that relate to, and interact with, a particular object. Here’s the EnergyManager class:

package
{
	import flash.display.MovieClip;

	public class EnergyManager
	{
		public var energy:Energy;
		// this Vector will store all instances of the Energy class
		private var energyList:Vector.<Energy>	

		public function EnergyManager()
		{
			energyList = new Vector.<Energy>;
		}
	}
}

So far the class contain no other functions; we will add them in later.


Step 6: Creating Energy

Add below function for creating energy, this is just a function, we will be calling the function later from StageController Class:

	public function createEnergy(number:int):void
	{
		for (var i:int = 0; i < number; i++) {		

			energy = new Energy(4);				

			StageController.STAGE.addChild(energy);

			energyList.push(energy);				

			energy.x = Calculation.generateRandomValue(30, 520);
			energy.y = Calculation.generateRandomValue( -150, -20);
		}
	}

We create a new energy supply with a speed of 4, add it directly to the stage via the StageController, add it to the Vector of all energy objects that we just created, and set its position to a random point within certain bounds.

Editor’s Note: I’m a little uncomfortable with adding a display object directly to the stage like that, although of course it does work. One alternative would be to create a function within StageController that handles this for us.

The Calculation.generateRandomValue(#, #) is a static function we haven’t written yet, so let’s do that now. Create a new class called Calculation and add this function:

	public static function generateRandomValue(min:Number, max:Number):Number
	{
		var randomValue:Number = min + (Math.random() * (max - min));

		return randomValue;
	}

This function will generate a random number between the two values passed to it. For more information on how it works, see this Quick Tip. Since this is a static function, we don’t need to create an instance of Calculation in order to call it.


Step 7: Spawning Energy

Let’s set a timer that defines the interval for each spawning. This code goes in StageController‘s constructor function:

energyM = new EnergyManager;

var spawnTimer:Timer = new Timer(3000, 0);
spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
spawnTimer.start();

So, every three seconds, the timer will call spawnEnergy(). Let’s write that function now:

private function spawnEnergy(e:TimerEvent):void
	{
		energyM.createEnergy(4);    // create 4 energies
	}

Step 8: Creating Player

Let’s use another, bigger circle to represent the player. Feel free to import an image to use instead:

public function Player()
		{
			graphics.beginFill(0x7ebff1);
			graphics.drawCircle(0, 0, 20);

Add this code to StageController to add the player to the screen:

// in the variable definitions
public var player:Player;
// in the constructor function
player = new Player;
STAGE.addChild(player);
player.x = 275;
player.y = 450;

So far we should have a few energy supplies falling few seconds, and the player appearing in the middle of the screen:

playerandenergy.

Step 9: Moving the Player

There are basically two ways to apply movement:

  1. Using Boolean (true/false) values – true = moving, false = not moving. When the right arrow key is pressed, the value for “moving right” will change to true. In each frame update, “moving right” is true, we increase the object’s x-value.
  2. Using direct update each frame – when the right arrow key is pressed, an object is told to move right immediately, by increasing its x-value.

The second method does not lead to smooth movement when the key is continuously pressed, but the first method does – so we shall use the first method.

There are three simple steps to doing this:

  1. Create two Boolean variables, one for moving right and one for moving left.
    	private var moveRight:Boolean = false;
    	private var moveLeft:Boolean = false;
    	
  2. Toggle the Boolean when keys are pressed or released:
    		STAGE.addEventListener(Event.ENTER_FRAME, update);
    		STAGE.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
    		STAGE.addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);
    	}
    
    	private function KeyDownHandler(e:KeyboardEvent):void
    	{
    		if (e.keyCode == Keyboard.RIGHT) {
    			moveRight = true;
    		}
    		if (e.keyCode == Keyboard.LEFT) {
    			moveLeft = true;
    		}
    		if (e.keyCode == Keyboard.SPACE) {
    			if (space == true) {
    				space = false;
    			}else if (space == false) {
    				space = true;
    			}
    		}
    	}
    
    	private function KeyUpHandler(e:KeyboardEvent):void
    	{
    		if (e.keyCode == Keyboard.RIGHT) {
    			moveRight = false;
    		}
    		if (e.keyCode == Keyboard.LEFT) {
    			moveLeft = false;
    		}
    	}
    	
  3. Based on these Booleans, actually move the player every frame:

    Don’t forget to first create a function listen from the enter frame event, “updating” :

    //call this function every frame
    private function update(e:Event):void
    	if (moveRight == true) {
    		player.x += 6;
    	}
    	if (moveLeft == true) {
    		player.x -= 6;
    	}
    	

    Keep the player within the bounds of the screen:

    	if (player.x >= 525) {
    		moveRight = false;
    	}
    	if (player.x <= 20) {
    		moveLeft = false;
    	}
    	

Here’s how all that looks, in place:

package
{
    import flash.display.MovieClip;
    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.ui.Keyboard;
    import flash.utils.Timer;
    import flash.events.KeyboardEvent;

    public class StageController
    {
        public static var STAGE:Stage;    // A variable that store Stage class type.
        public var player:Player;

        private var energyM:EnergyManager;

        private var moveRight:Boolean = false;
        private var moveLeft:Boolean = false;
        private var space:Boolean = true;

        private var returnedPower:int = 0;

        private var scoreText:Text;
        private var totalScore:int=0;
        private var score:Text;

        public function StageController(stg:Stage)   // Passing the stage from calling.
        {
            STAGE = stg;        // store "stage" passed to STAGE (we will pass from Main class).
            scoreText = new Text("Score :");
            STAGE.addChild(scoreText);

            energyM = new EnergyManager;

            var spawnTimer:Timer = new Timer(3000, 0);
            spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
            spawnTimer.start();

            player = new Player;
            STAGE.addChild(player);
            player.x = 275;
            player.y = 450;

            STAGE.addEventListener(Event.ENTER_FRAME, update);
            STAGE.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
            STAGE.addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);
        }

	private function KeyDownHandler(e:KeyboardEvent):void
	{
		if (e.keyCode == Keyboard.RIGHT) {
			moveRight = true;
		}
		if (e.keyCode == Keyboard.LEFT) {
			moveLeft = true;
		}
		if (e.keyCode == Keyboard.SPACE) {
			if (space == true) {
				space = false;
			}else if (space == false) {
				space = true;
			}
		}
	}

	private function KeyUpHandler(e:KeyboardEvent):void
	{
		if (e.keyCode == Keyboard.RIGHT) {
			moveRight = false;
		}
		if (e.keyCode == Keyboard.LEFT) {
			moveLeft = false;
		}
	}

	private function update(e:Event):void
	{
		if (player.x >= 525) {
			moveRight = false;
		}
		if (player.x <= 20) {
			moveLeft = false;
		}
		if (moveRight == true) {
			player.x += 6;
		}
		if (moveLeft == true) {
			player.x -= 6;
		}
	}
    }
}

Step 10: Collision Detection

We will need to check for collisions between each energy object and the player. (If you develop the game further, you’ll need to check this for asteroids and energy consumers, but not for stars.)

The best place to handle these checks is inside the EnergyManager, triggered every frame by the StageController.

One thing to consider: the collision checks will be between two circles, so hitTestObject() is not ideal. Instead, we’ll be using the method explained in this tutorial.

We can write the function as below:

	public function checkCollision(p:Player):int
	{
		// energy transferred due to collision
		var energyTransfer:int = 0;

		for (var i:int = 0; i < energyList.length; i++) {
			var energyS:Energy = energyList[i];

			var newX:Number = p.x - energyS.x;
			var newY:Number = p.y - energyS.y;

			var distance:Number = Math.sqrt(newX * newX + newY * newY);

			if (distance <= 28) {
				StageController.STAGE.removeChild(energyS);
				energyList.splice(i, 1);
				// for this simple game, we'll always transfer 1 unit
				// but you could alter this based on speed of collision
				// or any other factor
				energyTransfer = 1;
			}
		}
		return energyTransfer;
	}
  • Line 32: note that we pass in a reference to the player, so that we can access its position.
  • Line 38: EnergyS is short for Energy Supply.
  • Line 40 & 41: finding the difference in x- and y-coordinates between the player and the energy supply we are currently checking.
  • Line 43: calculate the distance between the objects via Pythagorus.
  • Line 45: check for collision; 28 is the sum of the two objects’ radii (player radius is 20, energy radius is 8).
  • Line 46 & 47: remove energy supply from screen and from Vector.
  • Line 51: add a maximum of one unit of energy per frame.

You could alter Line 51 to energyTransfer += 1, to allow the player to absorb more than one energy object at once. It’s up to you – try it out and see how it affects the game.


Step 11: Call Collision Detection Routine

We need to check for collisions every frame, so we should call the function we just wrote from StageController.update().

First, we need to create an integer variable to store the energy transfer value from the collision detection function. We’ll use this value for increasing the ship’s energy and adding to the player’s score.

private var returnedPower:int = 0;
returnedPower = energyM.checkCollision(player);

Step 12: Newton’s Law of Gravitation

Before we go into creating the game mechanic for the ‘Push’ and ‘Pull’ function of the ship, I would like to introduce the physics concept on which the mechanic is based.

The idea is to attract the object towards the player by means of a force. Newton’s Law of Universal Gravitation gives us a great (and simple) mathematical formula we can use for this, where the force is of course the gravitational force:

G is just a number, and we can set it to whatever we like. Similarly, we can set the masses of each object in the game to any values that we like. Gravity occurs across infinite distances, but in our game, we’ll have a cut-off point (denoted by the white circle in the demo from the start of the tutorial).

The two most important things to note about this formula are:

  • The strength of the force depends on the square of the distance between the two objects (so if the objects are twice as far away, the force is one-quarter as strong).
  • The direction of the force is along the direct line connecting the two objects through space.

Step 13: Revising Math Concepts

Before we start coding the game mechanics for the ‘Push’ and ‘Pull’ function, let’s be clear on what we want it to do:

frameWork

Essentially, we want A (the player) to exert a certain force on B (a crystal), and move B towards A based on that force.

We should revise a few concepts:

  • Flash works in radians rather than degrees.
  • Flash’s coordinate system has its y-axis reversed: going down means an increase in y.
  • We can get the angle of the line connecting A to B using Math.atan2(B.y - A.y, B.x - A.x).
  • We can use trigonometry to figure out how much we need to move B along each axis, based on this angle and the force:
    • B.x += (Force*Math.cos(angle));
    • B.y += (Force*Math.sin(angle));
  • We can use Pythagorus’s theorem to figure out the distance between the two objects:

For more information, see the tutorials Gravity in Action and Trigonometry for Flash Game Developers.


Step 14: Implementing Push and Pull

Based on the previous explanation, we can come up with an outline for our code that attracts each crystal to the ship:

  1. Find the difference in x and y between the ship and a given crystal.
  2. Find the angle between them, in radians.
  3. Find the distance between them, using Pythagorus.
  4. Check whether object is within the ship’s gravitational field.
  5. If so, calculate the gravitational force, and…
  6. …apply the force, changing the x and y values of the crystal.

Sample Code:

	public function gravityPull(p:Player): void
	{
		for (var i:int = 0; i < energyList.length; i++) {
			var energyS:Energy = energyList[i];

			var nX:Number = (p.x - energyS.x);
			var nY:Number = (p.y - energyS.y);

			var angle:Number = Math.atan2(nY, nX);

			var r:Number =  Math.sqrt(nX * nX + nY * nY);

			if (r <= 250) {
				var f:Number = (4 * 50 * 10) / (r * r);
				energyS.x += f * Math.cos(angle);
				energyS.y += f * Math.sin(angle);
			}
		}
	}
  • Line 53: get a reference to the player.
  • Line 55: we loop through each energy object.
  • Line 61: find the angle between the ship and the energy.
  • Line 63: find the distance between them, too.
  • Line 65: check whether the energy is within the ship’s force field.
  • Line 67: use the formula:
    • 4 = G, the “gravitational constant” I’ve chosen.
    • 50 = m1, the mass of the ship player.
    • 10 = m2, the mass of the energy object.
  • Line 69: apply movement.

Here’s a timelapse showing how this looks:

Note that the energy moves faster the closer it gets to the ship, thanks to the r-squared term.

We can implement the pushing function just by making the force negative:

	public function gravityPull(p:Player): void
	{
		for (var i:int = 0; i < energyList.length; i++) {
			var energyS:Energy = energyList[i];

			var nX:Number = (p.x - energyS.x);
			var nY:Number = (p.y - energyS.y);

			var angle:Number = Math.atan2(nY, nX);

			var r:Number =  Math.sqrt(nX * nX + nY * nY);

			if (r <= 250) {
				var f:Number = (4 * 50 * 10) / (r * r);
				energyS.x -= f * Math.cos(angle);
				energyS.y -= f * Math.sin(angle);
			}
		}
	}

Here the object moves more slowly as it gets further away from the player, since the force gets weaker.


Step 15: Apply the Mechanic

Of course that you will need this function to be run each frame by StageController – but before that, we will need to use a Boolean function to toggle between the two functions:

private var space:Boolean = true;  //called space because hitting space toggles it

We are going to use true for ‘Push’ and false for ‘Pull’.

Inside KeyDownHandler():

	if (e.keyCode == Keyboard.SPACE) {
		if (space == true) {
			space = false;
		} else if (space == false) {
			space = true;
		}
	}

Afterwards, you will have to check the Boolean each frame. Add this to update():

	if (space == true) {
		energyM.gravityPull(player);
	}
	if (space == false) {
		energyM.gravityPush(player);
	}

Step 16: Modification

You might find that the movement doesn’t look so nice. This could be because the force is not quite ideal, or because of the r-squared term.

I’d like to alter the formula like so:

var f:Number = (0.8 * 50 * 10) / r;

As you can see, I’ve reduced the value of “G” to 0.8, and changed the force to depend simply on the distance between the objects, rather than the distance squared.

Try it out and see if you enjoy the change. You can always alter it however you like.


Step 17: The Text Class

We will need to show some text on the screen, for showing the score and the ship’s remaining power.

For this purpose, we’ll build a new class, Text:

package
{
	import flash.display.MovieClip;
	import flash.text.TextField;
	import flash.events.Event;
	import flash.text.TextFormat;

	import flash.text.TextFormatAlign;

	public class Text extends MovieClip
	{
		public var _scoreText:TextField= new TextField();

		public function Text(string:String)
		{
			var myScoreFormat:TextFormat = new TextFormat(); //Format changeable
			myScoreFormat.size = 24;		

			myScoreFormat.align = TextFormatAlign.LEFT;
			myScoreFormat.color = (0x131313);

			_scoreText.defaultTextFormat = myScoreFormat;

			_scoreText.text = string;

			addChild(_scoreText);
		}

		public function updateText(string:String)
		{
			_scoreText.text = string;
		}
	}
}

It’s very simple; it’s basically a MovieClip with a text field inside.


Step 18: Adding Power for Player

To give the game some challenge, we’ll make the ship’s power get used up slowly, so that the player has to collect energy objects in order to recharge.

To make the ship’s power appear on the ship itself, we can simply add an instance of Text to the ship object’s display list.

Declare these variables within the Ship class:

public var totalPower:Number = 100;  // ship starts with this much power
private var powerText:Text;

We’ll need to keep the amount of power (both stored and displayed) updated every frame, so add this to the constructor:

addEventListener(Event.ENTER_FRAME, updatePower);

Here’s the actual updatePower() function:

	private function updatePower(e:Event):void
		{
			// add a new text object if it doesn't already exist
			if (!powerText) {
				powerText = new Text(String(int(totalPower)));
				addChild(powerText);
				powerText.x -= 20;			//Adjust position
				powerText.y -= 16;
			}

			// fps = 24, so this makes power decrease by 1/sec
			totalPower -= 1 / 24;
			powerText.updateText(String(int(totalPower)));
		}

The power will decrease every frame by 1/24th of a unit, meaning it’ll decrease by one full unit every second.


Step 19: Make Energy Increase Power

When the ship collides with an energy object, we want it to increase its power.

In StageController.update(), add the highlighted line:

returnedPower = energyM.checkCollision(player);
player.totalPower += returnedPower;

Remember you can alter how much power is returned in the EnergyManager.checkCollision() function.


Step 20: Setting Up the Score

Again, we will need the text class. This time, we’ll display “Score” and then the value.

Here, we will need three more variables:

  • The “Score” text.
  • The score value text.
  • A variable to store the actual score.

Declare these in StageController class:

private var scoreText:Text;
private var totalScore:int = 0;
private var score:Text;

In the constructor, add this code:

scoreText = new Text("Score :");
STAGE.addChild(scoreText);

if (!score) {
	STAGE.removeChild(score);
	score = null;
}

score = new Text(String(totalScore));
STAGE.addChild(score);
score.x = scoreText.x + 100;   //Positioning it beside the "Score : " Text.
score.y += 2;

Now, in the update() function, add this:

score.updateText(String(totalScore));

That’s it – we’ve created a basic version of the above game!

Take a look (you may need to reload the page):


Extra Features and Polishing

Space Background

Maybe you would also like a background with an embedded image and stars. Add this to your Main class:

[Embed(source = "/../lib/SpaceBackground.jpg")]	//embed
		private var backgroundImage:Class; //This line must come immediately after the embed

		private var bgImage:Bitmap = new backgroundImage();
		private var numOfStars:int = 70;

Now create the Star class:

package assets
{
	import flash.display.MovieClip;
	import flash.events.Event;

	public class Star extends MovieClip
	{
		private var speed:Number;

		public function Star(alpha:Number, size:Number, speed1:Number)
		{
			graphics.beginFill(0xCCCCCC);
			graphics.drawCircle(0, 0, size);

			this.addEventListener(Event.ENTER_FRAME, moveDown);
			speed = speed1;
		}

		private function moveDown(e:Event):void
		{
			this.y += speed;

			if (this.y >= 600) {
				this.y = 0;
			}
		}
	}
}

In the Main() constructor, add this to create the stars:


for (var i:int = 0; i < numOfStars; i++) {
		createStars();
}

Here’s the actual createStars() function:


private function createStars():void
{
	var star:Star = new Star(
		Math.random(),
		Calculations.getRandomValue(1, 2),
		Calculations.getRandomValue(2, 5)
	);  //random alpha, size and speed

	addChild(star);

	star.x = Calculations.getRandomValue(0, 550);
	star.y = Calculations.getRandomValue(0, 600);
}

With random alpha, size, position, and speed, a pseudo-3D background can be generated.

Range indicator

A range indicator circle can be made by simply creating another circle and adding it to the ship’s display list, just like how you added the power indicator text. Make sure the circle is centred on the ship, and has a radius equal to the ship’s push/pull range.

Add transparancy (alpha value) to the circle with the below code:

			graphics.beginFill(0xCCCCCC, 0.1);

Try adding extra controls that make the range increase or decrease when the up and down arrow keys are pressed.


Conclusion

I hope you enjoyed this tutorial! Please do leave your comments.



View full post on Activetuts+

Nov 17, 2011 Posted on Nov 17, 2011 in Hints and Tips | 10 comments

An Introduction to FlashPunk: Creating a Spaceship Shoot-’Em-Up

This entry is part 2 of 2 in the series An Introduction to FlashPunk

In the last tutorial, we introduced FlashPunk and its capabilities. Now it’s time to build a game with it! We’ll build a top-down, mouse-controlled shoot-’em-up, with a title screen and a game over screen. Read on to learn more…


Final Result Preview

Let’s take a look at the final result we will be working towards:


Step 1: The Player Ship

As always, first we need a clean project. Grab the latest FlashPunk build from the official site. Create a new AS3 project in FlashDevelop and put FlashPunk’s source in the source folder of the project. The game will have the following dimensions: 400×500 px.

We will begin our game by adding a ship – the player ship – on the screen. For that, we will need a new world, called GameWorld, and an image:

Player Ship Image

The player ship will be an entity. Create one, embed the image in it and put it on the screen. If you’re feeling lost, below is the code for the player ship (if you’re really feeling lost, I recommend reading the first tutorial again). I think that creating the world won’t be a problem for you.

package
{
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Image;

	public class PlayerShip extends Entity
	{
		[Embed(source = '../img/PlayerShipImage.png')]
		private const IMAGE:Class;

		public function PlayerShip()
		{
			graphic = new Image(IMAGE);

			graphic.x = -27.5;
			graphic.y = -30;

			x = 200;
			y = 400;
		}

	}

}

Add the player ship into the world and make it the current world when FlashPunk’s Engine starts. You’ll get the following:

The player ship in game

Step 2: Movement

With the player ship on the screen, we need to make it move. Just like every shoot-’em-up game, the player ship will be able to move across all the screen. There’s one thing left to decide before coding the movement: we will be using frame-based movement (the reason for this is in the next step). That means changing (if needed) the super() call to FlashPunk’s Engine and NOT using the FP.elapsed property.

The code for the player ship movement is below. The movement is mouse-based:

		private var _currentDistanceX:Number;
		private var _currentDistanceY:Number;

		private const SPEED:int = 3;

		override public function update():void
		{
			calculateDistances();

			if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED)
			{
				x = Input.mouseX;
				y = Input.mouseY;
			}
			else
			{
				x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
				y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
			}
		}

		private function calculateDistances():void
		{
			_currentDistanceX = Input.mouseX - x;
			_currentDistanceY = Input.mouseY - y;
		}

You will need to import net.flashpunk.utils.Input in the player ship class. Also, don’t forget to enable FlashPunk’s console. After compiling the project, you will see the player ship following the mouse:


Step 3: Enemies

Time to add something fun: enemies. Enemies need to spawn randomly (based on waves) and need to have a controlled movement. They also have a different image:

Image of the enemy

The code for creating the enemy class and adding the image to it shouldn’t be a problem. What we need to focus on is how to make enemies follow a path. The idea is this: we create a wave of enemies and pass them a path to follow, and when to spawn. After that, they will be responsible for showing themselves on the screen and moving along the path.

What is a good representation for a path? A Vector of points seems good enough. Also, we need to define a distance between each point. That way, we can be sure of one important thing: if we define the distance between two points of the path to be the distance that the enemy moves during 1 frame, we won’t need the enemy to process too much information, and we will be able to define after how many frames the enemy will leave the screen by just counting the number of points in the vector. That way, it’s very easy to define when a wave will end.

See it in action: the code below only makes enemies follow a path already given to them, and on the time passed to them (which will be counted in frames). When the enemy is created, a counter that starts on a given number begins decreasing after each elapsed frame, and when it reaches zero, the enemy will put itself on screen and begin following its path.

package
{
	import flash.geom.Point;
	import net.flashpunk.Entity;
	import net.flashpunk.FP;
	import net.flashpunk.graphics.Image;
	import net.flashpunk.World;

	public class Enemy extends Entity
	{
		[Embed(source = '../img/EnemyImage.png')]
		private const IMAGE:Class;

		private var _timeToAct:uint;
		private var _pathToFollow:Vector.<Point>;

		private var _currentPoint:uint;

		private var _myWorld:World;
		private var _added:Boolean;

		public function Enemy(timeToAct:uint, pathToFollow:Vector.<Point>, worldToBeAdded:World)
		{
			graphic = new Image(IMAGE);

			graphic.x = -15;
			graphic.y = -8;

			_timeToAct = timeToAct;

			_pathToFollow = pathToFollow;

			_currentPoint = 0;

			_myWorld = worldToBeAdded;
			_added = false;
		}

		override public function update():void
		{
			if (_timeToAct > 0)
			{
				_timeToAct--;
			}
			else
			{
				if (!_added)
				{
					_myWorld.add(this);

					_added = true;
				}

				x = _pathToFollow[_currentPoint].x;
				y = _pathToFollow[_currentPoint].y;

				_currentPoint++;

				if (_currentPoint == _pathToFollow.length)
				{
					_myWorld.remove(this);

					_added = false;

					destroy();
				}
			}
		}

		public function destroy():void
		{
			graphic = null;
		}

	}

}

From the code above, you can see that we always move a fixed distance from point to point by just positioning the enemy on its current point. It is because of this that we are able to determine when an enemy wave will end. You can also see that the enemy takes care of everything: adding itself in the world, moving through the world and removing itself from the world. With that, it’s very simple to create enemies in the game.


Step 4: Adding Enemies to the Screen

Our base Enemy class is done. Now it’s time to modify GameWorld a bit to add enemies. The first task is to generate paths for the enemies. For the purposes of this tutorial, we will only create a straight line, but feel free to try creating any kind of wave path. This is the function that creates a straight line:

		private function generateEnemyPath(distanceBetweenPoints:Number):Vector.<Point>
		{
			var i:Number;

			var vec:Vector.<Point> = new Vector.<Point>();

			var xPos:Number = Math.random() * 360 + 20;

			for (i = -20; i < 520; i += distanceBetweenPoints)
			{
				vec.push(new Point(xPos, i));
			}

			return vec;
		}

With that, we can already give to an enemy a path to follow. The next step is to actually create the enemy:

		private var _enemy:Enemy;

		public function GameWorld()
		{
			_playerShip = new PlayerShip();

			add(_playerShip);

			_enemy = new Enemy(0, generateEnemyPath(1), this);
		}

		override public function update():void
		{
			super.update();

			if (_enemy)
				_enemy.update();
		}

Compile and run the game. You’ll probably get the following error:

[Fault] exception, information=RangeError: Error #1125: The index 540 is out of range 540.

That happens because even after the enemy deletes itself from the world, we are still calling the update() function of it, because our code didn’t detect when the enemy removed itself. Let’s fix that by overriding the current remove() method:

		override public function remove(e:Entity):Entity
		{
			if (e is Enemy)
			{
				_enemy = new Enemy(0, generateEnemyPath(1), this);
			}

			return super.remove(e);
		}

Now compile the project and you’ll see this:

This is what that function does: every time the enemy removes itself from the world, we detect that through our overriden function and then just create another enemy to “replace” the old one. That’s it! We now have enemies moving across the screen!


Step 5: Shooting With the Player Ship

A shoot-’em-up game wouldn’t be fun without cool ways of shooting bullets out of your ship, would it? In this step we’ll see a great way of organizing bullet patterns in order to shoot them. If you tried to take a guess, you are probably correct: we’re going to use Vectors of Points. However, this time the points will have dynamic beginnings and ends, because your ship won’t always be at the same place every time you shoot, but don’t worry, it’s not as hard as it sounds!

The strategy here is to generate a bullet pattern around a fixed x- and y-axis, and then sum the player ship’s position to the points from the pattern, thus relocating the axis to a new position, giving the impression that the bullets are coming out of the player ship. The bullet image we are going to use is this:

Player bullet

Everything gets simpler when you look at the code. We are basically doing something very similar to the enemy path:

package
{
	import flash.geom.Point;
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Image;

	public class PlayerBullet extends Entity
	{
		[Embed(source = '../img/BulletImage.png')]
		private const IMAGE:Class;

		private var _pathToFollow:Vector.<Point>;

		private var _xPos:Number;
		private var _yPos:Number;

		public function PlayerBullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
		{
			graphic = new Image(IMAGE);

			graphic.x = graphic.y = -3.5;

			_pathToFollow = pathToFollow;

			_xPos = xPos;
			_yPos = yPos;
		}

		override public function update():void
		{
			x = _xPos + _pathToFollow[0].x;
			y = _yPos + _pathToFollow[0].y;

			_pathToFollow.shift();

			if (_pathToFollow.length == 0)
			{
				world.remove(this);

				destroy();
			}
		}

		public function destroy():void
		{
			_pathToFollow = null;

			graphic = null;
		}

	}

}

Notice that we don’t really create the bullet patterns in here: they’re always passed as parameters, just like the enemies. The only difference is that the bullets are always added right away in the world and we keep the initial position of the bullet.

Let’s try adding a bullet when the player clicks with the mouse. In PlayerShip.as:

		override public function update():void
		{
			calculateDistances();

			if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED)
			{
				x = Input.mouseX;
				y = Input.mouseY;
			}
			else
			{
				x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
				y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
			}

			if (Input.mousePressed)
			{
				world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x, y));
			}
		}

Now we need to create the bullet path. We are going to create a straight line, just like for the enemy, but you can do any kind of path! In GameWorld.as, let’s create the generateBulletPath() function:

		public function generateBulletPath(distanceBetweenPoints:Number):Vector.<Point>
		{
			var i:Number;

			var vec:Vector.<Point> = new Vector.<Point>();

			for (i = 0; i > -500; i -= distanceBetweenPoints)
			{
				vec.push(new Point(0, i));
			}

			return vec;
		}

With that, hit the compile and run button and this is what you get:


Step 6: Collision Detection (Using Masks)

We have now the basics of the game running: a player ship that shoots and enemies that go down the screen. Time to add collision detection!

The first step to add the collision detection is to give each entity a type. I’ll leave that to you: give the “Player” type to PlayerShip, “Enemy” to Enemy and “PlayerBullet” to PlayerBullet.

We will be using pixel-perfect collision in this game, so it might be useful to talk about masks. Masks are elements used by FlashPunk for collision detection. They are basically like hitboxes, but they can have a different form (pixel level). We need to set up masks for the player ship, enemies and bullets. The image used by the mask is the same image of the entity. Look at the code for the PlayerShip, Enemy and PlayerBullet, respectively:

		public function PlayerShip()
		{
			graphic = new Image(IMAGE);

			graphic.x = -27.5;
			graphic.y = -30;

			mask = new Pixelmask(IMAGE, -27.5, -30);

			x = 200;
			y = 400;

			type = "Player";
		}
		public function Enemy(timeToAct:uint, pathToFollow:Vector.<Point>, worldToBeAdded:World)
		{
			graphic = new Image(IMAGE);

			graphic.x = -15;
			graphic.y = -8;

			mask = new Pixelmask(IMAGE, -15, -8);

			_timeToAct = timeToAct;

			_pathToFollow = pathToFollow;

			_currentPoint = 0;

			_myWorld = worldToBeAdded;
			_added = false;

			type = "Enemy";
		}
		public function PlayerBullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
		{
			graphic = new Image(IMAGE);

			graphic.x = graphic.y = -3.5;

			mask = new Pixelmask(IMAGE, -3.5, -3.5);

			_pathToFollow = pathToFollow;

			_xPos = xPos;
			_yPos = yPos;

			type = "PlayerBullet";
		}

As you can see, this is very simple: we create a new Pixelmask, pass the source to use as a mask (just like with the graphic) and then pass both x and y offsets (in case you want to center the mask somewhere). Now, in GameWorld.as:

		private var _bulletList:Vector.<PlayerBullet>;

		override public function update():void
		{
			super.update();

			if (_enemy)
				_enemy.update();

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				if (bullet.collideWith(_enemy, bullet.x, bullet.y))
				{
					_enemy.takeDamage();

					remove(bullet);

					bullet.destroy();
				}
			}
		}

Notice that we could have simply used _enemy.collide("PlayerBullet", _enemy.x, _enemy.y) to check for collisions, but the method above is better when we have many bullets on the screen and there is a possibility that two bullets hit the same enemy at the same time. We have called the takeDamage() function of the Enemy class, but at the moment there is none. (Create an empty function for now. In the next step we will make the enemy take damage and explode when necessary.) Compile the project and you’ll get this:


Step 7: Enemy Death

We have made bullets hit our enemies. In this step we will play an explosion animation every time an enemy dies and remove it from the game. The explosion animation sprite sheet is below:

Explosion after enemy death

The approach we will take to do this is by decreasing the enemy’s health in the takeDamage() function, and if the health gets below zero, we will destroy it and put the animation in the screen. The code for decreasing the health is below:

		private var _health:int = 100;

		public function takeDamage():void
		{
			_health -= 50;

			if (_health <= 0)
			{
				addExplosion();

				_myWorld.remove(this);

				_added = false;

				destroy();
			}
		}

The code is very simple. There’s only one thing unknown about it: the addExplosion() function. This function will create an instance of Explosion and add it to the world. The Explosion class will just play and remove itself from the world after that. It’s a simple class:

package
{
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Spritemap;

	public class Explosion extends Entity
	{
		[Embed(source = '../img/ExplosionAnimation.png')]
		private const ANIMATION:Class;

		public function Explosion(xPos:Number, yPos:Number)
		{
			graphic = new Spritemap(ANIMATION, 50, 46, onAnimationEnd);

			graphic.x = -25;
			graphic.y = -23;

			x = xPos;
			y = yPos;

			Spritemap(graphic).add("Explode", [0, 1, 2, 3, 4], 25/60, false);

			Spritemap(graphic).play("Explode");
		}

		private function onAnimationEnd():void
		{
			world.remove(this);

			destroy();
		}

		public function destroy():void
		{
			graphic = null;
		}

	}

}

The trick here is using the callback parameter of the Spritemap class: when the animation ends, that function will be called, and then it removes itself from the world.

Now, back to Enemy.as to finish that function!

		private function addExplosion():void
		{
			world.add(new Explosion(x, y));
		}

Easy, isn’t it? Compile the game and destroy some enemies!


Step 8: Score

The next logical step after making enemies die is to add a score in the game! We will do that using FlashPunk’s Text class. Start by creating a GameScore class, which will hold the score of the game. Since Text is a Graphic, we will make GameScore an Entity and add its text as a graphic. Look at the code:

package
{
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Text;

	public class GameScore extends Entity
	{
		private var _score:int;

		public function GameScore()
		{
			graphic = new Text("Score: 0");

			_score = 0;
		}

		public function addScore(points:int):void
		{
			_score += points;

			Text(graphic).text = "Score: " + _score.toString();
		}

		public function destroy():void
		{
			graphic = null;
		}

	}

}

As you can see, we will call the addScore() function to add points to the game’s score. First, we need to add it to the world. In GameWorld.as:

		private var _score:GameScore;

		public function GameWorld()
		{
			_playerShip = new PlayerShip();

			add(_playerShip);

			_enemy = new Enemy(0, generateEnemyPath(1), this);

			_score = new GameScore();

			_score.x = 300;
			_score.y = 470;

			add(_score);
		}

		public function get score():GameScore
		{
			return _score;
		}

		public function get score():int
		{
			return _score;
		}

If we hit compile, we get just a static score on the bottom of the screen:

The game score

We need to add something to the score every time an enemy is killed. In Enemy.as:

		public function takeDamage():void
		{
			_health -= 50;

			if (_health <= 0)
			{
				addExplosion();

				GameWorld(world).score.addScore(1);

				_myWorld.remove(this);

				_added = false;

				destroy();
			}
		}

Hit compile now and the score will always increase when an enemy is killed!


Step 9: Upgrades

Time to add upgrades! We will not have a nice screen to choose upgrades. Instead, we will create upgrades based on the score: each time the score goes up by 5 (up to 45), the player’s speed will increase a bit. When the score reaches 25, the player will be able to shoot two shots on every click. We will make the score 50 be the end of the game.

Let’s begin by coding the player speed upgrade. For that, we will need to add a multiplier to the speed. In PlayerShip.as:

		public var speedMultiplier:Number = 1;

		override public function update():void
		{
			calculateDistances();

			if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
			{
				x = Input.mouseX;
				y = Input.mouseY;
			}
			else
			{
				x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
				y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
			}

			if (Input.mousePressed)
			{
				world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x, y));
			}
		}

Now it’s all about changing the multiplier in GameWorld.as:

		private var _speedUpgradeNumber:int = 0;

		override public function update():void
		{
			super.update();

			if (_enemy)
				_enemy.update();

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				if (bullet.collideWith(_enemy, bullet.x, bullet.y))
				{
					_enemy.takeDamage();

					remove(bullet);

					bullet.destroy();
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}
		}

Done! Now, every 5 enemy deaths the player will receive a 10% increase in moving speed!

For the double bullet upgrade, we will make a boolean in the PlayerShip class indicating whether or not the ship has the upgrade. Then we will check that when shooting. Here is it:

		public var hasDoubleShoot:Boolean = false;

		override public function update():void
		{
			calculateDistances();

			if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
			{
				x = Input.mouseX;
				y = Input.mouseY;
			}
			else
			{
				x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
				y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
			}

			if (Input.mousePressed)
			{
				if (hasDoubleShoot)
				{
					world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x - 5, y));
					world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x + 5, y));
				}
				else
				{
					world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x, y));
				}
			}
		}

Now, let’s do the same as we did for the speed in GameWorld.as:

		override public function update():void
		{
			super.update();

			if (_enemy)
				_enemy.update();

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				if (bullet.collideWith(_enemy, bullet.x, bullet.y))
				{
					_enemy.takeDamage();

					remove(bullet);

					bullet.destroy();
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}
		}

And that’s it! Hit compile and your game will have upgrades!


Step 10: Increasing the Difficulty

If you played the game until getting the double shot upgrade in the last step, you may have noticed that the game is too easy right now. What do you think of increasing its difficulty based on the player’s score?

That’s the idea: the game will now be able to put on the screen more than one enemy. And for each kill the player gets, we decrease the timer of spawning a new enemy. Interesting, isn’t it? But that’s not the only thing. What about increasing the enemies’ healths and decreasing the damage they take from the player? Now we’re getting somewhere!

Let’s jump to the coding: first we will make the health increase and damage decrease every kill. They will be just like the upgrades on the player ships, but this time we will need to change our approach as to where to keep the multipliers. In Enemy.as:

		private var _health:int;

		public static var healthMultiplier:Number = 1;
		public static var damageMultiplier:Number = 1;

		public function Enemy(timeToAct:uint, pathToFollow:Vector.<Point>, worldToBeAdded:World)
		{
			graphic = new Image(IMAGE);

			graphic.x = -15;
			graphic.y = -8;

			mask = new Pixelmask(IMAGE, -15, -8);

			_timeToAct = timeToAct;

			_pathToFollow = pathToFollow;

			_currentPoint = 0;

			_myWorld = worldToBeAdded;
			_added = false;

			type = "Enemy";

			health = 100 * Enemy.healthMultiplier;
		}

		public function takeDamage():void
		{
			_health -= 50 * Enemy.damageMultiplier;

			if (_health <= 0)
			{
				addExplosion();

				GameWorld(world).score.addScore(1);

				_myWorld.remove(this);

				_added = false;

				destroy();
			}
		}

And now, in GameWorld.as:

		private var _enemyUpgradeNumber:int = 0;

		override public function update():void
		{
			super.update();

			if (_enemy)
				_enemy.update();

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				if (bullet.collideWith(_enemy, bullet.x, bullet.y))
				{
					_enemy.takeDamage();

					remove(bullet);

					bullet.destroy();
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}

			if (_score.score > _enemyUpgradeNumber)
			{
				Enemy.damageMultiplier -= 0.015;
				Enemy.healthMultiplier += 0.02;

				_enemyUpgradeNumber++;
			}
		}

And now our enemies are getting stronger after each kill! Take that, evil player!

Now we need to modify GameWorld in order to spawn enemies based on time. It’s a simple thing: we will just need a timer and a spawn interval. Here’s all the modified code:

		private var _enemyList:Vector.<Enemy>;

		private var _enemySpawnInterval:int = 5000;
		private var _enemySpawnTimer:int;

		public function GameWorld()
		{
			_playerShip = new PlayerShip();

			add(_playerShip);

			_enemyList = new Vector.<Enemy>();

			_score = new GameScore();

			_score.x = 300;
			_score.y = 470;

			add(_score);

			_enemySpawnTimer = 0;
		}

		override public function update():void
		{
			super.update();

			_enemySpawnTimer--;

			if (_enemySpawnTimer <= 0)
			{
				_enemySpawnTimer = _enemySpawnInterval;

				_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));

				add(_enemyList[_enemyList.length - 1]);
			}

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				for each (var enemy:Enemy in _enemyList)
				{
					if (bullet.collideWith(enemy, bullet.x, bullet.y))
					{
						enemy.takeDamage();

						remove(bullet);

						bullet.destroy();
					}
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}

			if (_score.score > _enemyUpgradeNumber)
			{
				Enemy.damageMultiplier -= 0.015;
				Enemy.healthMultiplier += 0.02;

				_enemyUpgradeNumber++;
			}
		}

		override public function remove(e:Entity):Entity
		{
			if (e is Enemy)
			{
				_enemyList.splice(_enemyList.indexOf(e), 1);
			}

			return super.remove(e);
		}

Notice that I gave the enemies a few random frames of “wait time” before appearing. That will make their appearance unpredictable. Now all that’s left is to decrease the spawn interval after every kill:

		override public function update():void
		{
			super.update();

			_enemySpawnTimer--;

			if (_enemySpawnTimer <= 0)
			{
				_enemySpawnTimer = _enemySpawnInterval;

				_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));

				add(_enemyList[_enemyList.length - 1]);
			}

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				for each (var enemy:Enemy in _enemyList)
				{
					if (bullet.collideWith(enemy, bullet.x, bullet.y))
					{
						enemy.takeDamage();

						remove(bullet);

						bullet.destroy();
					}
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}

			if (_score.score > _enemyUpgradeNumber)
			{
				Enemy.damageMultiplier -= 0.015;
				Enemy.healthMultiplier += 0.02;

				_enemySpawnInterval -= 3;

				_enemyUpgradeNumber++;
			}
		}

With that, we basically have everything done in the game world!


Step 11: The Main Menu World

I think we have everything finished in the game world. The game’s surprisingly difficult with the tougher enemies! What do you think of making a nice main menu now? I created a nice background for it:

The main menu screen

Create the MainMenuWorld class, which extends from net.flashpunk.World, and add the background in it. I’ll leave the code for you. We will need a play button, which I also created:

The play button

In order to create the play button, we are going to use the Button class created in the first part of this tutorial series. Here’s the code for the button in MainMenuWorld.as:

		[Embed(source = '../img/PlayGameButton.png')]
		private const PLAYBUTTON:Class;

		private var _playButton:Button;

		public function MainMenuWorld()
		{
			addGraphic(new Image(TITLE));

			_playButton = new Button(playTheGame, null, 48, 395);

			_playButton.setSpritemap(PLAYBUTTON, 312, 22);

			add(_playButton);
		}

		private function playTheGame():void
		{
			FP.world = new GameWorld();

			destroy();
		}

		public function destroy():void
		{
			removeAll();

			_playButton = null;
		}

Don’t forget to change the Main class as well!

		override public function init():void
		{
			FP.world = new MainMenuWorld();

			FP.console.enable();
		}

Hit compile and… Yes! Our shiny main menu world works! Now to the game over world!


Step 12: The Game Over World

The game over world is going to be very simple. I have created two images: one for when the player dies and one for when the player wins the game. There will be a Quit button that will return the player to the main menu. It’s basically the same thing as the main menu world. Here are the two images and the button:

Game over image when player loses
Game over image when player wins
The quit button

I will leave the coding to you. The only thing that will change in this class is that it will need an argument passed to the constructor, telling whether or not the player destroyed the enemies. Here’s the code for the constructor:

		public function GameOverWorld(hasLost:Boolean)
		{
			if (hasLost)
			{
				addGraphic(new Image(BACKGROUNDLOST));
			}
			else
			{
				addGraphic(new Image(BACKGROUNDWON));
			}

			_quitButton = new Button(quitToMain, null, 166, 395);

			_quitButton.setSpritemap(QUITBUTTON, 69, 19);

			add(_quitButton);
		}

Step 13: The Boss – Movement

Finally, the moment everyone was waiting for. Every shoot-’em-up needs a boss, and this is ours!

The boss! Kill him!

What we need now is code it. First, the movements. And then, the bullets. This step is for the movements.

As you may have guessed, our boss won’t go directly down the screen. Instead, it will move randomly around the top of the screen, to give the player a bit of difficulty defeating it. What we will need to do is a movement very similar to the player’s. The only difference is that it will follow a point chosen randomly in the top of the screen, and not the mouse. Here’s the full code for the Boss class!

package
{
	import flash.geom.Point;
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Image;
	import net.flashpunk.masks.Pixelmask;

	public class Boss extends Entity
	{
		[Embed(source = '../img/BossImage.png')]
		private const IMAGE:Class;

		private var _currentDistanceX:Number;
		private var _currentDistanceY:Number;

		private var _randomPoint:Point;

		private const SPEED:int = 3;

		public var speedMultiplier:Number = 1;

		public function Boss()
		{
			graphic = new Image(IMAGE);

			graphic.x = -38;
			graphic.y = -35;

			mask = new Pixelmask(IMAGE, -38, -35);

			type = "BossEnemy";

			getRandomPoint();
		}

		private function getRandomPoint():void
		{
			_randomPoint = new Point();

			_randomPoint.x = Math.random() * 400;
			_randomPoint.y = 38 + (Math.random() * 100);
		}

		override public function update():void
		{
			calculateDistances();

			if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
			{
				x = _randomPoint.x;
				y = _randomPoint.y;

				getRandomPoint();
			}
			else
			{
				x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
				y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
			}
		}

		private function calculateDistances():void
		{
			_currentDistanceX = _randomPoint.x - x;
			_currentDistanceY = _randomPoint.y - y;
		}

	}

}

We are basically using the same movement code from PlayerShip. Notice that we have kept the speed multipliers, because there will be a really fun thing in the end!

We need now to come up with a way to test this movement. Running the game and getting 50 kills is too much time to wait until we can see the boss (and end up realizing there’s a bug and we will need to do it all again and again!). Let’s just add the boss on the screen when the game begins (yes, with the other enemies going down the screen!) and check the movement! In GameWorld.as:

		private var _boss:Boss;

		public function GameWorld()
		{
			_playerShip = new PlayerShip();

			add(_playerShip);

			_enemyList = new Vector.<Enemy>();

			_score = new GameScore();

			_score.x = 300;
			_score.y = 470;

			add(_score);

			_enemySpawnTimer = 0;

			_boss = new Boss();

			add(_boss);
		}

Hit compile and test the game! Our boss is moving nicely, isn’t it? It’s going to be hard to kill it!


Step 14: The Boss – Shooting

Time for the really evil boss bullets! Here is their image:

Boss bullet

But there is something really bothering me: they will have exactly the same behavior as the player bullet, but instead they will just follow the same enemy downward path, and will have a different FlashPunk type, but I don’t want to copy and paste the same code in their class. What do you think about using some Object-Oriented Design and make an inheritance? Take all the code (yes, all the code) of PlayerBullet and copy it to a new class called Bullet. Remove the code related to the bullet’s image, and this is what you get:

package
{
	import flash.geom.Point;
	import net.flashpunk.Entity;

	public class Bullet extends Entity
	{
		private var _pathToFollow:Vector.<Point>;

		private var _xPos:Number;
		private var _yPos:Number;

		public function Bullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
		{
			_pathToFollow = pathToFollow;

			_xPos = xPos;
			_yPos = yPos;
		}

		override public function update():void
		{
			x = _xPos + _pathToFollow[0].x;
			y = _yPos + _pathToFollow[0].y;

			_pathToFollow.shift();

			if (_pathToFollow.length == 0)
			{
				world.remove(this);

				destroy();
			}
		}

		public function destroy():void
		{
			_pathToFollow = null;

			graphic = null;
		}

	}

}

That’s the basic behavior of the bullet. Now, what do we do with the PlayerBullet class? Put only the things related to the bullet image in there, and remove the rest. And also make it inherit from Bullet:

package
{
	import flash.geom.Point;
	import net.flashpunk.graphics.Image;
	import net.flashpunk.masks.Pixelmask;

	public class PlayerBullet extends Bullet
	{
		[Embed(source = '../img/BulletImage.png')]
		private const IMAGE:Class;

		public function PlayerBullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
		{
			super(pathToFollow, xPos, yPos);

			graphic = new Image(IMAGE);

			graphic.x = graphic.y = -3.5;

			mask = new Pixelmask(IMAGE, -3.5, -3.5);

			type = "PlayerBullet";
		}

	}

}

Do you mind making the same thing for the BossBullet class too? The only difference is that it will have a type of “BossBullet”. I’ll leave the code to you. Check the tutorial source if you need help!

We could have done the same for the boss and the enemies, but we would need to change more things, because the movement of the enemies isn’t the same as the movement of the boss. It’s better to leave it that way. And now, for the boss shooting. We will use the same timer strategy that we used for the enemy spawning. Here’s the code:

		private var _shootingInterval:int = 75;
		private var _shootingTimer:int = 0;

		override public function update():void
		{
			calculateDistances();

			if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
			{
				x = _randomPoint.x;
				y = _randomPoint.y;

				getRandomPoint();
			}
			else
			{
				x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
				y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
			}

			_shootingTimer--;

			if (_shootingTimer <= 0)
			{
				_shootingTimer = _shootingInterval;

				world.add(new BossBullet(GameWorld(world).generateBossBulletPath(1.5), x - 10, y));
				world.add(new BossBullet(GameWorld(world).generateBossBulletPath(1.5), x + 10, y));
				world.add(new BossBullet(GameWorld(world).generateBossBulletPath(1.5), x, y + 5));
			}
		}

Compile and run the code and now you have a boss shooting bullets and flying around! Time to make the last battle happen in the next step :)


Step 15: Final Touches

You may have noticed that the boss’s bullets don’t hit the player ship, and the player’s bullets don’t hit the boss. That’s because we haven’t coded them to hit their enemies. That’s what we are going to do now. We will also make the boss only appear when the score reaches 50, and check for when the player loses the game.

The first task: to make the boss only appear when the score reaches 50. We will do that by checking for the score in GameWorld.as, just like we did with the enemy and player upgrades.

		private var _bossAppeared:Boolean = false;

		public function GameWorld()
		{
			_playerShip = new PlayerShip();

			add(_playerShip);

			_enemyList = new Vector.<Enemy>();

			_score = new GameScore();

			_score.x = 300;
			_score.y = 470;

			add(_score);

			_enemySpawnTimer = 0;

			_boss = new Boss();

			// Not adding the boss in the game this time
		}

		override public function update():void
		{
			super.update();

			_enemySpawnTimer--;

			if (_enemySpawnTimer <= 0 && !_bossAppeared)
			{
				_enemySpawnTimer = _enemySpawnInterval;

				_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));

				add(_enemyList[_enemyList.length - 1]);
			}

			_bulletList = new Vector.<PlayerBullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				for each (var enemy:Enemy in _enemyList)
				{
					if (bullet.collideWith(enemy, bullet.x, bullet.y))
					{
						enemy.takeDamage();

						remove(bullet);

						bullet.destroy();
					}
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}

			if (_score.score > _enemyUpgradeNumber)
			{
				Enemy.damageMultiplier -= 0.015;
				Enemy.healthMultiplier += 0.02;

				_enemySpawnInterval -= 3;

				_enemyUpgradeNumber++;
			}

			if (_score.score == 50 && !_bossAppeared)
			{
				add(_boss);

				_bossAppeared = true;
			}
		}

First task done. Notice that we also changed the block that spawned new enemies. That way, when the boss appears, no more enemies will spawn.

Second task: make boss bullets hit the player and player bullets hit the boss. This is also done in GameWorld.as. Take a look at the code:

		private var _bulletList:Vector.<Bullet>;

		override public function update():void
		{
			super.update();

			_enemySpawnTimer--;

			if (_enemySpawnTimer <= 0 && !_bossAppeared)
			{
				_enemySpawnTimer = _enemySpawnInterval;

				_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));

				add(_enemyList[_enemyList.length - 1]);
			}

			_bulletList = new Vector.<Bullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				for each (var enemy:Enemy in _enemyList)
				{
					if (bullet.collideWith(enemy, bullet.x, bullet.y))
					{
						enemy.takeDamage();

						remove(bullet);

						bullet.destroy();
					}
				}

				if (_bossAppeared)
				{
					if (bullet.collideWith(_boss, bullet.x, bullet.y))
					{
						_boss.takeDamage();

						if (!_boss)
						{
							endTheGame();

							return;
						}

						remove(bullet);

						bullet.destroy();
					}
				}
			}

			_bulletList = new Vector.<Bullet>();

			getType("BossBullet", _bulletList);

			for each (var bossBullet:BossBullet in _bulletList)
			{
				if (bossBullet.collideWith(_playerShip, bossBullet.x, bossBullet.y))
				{
					endTheGame();

					return;
				}
			} 

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}

			if (_score.score > _enemyUpgradeNumber)
			{
				Enemy.damageMultiplier -= 0.015;
				Enemy.healthMultiplier += 0.02;

				_enemySpawnInterval -= 3;

				_enemyUpgradeNumber++;
			}

			if (_score.score == 50 && !_bossAppeared)
			{
				add(_boss);

				_bossAppeared = true;
			}
		}

In the first part of the code, we check for a collision between the player’s bullets and the boss. If there is a collision, we call the takeDamage() function from the boss, which is below. After checking the player’s bullets, we check for the boss’s bullets, and if we find a collision between any of them and the player, we end the game. This function is also below.

Now, for the takeDamage() function of the boss. We want the boss to have a lot of health, and we will make it fly faster after each hit. In Boss.as:

		private var _health:int = 1000;

		public function takeDamage():void
		{
			_health -= 50;

			speedMultiplier += 0.05;

			if (_health <= 0)
			{
				world.remove(this);

				destroy();
			}
		}

		public function destroy():void
		{
			graphic = null;

			mask = null;

			_randomPoint = null;
		}

Our boss battle is complete! It will die after 20 hits from the player, getting faster after each hit.

Now, the only thing remaining is to end the game and show the screen when the boss is killed, and also make the player lose before the boss battle if an enemy goes down the screen. For the end of the game, we need to check when the boss is killed and create the endTheGame() function in GameWorld.as. This function will basically remove every bullet from the screen, remove the player and boss and then add the game over screen. In GameWorld.as:

		override public function remove(e:Entity):Entity
		{
			if (e is Enemy)
			{
				_enemyList.splice(_enemyList.indexOf(e), 1);
			}

			if (e is Boss)
			{
				_boss = null;
			}

			return super.remove(e);
		}

		public function endTheGame():void
		{
			removeAll();

			while (_bulletList.length > 0)
			{
				_bulletList[0].destroy();

				_bulletList.shift();
			}

			while (_enemyList.length > 0)
			{
				_enemyList[0].destroy();

				_enemyList.shift();
			}

			_bulletList = null;
			_enemyList = null;
			_playerShip = null;
			_score = null;

			if (_boss)
			{
				FP.world = new GameOverWorld(true);
			}
			else
			{
				FP.world = new GameOverWorld(false);
			}

			_boss = null;
		}

And that’s it! The endTheGame() function is basically the same as a destroy() function. It just cleans every reference in the game world.

The last part: making the player lose the game if an enemy has reached the end of the screen. For this one we’re going to remember that an enemy only reaches the bottom of the screen if it still has health. So, in the remove() function of GameWorld.as:

		private var _gameEnded:Boolean = false;

		override public function remove(e:Entity):Entity
		{
			if (e is Enemy)
			{
				if (Enemy(e).health > 0)
				{
					endTheGame();

					return e;
				}

				_enemyList.splice(_enemyList.indexOf(e), 1);
			}

			if (e is Boss)
			{
				_boss = null;
			}

			return super.remove(e);
		}

		override public function update():void
		{
			super.update();

			if (_gameEnded)
			{
				return;
			}

			_enemySpawnTimer--;

			if (_enemySpawnTimer <= 0 && !_bossAppeared)
			{
				_enemySpawnTimer = _enemySpawnInterval;

				_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));

				add(_enemyList[_enemyList.length - 1]);
			}

			_bulletList = new Vector.<Bullet>();

			getType("PlayerBullet", _bulletList);

			for each (var bullet:PlayerBullet in _bulletList)
			{
				for each (var enemy:Enemy in _enemyList)
				{
					if (bullet.collideWith(enemy, bullet.x, bullet.y))
					{
						enemy.takeDamage();

						remove(bullet);

						bullet.destroy();
					}
				}

				if (_bossAppeared)
				{
					if (bullet.collideWith(_boss, bullet.x, bullet.y))
					{
						_boss.takeDamage();

						if (!_boss)
						{
							endTheGame();

							return;
						}

						remove(bullet);

						bullet.destroy();
					}
				}
			}

			_bulletList = new Vector.<Bullet>();

			getType("BossBullet", _bulletList);

			for each (var bossBullet:BossBullet in _bulletList)
			{
				if (bossBullet.collideWith(_playerShip, bossBullet.x, bossBullet.y))
				{
					endTheGame();

					return;
				}
			}

			if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
			{
				_playerShip.speedMultiplier += 0.1;

				_speedUpgradeNumber++;
			}

			if (_score.score >= 25)
			{
				_playerShip.hasDoubleShoot = true;
			}

			if (_score.score > _enemyUpgradeNumber)
			{
				Enemy.damageMultiplier -= 0.015;
				Enemy.healthMultiplier += 0.02;

				_enemySpawnInterval -= 3;

				_enemyUpgradeNumber++;
			}

			if (_score.score == 50 && !_bossAppeared)
			{
				add(_boss);

				_bossAppeared = true;
			}
		}

		public function endTheGame():void
		{
			removeAll();

			while (_bulletList.length > 0)
			{
				_bulletList[0].destroy();

				_bulletList.shift();
			}

			while (_enemyList.length > 0)
			{
				_enemyList[0].destroy();

				_enemyList.shift();
			}

			_bulletList = null;
			_enemyList = null;
			_playerShip = null;
			_score = null;

			if (_boss)
			{
				FP.world = new GameOverWorld(true);
			}
			else
			{
				FP.world = new GameOverWorld(false);
			}

			_boss = null;

			_gameEnded = true;
		}

This code will only end the game when an enemy reaches the end (is destroyed) with a health above 0. If the enemy dies, this function is also called, but then the enemy health will be below (or equal to) 0, skipping the code to end the game. We have also created the _gameEnded boolean because when an enemy reaches the end of the screen and gets removed, the world is still updating its entities. Only when it finished updating them (after the super.update() call in the class) is that we can end the game.

After all these lines and lines of code changed, remove the FlashPunk console, hit compile and test the game. It’s finally done, your very first game entirely done in FlashPunk! Congratulations!


Step 16: Conclusion

Congratulations, you have created your first FlashPunk game! You have used pretty much all of FlashPunk’s features for a very basic game, which means you are ready to create more FlashPunk games and spread the word! What do you think of improving this game? It could have different enemies, enemies that also shoot bullets, levels, more bosses, more upgrades and a lot of other things! Are you up to the challenge?



View full post on Activetuts+

Feb 22, 2011 Posted on Feb 22, 2011 in Hints and Tips | 0 comments

Creating Generative Art with HYPE

During this tutorial we’re going to tie math and design together. We’ll explore Branden Hall and Joshua Davis’ HYPE framework and create generative art from code.


Final Result Preview

Let’s take a look at the final result we will be working towards:


Step 1: Project Structure

Before diving head-long into the code let’s take a brief moment to familiarize ourselves with the project files.

Inside the source .zip file you will find a folder for each significant step, so that you can see exactly what changes have been made. Also, you will find a folder called Base, make a copy of this folder as this is will serve as our starting point.

Inside the Base folder we have a bin folder where our SWF will be published. A src folder which contains our ActionScript 3 and Flash Files and lastly a lib folder where we will store the HYPE framework’s SWC files.

Overview of folder structure

Step 2: Getting HYPE

Next up, we need to grab the latest version of the HYPE framework from its home at www.hypeframework.org.

Once the download has completed, open the .zip file. You’ll find two SWC files named hype-framework.swc and hype-extended.swc. Copy both of these to your Base\lib folder.

These SWC files are essentially a collection of source files for the framework, all rolled in to one file for ease.

Copying the required SWC files

Step 3: Adding SWCS to Flash

The final step needed to get everything up and running is to tell Flash to look for the two new SWC files when we compile the movie, otherwise it will throw a whole bunch of errors our way, not nice!

Open the Main.fla inside the Base\src folder, then choose File, Publish Settings. Select the Flash tab as shown, in the new window that opens select the Library Path tab.

Adding a SWC to Flash

Press the “Browse TO SWC” File button and proceed to add both SWC files to the Flash file. Once this is complete it’s time to start adding some code!

Browsing for SWC files

Step 4: Init HYPE

Open up the Main.as source file in your chosen editor. Add the following private properties and the initHype() method:

public class Main extends MovieClip
{
	// private properties
	private var bitmapCanvas:BitmapCanvas;
	private var clipContainer:Sprite;
	private var objectPool:ObjectPool;

	/**
	 * constructor
	 */
	public function Main()
	{
		// inits the Hype framework
		initHype();
	}

	/**
	 * initiation of the Hype members we will be using and configuration prior
	 * to running the animation
	 */
	private function initHype():void
	{
		// the clipContainer is used as a parent for all of our objects
		clipContainer = new Sprite();
		addChild(clipContainer);
	}
}

In the next few steps we’ll be looking at each of these objects we’ve added as private properties, starting with the clipContainer Sprite.

As our design is going to have over a hundred objects all moving around the screen at once, we’re going to need something to house them all – just adding them to the Stage will become problematic further down the line. The answer is to create a regular AS3 Sprite to act as a parent.


Step 5: The BitmapCanvas

The first real part of HYPE, the BitmapCanvas can be thought of as a Sprite or better still, a Bitmap/BitmapData to which we will be painting our objects, each frame, like a painters canvas.

We create it just below the clipContainer code and define it with a width and height to match the Stage. We add it to the Stage but also tell it to startCapture(clipContainer, true), this simply tells the BitmapCanvas to take a snapshot of the clipContainer each frame. For now though, keep this commented out!

	/**
	 * initiation of the Hype members we will be using and configuration prior
	 * to running the animation
	 */
	private function initHype():void
	{
		// the clipContainer is used as a parent for all of our objects
		clipContainer = new Sprite();
		addChild(clipContainer);

		// think of the BitmapCanvas as an empty space we will 'paint'
		// every frame with new image data
		bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
		//bitmapCanvas.startCapture(clipContainer, true);
		addChild(bitmapCanvas);
	}
}

Step 6: The ObjectPool

If you have worked with games you’ve probably come across the concept of an ObjectPool. As creating new objects is too much of a hit on the processor we create a pool of a specified amount of objects before the game or application begins. We would then use the objects from this pool and upon running out we would recycle and reuse them all again, which avoids creating new objects. This is commonly used for bullets/lasers in games and the same logic is used in HYPE.

If you take a look at the Main.fla Library in Flash you will see I’ve created a MovieClip called circleShape and given it the Linkage Identifier of circleShape so we can create multiple copies of this object with code; this is what our ObjectPool will house.

a MovieClip to be used with ObjectPool

Add the ObjectPool below the BitmapCanvas code, like so:

	/**
	 * initiation of the Hype members we will be using and configuration prior
	 * to running the animation
	 */
	private function initHype():void
	{
		// the clipContainer is used as a parent for all of our objects
		clipContainer = new Sprite();
		addChild(clipContainer);

		// think of the BitmapCanvas as an empty space we will 'paint'
		// every frame with new image data
		bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
		//bitmapCanvas.startCapture(clipContainer, true);
		addChild(bitmapCanvas);

		// create a collection of 10 objects and store them in an ObjectPool
		// for use in the animation
		objectPool = new ObjectPool(circleShape, 10);
	}

Step 7: Creating Objects Using ObjectPool.request();

Now we have our core players setup, the clipContainer, the BitmapCanvas and the ObjectPool with its 10 clips, it’s time to start making things move.

To get an item from the ObjectPool we can use objectPool.request(); which will give us a circleShape MovieClip from the Flash Library to work with.

The ObjectPool also gives us the objectPool.onRequestObject() method which is a handy way to assign properties of a clip each time we request one. Add the following below where you instantiated the ObjectPool:

	// create a collection of 10 objects and store them in an ObjectPool
	// for use in the animation
	objectPool = new ObjectPool(circleShape, 10);

	// each time we request a new shape from the pool
	// it will perform the following
	objectPool.onRequestObject = function(clip:MovieClip):void
	{
		clip.x = Math.random() * stage.stageWidth;
		clip.y = Math.random() * stage.stageHeight;

		clipContainer.addChild(clip);
	}

Step 8: See the Result

With that new code added, every time we request an object from the pool by using objectPool.request() it will create a circleShape. Add it to the clipContainer and position it randomly on the screen. You can test this by amending the constructor to look like the following:

	/**
	 * constructor
	 */
	public function Main()
	{
		// inits the Hype framework
		initHype();

		objectPool.request();
	}

If all went well you should have a single, lonely circle on the screen.


Step 9: Requesting all Objects at Once

Do you remember we set the ObjectPool size to 10? Well we’re going to up the ante and increase this to 100 objects by changing the following:

	// create a collection of 10 objects and store them in an ObjectPool
	// for use in the animation
	objectPool = new ObjectPool(circleShape, 100);

We can amend the earlier request statement to read as requestAll() like this:

	/**
	 * constructor
	 */
	public function Main()
	{
		// inits the Hype framework
		initHype();

		objectPool.requestAll();
	}

Now we should have 100 circles scattered over the screen’s area.


Step 10: Adding FixedVibrations

Now we have our 100 circleShapes distributed around the screen it’s time to make our design come to life by adding movement.

Let’s start by applying a FixedVibration to the alpha and scale properties of each clip. We can use the ObjectPools onRequestObject method to implement it as shown:

	// create a collection of 10 objects and store them in an ObjectPool
	// for use in the animation
	objectPool = new ObjectPool(circleShape, 100);

	// each time we request a new shape from the pool
	// it will perform the following
	objectPool.onRequestObject = function(clip:MovieClip):void
	{
		clip.x = Math.random() * stage.stageWidth;
		clip.y = Math.random() * stage.stageHeight;

		// add a FixedVibration to the alpha and scale properties of each circleShape when requested
		var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
		var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
		alphaVib.start();
		scaleVib.start();

		clipContainer.addChild(clip);
	}

Let’s have a closer look at the FixedVibration objects we created. Each FixedVibration object we create takes 7 parameters, respectively they are as follows:

  • The object to apply the FixedVibration to, in our case our circleShape called “clip”.
  • The property to apply the FixedVibration to, this time we’re working with the alpha and scale properties.
  • The third parameter is the Spring of the FixedVibration, the higher the number the more ‘springy’ the movement. A value between 0 and 1 will work best.
  • Next up is the Ease of the vibration, the lower the value the quicker it will slide between the following two values. A value between 0 and 1 will work best.
  • The minimum value is up next, this will be the lowest the the vibration will hit.
  • Similarly, the maximum value will be the maximum value the vibration will hit.
  • Finally, the last parameter is relative, default this to false.

So how do all of these fit together? Let’s look at how the scale property is affected by the FixedVibration. It’s given Min and Max values of 0.05 and 0.8, the Spring value is pretty high at 0.9 and the Ease is pretty low at 0.05 making it scale erratically and fast.

Have a play around with these values to get a feel for how they influence the movement.

When we test our Flash file we should get something like this:


Step 11: Adding a VariableVibration

Very similar to the FixedVibration, the VariableVibration will adjust a property of an object with a value that fluctuates. The difference being that the VariableVibration isn’t linear as the name suggests.

Amend your code as follows to place the clips to the center of the Stage, only this time we’ll apply a VariableVibration to the x and y values to start seeing some movement!

	// each time we request a new shape from the pool
	// it will perform the following
	objectPool.onRequestObject = function(clip:MovieClip):void
	{
		clip.x = stage.stageWidth/2;
		clip.y = stage.stageHeight/2;

		// add a VariableVibration for the x/y movement of each circleShape
		var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
		var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
		xVib.start();
		yVib.start();

		// add a FixedVibration to the alpha and scale properties of each circleShape when requested
		var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
		var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
		alphaVib.start();
		scaleVib.start();

		clipContainer.addChild(clip);
	}

Let’s have a closer look at the VariableVibration objects we created. Each VariableVibration object we create takes only 5 parameters, respectively they are as follows:

  • The object to apply the VariableVibration to, in our case our circleShape called “clip”.
  • The property to apply the VariableVibration to, this time we’re working with the x and y properties.
  • The third parameter is the Spring of the vibration.
  • Next up is the Ease of the vibration.
  • The final parameter is the Range of values that is produced. The higher the number the more erratic the effect.

Our Flash file should look something like this when published:


Step 12: Adding Some Wow

It’s starting to look good, but we can do much better! Remember that bitmapCanvas.startCapture() line I asked you to keep uncommented way back in Step 6? Go ahead and uncomment it then test your movie again.

This is more like it!


Step 13: A Quick Trick for Rotation

A very simple trick to add a spiraling movement is to add another vibration to the clip’s rotation property like so:

	// each time we request a new shape from the pool
	// it will perform the following
	objectPool.onRequestObject = function(clip:MovieClip):void
	{
		clip.x = stage.stageWidth/2;
		clip.y = stage.stageHeight/2;

		// add a VariableVibration for the x/y movement of each circleShape
		var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
		var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
		xVib.start();
		yVib.start();

		// add a FixedVibration to the alpha and scale properties of each circleShape when requested
		var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
		var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
		alphaVib.start();
		scaleVib.start();

		// add a FixedVibration to the rotation of the circleShape
		var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
		rotationVib.start();

		clipContainer.addChild(clip);
	}

Step 14: A Quick Trick for Rotation

Before testing this jump over to Flash and open the circleShape MovieClip in the Library.

As shown, drag the circle just off from center in any direction. The further you move it from center, the more spirals will appear in your design when you publish:

Offsetting the circleShape for spirals

Step 15: ExitShapes

One problem with our current animation is that once the clips move off the screen, they very rarely come back. We can solve this little problem by creating an ExitShapeTrigger.

An ExitShapeTrigger is an area considered safe for the clip. When the clip leaves this area we need to perform some kind of function, such as requesting a new clip from the ObjectPool.

We define an ExitShapeTrigger as below:

	// each time we request a new shape from the pool
	// it will perform the following
	objectPool.onRequestObject = function(clip:MovieClip):void
	{
		clip.x = stage.stageWidth/2;
		clip.y = stage.stageHeight/2;

		// add a VariableVibration for the x/y movement of each circleShape
		var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
		var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
		xVib.start();
		yVib.start();

		// add a FixedVibration to the alpha and scale properties of each circleShape when requested
		var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
		var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
		alphaVib.start();
		scaleVib.start();

		// add a FixedVibration to the rotation of the circleShape
		var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
		rotationVib.start();

		// define an ExitShape
		var exit:ExitShapeTrigger = new ExitShapeTrigger(onExitShape, clip, exitShape, true);
		exit.start();

		clipContainer.addChild(clip);
	}

	// recycle objects
	private function onExitShape(clip:MovieClip):void
	{
		trace("circleShape left the screen!");
	}

This will create an ExitShapeTrigger with the following parameters:

  • The method to trigger when the event has occurred.
  • The MovieClip to test if it is out of the given area.
  • The MovieClip used to define the safe area, you might have already noticed we’ve already created this, called it exitShape and placed it on the Stage in Flash.
  • The last parameter is the Enter Once flag, just set this to true for now.

Step 16: ObjectPool Release

Following on from the ExitShape we introduced in the last step, we’re going to simply edit the onExitShape method so that whenever a clip moves off the screen, we’ll delete it and request a new one from the ObjectPool.

Until now we’ve been working with the request() and requestAll() methods of the ObjectPool, when we want to delete the old one we use the release(clip) method:

	// recycle objects
	private function onExitShape(clip:MovieClip):void
	{
		// remove from the ObjectPool and the clipContainer
		objectPool.release(clip);
		clipContainer.removeChild(clip);

		// get a new clip from the ObjectPool
		objectPool.request();
	}

Step 17: Adding a Blur

HYPE features the ability to very easily add filters such as blur and glow to objects. To add a touch more pizzazz to the design we’re going to add a BlurFilter to the project using the FilterCanvasRhythm:

	// think of the BitmapCanvas as an empty space we will 'paint'
	// every frame with new image data
	bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
	bitmapCanvas.startCapture(clipContainer, true);
	addChild(bitmapCanvas);

	// adding a blur
	var blur:FilterCanvasRhythm = new FilterCanvasRhythm([new BlurFilter(1.1, 1.1, 1)], bitmapCanvas);
	blur.start(TimeType.TIME, 100);

	// create a collection of objects and store them in an ObjectPool
	// for use in the animation
	objectPool = new ObjectPool(circleShape, 100);

The above code creates a FilterCanvasRhythm which takes a Filter as a parameter and applies it to the bitmapCanvas we declared earlier.

Test the project, it’s really starting to come together now!


Step 18: Adding Some Diversity

We can easily add a little depth to the composition by adding more shapes in to the mix. Rather than having to create and manage several ObjectPools, we can add frames to the original circleShape we used and randomly select which frame to play.

Try this now, edit the circleShape object in the Flash Library. Create a new Keyframe, select a new color and draw a new shape. Go ahead and create a few Keyframes of your own, in the next step we’ll look at implementing them with code. This is our new shape:

Offsetting the circleShape for spirals

..compared with our old shape:

Offsetting the circleShape for spirals

Step 19: Choosing Random Frames for circleShape

With our circleShape now sporting a few new Keyframes we can simply insert this single line of code to choose a frame to use each time we call objectPool.request():

	// each time we request a new shape from the pool
	// it will perform the following
	objectPool.onRequestObject = function(clip:MovieClip):void
	{
		clip.x = stage.stageWidth/2;
		clip.y = stage.stageHeight/2;

		// choose a random frame
		clip.gotoAndStop(Math.ceil(Math.random() * 3));

		// add a VariableVibration for the x/y movement of each circleShape
		var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
		var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
		xVib.start();
		yVib.start();

		// add a FixedVibration to the alpha and scale properties of each circleShape when requested
		var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
		var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
		alphaVib.start();
		scaleVib.start();

		// add a FixedVibration to the rotation of the circleShape
		var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
		rotationVib.start();

		// define an ExitShape
		var exit:ExitShapeTrigger = new ExitShapeTrigger(onExitShape, clip, exitShape, true);
		exit.start();

		clipContainer.addChild(clip);
	}

As a quick note, the random frame code above will switch between frames 1, 2 and 3. You may need to adjust this to the amount of frames in your circleShape.


Step 20: Finish

It’s time to test your movie and bask in the mixture of funky patterns and colors as the HYPE framework takes your code and mixes it into a piece of generative art.

Heres the final code for reference:

package
{
	import hype.extended.behavior.FixedVibration;

	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.filters.BlurFilter;
	import hype.extended.behavior.VariableVibration;
	import hype.extended.rhythm.FilterCanvasRhythm;
	import hype.extended.trigger.ExitShapeTrigger;
	import hype.framework.core.ObjectPool;
	import hype.framework.core.TimeType;
	import hype.framework.display.BitmapCanvas;

	/**
	 * A tutorial to introduce HYPE. A visual framework
	 * by Branden Hall and Joshua David for creating
	 * generative / iterative design with code.
	 *
	 * @author Anton Mills
	 * @version 06/02/2011
	 */
	public class Main extends MovieClip
	{
		// private properties
		private var bitmapCanvas:BitmapCanvas;
		private var clipContainer:Sprite;
		private var objectPool:ObjectPool;

		/**
		 * constructor
		 */
		public function Main()
		{
			// inits the Hype framework
			initHype();

			// begin sequence
			objectPool.requestAll();
		}

		/**
		 * initiation of the Hype members we will be using and configuration prior
		 * to running the animation
		 */
		private function initHype():void
		{
			// the clipContainer is used as a parent for all of our sprites
			clipContainer = new Sprite();
			addChild(clipContainer);

			// think of the BitmapCanvas as an empty space we will 'paint'
			// every frame with new image data
			bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
			bitmapCanvas.startCapture(clipContainer, true);
			addChild(bitmapCanvas);

			// adding a blur
			var blur:FilterCanvasRhythm = new FilterCanvasRhythm([new BlurFilter(1.1, 1.1, 1)], bitmapCanvas);
			blur.start(TimeType.TIME, 100);

			// create a collection of objects and store them in an ObjectPool
			// for use in the animation
			objectPool = new ObjectPool(circleShape, 100);

			// each time we request a new shape from the pool
			// it will perform the following
			objectPool.onRequestObject = function(clip:MovieClip):void
			{
				clip.x = stage.stageWidth/2;
				clip.y = stage.stageHeight/2;

				// choose a random frame
				clip.gotoAndStop(Math.ceil(Math.random() * 3));

				// add a VariableVibration for the x/y movement of each circleShape
				var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
				var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
				xVib.start();
				yVib.start();

				// add a FixedVibration to the alpha and scale properties of each circleShape when requested
				var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
				var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
				alphaVib.start();
				scaleVib.start();

				// add a FixedVibration to the rotation of the circleShape
				var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
				rotationVib.start();

				// define an ExitShape
				var exit:ExitShapeTrigger = new ExitShapeTrigger(onExitShape, clip, exitShape, true);
				exit.start();

				clipContainer.addChild(clip);
			};
		}

		// recycle objects
		private function onExitShape(clip:MovieClip):void
		{
			objectPool.release(clip);
			clipContainer.removeChild(clip);

			objectPool.request();
		}
	}
}

Conclusion

This just about wraps up introducing the HYPE framework, thanks very much for your time. I hope you enjoyed it and remember we only scratched the surface of some of the fantastic effects that can be made with the framework. Please do check out the HYPE framework website at www.hypeframework.org for some fantastic examples of the framework and how others have taken it to the next level with Away3D/Papervision integration!


More HYPE Resources on Activetuts+

  • Code a Chaotic Composition Inspired by Joshua Davis by Bruno Crociquia
  • Introduction to the HYPE ActionScript 3.0 Framework by Tom Green
  • Quick Tip: How to Export Flash to PNG with HYPE by Daniel Apt
  • Create a Mesmeric Music Visualizer with HYPE by Franci Zidar



View full post on Activetuts+

Jan 1, 2011 Posted on Jan 1, 2011 in Flash Video Training | 24 comments

Creating Smooth Animations in Flash


How to create smooth animations in flash.

Page 1 of 612345...»Last »
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
May 2013
M T W T F S S
« Jul    
 12345
6789101112
13141516171819
20212223242526
2728293031  
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