logo
468x60-2-495


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

UI Design for Developers: Introduction

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

Think: the first impression is the last impression.


Alignment

Alignment refers to the position or orientation of an element in relation to another element or to itself. When we refer to two elements being aligned to each other, alignment usually refers to which side of both elements is in line. In the context of text, alignment refers to the side to which text is anchored in a straight line.

Form Design

Alignment of form fields

In the image above, the second example of a simple form design shows labels that are right-aligned to each other with input fields that are left-aligned. This ensures that the association between each label and its input field is clear and the user does not get confused if some labels are too small while others are long.

Think: Make sure input fields are not too far away from the longest label. If the variation in width is small, try right-aligning labels and left-aligning input fields.

Text

Text alignment

For text, it is ideal to use left-alignment when desiging for the screen. Since most for-screen type rendering methods are incapable of distributing space appropriately when justifying text to both sides, left alignment keeps text readable and well organized. You can, of course, use center and right alignment where the design demands it, but those are usually reserved for special cases and smaller chunks of text.


Flow

The primary purpose of any user interface is to let the user interface with the application. This, believe it or not, is not going to be possible unless you tell the user what he needs to do and in what order. Since you won’t be there behind every user to help them out with this, the interface needs to provide all the cues. Here are some questions to ask when evaluating whether the intended workflow is appropriate:

  • How critical is it that the task be performed in a set order of steps?
  • Is it obvious to the user where to start and what to do next?
  • Is the intended outcome stated or implied – implicitly, if not explicitly?
Search with category selection n iStockPhoto

Let’s take the example of a search category selection on iStockPhoto. In this case, I can either search everything or select a specific category to limit my searches to that type of information. Since the primary act is to enter a search term and hit Search, those should be fairly obvious. A possible step in between is to select a category, which can be a drop-down list between (you guessed it right) the search field and the Search button.

The income/expense entry dialog in cashbase

Another example is the income/expense input dialog in the cashbase app. The fields are arranged according to the typical workflow one will use to log such information: enter the amount (which is the most important element), select a category, add a note if necessary, and click Add. Secondary information that will be used much less frequently – like the date which by default is today, and the option to repeat or cancel – are available, but much more subtle.

Further reading:

  • Designing for Flow

Proximity

Related elements in an interface should be grouped together. This might sound like common sense when I mention it, but it is not always well understood. The reason all page navigation links on most websites are laid out in a single horizontal bar, is so that the user can identify the relationship at a glance and make the choice to interact with them without any confusion.

The message toolbar in Gmail

Let’s look at this example from Gmail – an app that many of use on a regular basis. This is the toolbar that appears at the top when you open a mail. Although all those buttons perform some action on the open message, they are further grouped together based on what they do – actions one would use to get rid of the message (archive, spam, delete), to change the importance of the message (when using priority inbox), label-related actions, and finally a drop-down with secondary options.

Feature grouping in Zootool

Another example of good use of proximity is the options bar in Zootool. The toolbar at the bottom is divided into three sets, each corresponding to the three panes in the app: the list packs on the left, the mail window in the center which contains all your bookmarks, and the details pane on the right.

Further reading:

  • Proximity in Design: Why I can’t use my car’s A/C
  • Design Basics: Proximity (Or Why Skype’s "End Call" Button Is All Wrong)

Hierarchy

Not everything in a user interface, or any layout for that matter, carries the same importance as everything else. Hierarchy is the arrangement of elements in a way that denotes what is higher in order, what comes next, and so on.

A layout with no sense of hierarchy within elements

Let’s look at this example here and try to identify what the order of precedence is. Since everything – titles, labels and paragraph text – looks the same, one has to read through everything to make sense. If the same interface was tweaked just a little bit like below, the overall impact on the readability and in turn the usability of the interface is enormous.

The same layout with a better sense of hierarchy

As a general rule, the page heading should be biggest and most visible on the screen. This is followed by section titles, sub-titles and then smaller labels. Paragraph text can be more or less prominent depending on its purpose. It is also not limited to text. Primary action buttons can be differentiated from secondary actions by making them brighter, bigger or fancier. Input fields for mandatory inputs can be made more obvious than the others. I could go on, but I think you get the idea.


Contrast

Another very important consideration when designing interfaces is to ensure clear differentiation between elements. Of course, you want the text to be readable on the background, but contrast goes beyond simply using light text on a dark background or vice versa. Headings and paragraph text should be clearly distinguishable. Panels and navigation bars need to be segregated from each other so the user knows what is what. The list goes on.

Contrast can be established using one or more of the following characteristics:

Color

This should be obvious, but its amazing how often people slip on this point. If your background is light, you obviously want the text to be dark to ensure readability. Although in theory complimentary colors should work well together, it is not always that easy. Try placing bright green text on a red background and you will know what I’m saying.

Good & bad examples of contrast

The possibilities here are limitless, so my first recommendation to anyone looking to select colors is to pick up a popular color palette from sites like Adobe Kuler or ColourLovers. They are contributed, evaluated and voted up by passionate users who usually know their way around color. All the basics of color matching and contrast are usually taken care of, so its just a matter of deciding which color scheme works in your app’s context.

Browsing through color palettes on Kuler & ColourLovers

One note of caution though – be very wary of going overboard with color. You don’t want them to overshadow the utility and usability of your app.

Size

Another good way to differentiate between elements – based on hierarchy, categorization, or visual flow – is to use different sizes. This applies to text as much as it does to images, backgrounds and static or interactive elements. You may want to put more emphasis on the primary action button, for example, and keep the secondary buttons comparatively less accessible. Or optional prompts can be smaller and lighter than the primary labels in a form.

Yesterday, today and tomorrow in Teuxdeux

The TeuxDeux app does a brilliant job of using color to differentiate between past, present and future days. Since the layout is geared towards a work week, different sizes of text are used to make sure that names of days are easy to identify, while the dates are comparatively more subtle.


Interaction

Since the primary purpose of any user interface is to enable users interact with the app, it is imperative that learners intuitively know what to do. As creators of the interface, it is very easy to forget that you won’t be there for every user to tell them what to do. Neither do users have the patience any more to read manuals and quick start guides before diving into using an app. The interface is required to make it amply clear what parts of it are clickable, touchable, draggable – in short, interactive.

Everyone knows how to flick an electrical switch, right? The thing that makes it obvious to anyone that a switch needs to be pressed at a certain point to change state is called affordance. On the flat surface of a screen – desktop, mobile or otherwise – different techniques can be utilized to enable users intuitively click a button or type inside an input field. When creating text hyperlinks, adding an underline for the link is the most commonly used standard, although there are many other creative ways to do that.

Here are some examples:

Each interactive element has a different interaction objective, and therefore a different visual treatment

Going with the switch example, how do you know if flicking the switch did what it was supposed to do? The light comes on or goes off, or in some cases a light inside the switch helps make it clear whether the switch is on or off.

In an application, such feedback can be very obvious in cases where a button navigates to another page or opens a popup, but what about situations where all it does is process some data in the background – like when saving changes to the user settings? Some sort of a feedback mechanism is critical to let users know their action was successful. This could be as simple as a "your settings were saved" message, a brief notification at the top of the page, or a quick highlight around the area that was updated.

Two-level feedback in Remember the Milk

When you add a new task in Remember the Milk, it can either appear in the list on the same page, or simply get added to another list in the background (if, for example, the task has been assigned to a different category). The feedback for the action is therefore provided at two levels:

  1. a green highlight appears for a couple of seconds behind the task in the list to point to where it has been added, and
  2. a very prominent message appears on a yellow background at the top of the page letting the user know what exactly happened.

Typography

The text in your app – everything from the logo to the titles, labels and copy – is your primary mode of communication with the users. Since it is how your users access information about the app or through it, how you set the type can mean the difference between success and failure. Of course titles have to be bigger than body text and the fine print has to be, well, fine; but a lot of other decisions also influence how users consume information.

Fonts

Step one: define your fonts. It surprises me how many developers simply never bother to change whatever font their text gets generated in. Default fonts change from OS to OS and browser to browser, which means that unless you explicitly state what font you want to use, your text is going to look different in every OS and browser combination. Besides, Times New Roman – which a lot of browsers still use as the default font – is just not a good font for on-screen reading. My first recommendation is often to use a sans-serif font, although Georgia or the new Cambria font in Windows 7 also look good.

Sans-serif fonts make a big difference to the readability of text over Times New Roman

If you decide to use fonts other than the safe, universally available ones like Arial/Helvetica, Georgia, Tahoma etc., make sure there is a way to have them render similarly on all platforms. If Flash is your development environment of choice, embed them where necessary. For HTML/JS based apps, use @font-face in CSS or any of the web font services like Typekit or Google WebFonts. Remember though, that these techniques come with a caveat of extra file sizes for the embedded fonts. If speed and responsiveness are paramount for you, sticking to the base fonts is your best bet.

Disclaimer: Yes, I do know that Arial and Helvetica are not exactly similar, but they are similar enough for most users to not notice the difference.

Leading

The amount of space between two lines of text is the leading. You want the leading of your paragraph text (line-height in CSS speak) to be at least 140% of the font size to make sure it is easily readable. Any less and your text is going to be much harder to read and – more imporantly – to scan through.

Text leading makes a huge difference to the readability of your text

Localization

If you plan to translate your app into oither languages – and you really should – it is best to test the interface early on with different scripts. At the very least, the amount of space a certain message requires can vary drastically across different scripts. The East Asian scripts use fewer words on an average but need a bigger font size, Indian (Indic) scripts also need to be slightly bigger to be readable and middle-eastern scripts (like Arabic) go from right to left instead of the usual left-to-right.

Wrapping Up

That’s about it for now. I hope these tips covered enough basics for you to start applying them in your projects right away. As with most design-related disciplines, there are no hard and fast rules to follow, and everyone has their own take on how things should work. So if you disagree with any of my suggestions above – or even if you agree with them but have a different perspective – let’s hear about them in the comments.

Next up, we will take all of this wisdom and try applying it to an actual interface. Stay tuned!



View full post on Activetuts+

banner ad

10 Responses to “UI Design for Developers: Introduction”

  1. Ashish Bogawat says:
    October 20, 2011 at 1:13 am

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

    Think: the first impression is the last impression.


    Alignment

    Alignment refers to the position or orientation of an element in relation to another element or to itself. When we refer to two elements being aligned to each other, alignment usually refers to which side of both elements is in line. In the context of text, alignment refers to the side to which text is anchored in a straight line.

    Form Design

    Alignment of form fields

    In the image above, the second example of a simple form design shows labels that are right-aligned to each other with input fields that are left-aligned. This ensures that the association between each label and its input field is clear and the user does not get confused if some labels are too small while others are long.

    Think: Make sure input fields are not too far away from the longest label. If the variation in width is small, try right-aligning labels and left-aligning input fields.

    Text

    Text alignment

    For text, it is ideal to use left-alignment when desiging for the screen. Since most for-screen type rendering methods are incapable of distributing space appropriately when justifying text to both sides, left alignment keeps text readable and well organized. You can, of course, use center and right alignment where the design demands it, but those are usually reserved for special cases and smaller chunks of text.


    Flow

    The primary purpose of any user interface is to let the user interface with the application. This, believe it or not, is not going to be possible unless you tell the user what he needs to do and in what order. Since you won’t be there behind every user to help them out with this, the interface needs to provide all the cues. Here are some questions to ask when evaluating whether the intended workflow is appropriate:

    • How critical is it that the task be performed in a set order of steps?
    • Is it obvious to the user where to start and what to do next?
    • Is the intended outcome stated or implied – implicitly, if not explicitly?
    Search with category selection n iStockPhoto

    Let’s take the example of a search category selection on iStockPhoto. In this case, I can either search everything or select a specific category to limit my searches to that type of information. Since the primary act is to enter a search term and hit Search, those should be fairly obvious. A possible step in between is to select a category, which can be a drop-down list between (you guessed it right) the search field and the Search button.

    The income/expense entry dialog in cashbase

    Another example is the income/expense input dialog in the cashbase app. The fields are arranged according to the typical workflow one will use to log such information: enter the amount (which is the most important element), select a category, add a note if necessary, and click Add. Secondary information that will be used much less frequently – like the date which by default is today, and the option to repeat or cancel – are available, but much more subtle.

    Further reading:

    • Designing for Flow

    Proximity

    Related elements in an interface should be grouped together. This might sound like common sense when I mention it, but it is not always well understood. The reason all page navigation links on most websites are laid out in a single horizontal bar, is so that the user can identify the relationship at a glance and make the choice to interact with them without any confusion.

    The message toolbar in Gmail

    Let’s look at this example from Gmail – an app that many of use on a regular basis. This is the toolbar that appears at the top when you open a mail. Although all those buttons perform some action on the open message, they are further grouped together based on what they do – actions one would use to get rid of the message (archive, spam, delete), to change the importance of the message (when using priority inbox), label-related actions, and finally a drop-down with secondary options.

    Feature grouping in Zootool

    Another example of good use of proximity is the options bar in Zootool. The toolbar at the bottom is divided into three sets, each corresponding to the three panes in the app: the list packs on the left, the mail window in the center which contains all your bookmarks, and the details pane on the right.

    Further reading:

    • Proximity in Design: Why I can’t use my car’s A/C
    • Design Basics: Proximity (Or Why Skype’s "End Call" Button Is All Wrong)

    Hierarchy

    Not everything in a user interface, or any layout for that matter, carries the same importance as everything else. Hierarchy is the arrangement of elements in a way that denotes what is higher in order, what comes next, and so on.

    A layout with no sense of hierarchy within elements

    Let’s look at this example here and try to identify what the order of precedence is. Since everything – titles, labels and paragraph text – looks the same, one has to read through everything to make sense. If the same interface was tweaked just a little bit like below, the overall impact on the readability and in turn the usability of the interface is enormous.

    The same layout with a better sense of hierarchy

    As a general rule, the page heading should be biggest and most visible on the screen. This is followed by section titles, sub-titles and then smaller labels. Paragraph text can be more or less prominent depending on its purpose. It is also not limited to text. Primary action buttons can be differentiated from secondary actions by making them brighter, bigger or fancier. Input fields for mandatory inputs can be made more obvious than the others. I could go on, but I think you get the idea.


    Contrast

    Another very important consideration when designing interfaces is to ensure clear differentiation between elements. Of course, you want the text to be readable on the background, but contrast goes beyond simply using light text on a dark background or vice versa. Headings and paragraph text should be clearly distinguishable. Panels and navigation bars need to be segregated from each other so the user knows what is what. The list goes on.

    Contrast can be established using one or more of the following characteristics:

    Color

    This should be obvious, but its amazing how often people slip on this point. If your background is light, you obviously want the text to be dark to ensure readability. Although in theory complimentary colors should work well together, it is not always that easy. Try placing bright green text on a red background and you will know what I’m saying.

    Good & bad examples of contrast

    The possibilities here are limitless, so my first recommendation to anyone looking to select colors is to pick up a popular color palette from sites like Adobe Kuler or ColourLovers. They are contributed, evaluated and voted up by passionate users who usually know their way around color. All the basics of color matching and contrast are usually taken care of, so its just a matter of deciding which color scheme works in your app’s context.

    Browsing through color palettes on Kuler & ColourLovers

    One note of caution though – be very wary of going overboard with color. You don’t want them to overshadow the utility and usability of your app.

    Size

    Another good way to differentiate between elements – based on hierarchy, categorization, or visual flow – is to use different sizes. This applies to text as much as it does to images, backgrounds and static or interactive elements. You may want to put more emphasis on the primary action button, for example, and keep the secondary buttons comparatively less accessible. Or optional prompts can be smaller and lighter than the primary labels in a form.

    Yesterday, today and tomorrow in Teuxdeux

    The TeuxDeux app does a brilliant job of using color to differentiate between past, present and future days. Since the layout is geared towards a work week, different sizes of text are used to make sure that names of days are easy to identify, while the dates are comparatively more subtle.


    Interaction

    Since the primary purpose of any user interface is to enable users interact with the app, it is imperative that learners intuitively know what to do. As creators of the interface, it is very easy to forget that you won’t be there for every user to tell them what to do. Neither do users have the patience any more to read manuals and quick start guides before diving into using an app. The interface is required to make it amply clear what parts of it are clickable, touchable, draggable – in short, interactive.

    Everyone knows how to flick an electrical switch, right? The thing that makes it obvious to anyone that a switch needs to be pressed at a certain point to change state is called affordance. On the flat surface of a screen – desktop, mobile or otherwise – different techniques can be utilized to enable users intuitively click a button or type inside an input field. When creating text hyperlinks, adding an underline for the link is the most commonly used standard, although there are many other creative ways to do that.

    Here are some examples:

    Each interactive element has a different interaction objective, and therefore a different visual treatment

    Going with the switch example, how do you know if flicking the switch did what it was supposed to do? The light comes on or goes off, or in some cases a light inside the switch helps make it clear whether the switch is on or off.

    In an application, such feedback can be very obvious in cases where a button navigates to another page or opens a popup, but what about situations where all it does is process some data in the background – like when saving changes to the user settings? Some sort of a feedback mechanism is critical to let users know their action was successful. This could be as simple as a "your settings were saved" message, a brief notification at the top of the page, or a quick highlight around the area that was updated.

    Two-level feedback in Remember the Milk

    When you add a new task in Remember the Milk, it can either appear in the list on the same page, or simply get added to another list in the background (if, for example, the task has been assigned to a different category). The feedback for the action is therefore provided at two levels:

    1. a green highlight appears for a couple of seconds behind the task in the list to point to where it has been added, and
    2. a very prominent message appears on a yellow background at the top of the page letting the user know what exactly happened.

    Typography

    The text in your app – everything from the logo to the titles, labels and copy – is your primary mode of communication with the users. Since it is how your users access information about the app or through it, how you set the type can mean the difference between success and failure. Of course titles have to be bigger than body text and the fine print has to be, well, fine; but a lot of other decisions also influence how users consume information.

    Fonts

    Step one: define your fonts. It surprises me how many developers simply never bother to change whatever font their text gets generated in. Default fonts change from OS to OS and browser to browser, which means that unless you explicitly state what font you want to use, your text is going to look different in every OS and browser combination. Besides, Times New Roman – which a lot of browsers still use as the default font – is just not a good font for on-screen reading. My first recommendation is often to use a sans-serif font, although Georgia or the new Cambria font in Windows 7 also look good.

    Sans-serif fonts make a big difference to the readability of text over Times New Roman

    If you decide to use fonts other than the safe, universally available ones like Arial/Helvetica, Georgia, Tahoma etc., make sure there is a way to have them render similarly on all platforms. If Flash is your development environment of choice, embed them where necessary. For HTML/JS based apps, use @font-face in CSS or any of the web font services like Typekit or Google WebFonts. Remember though, that these techniques come with a caveat of extra file sizes for the embedded fonts. If speed and responsiveness are paramount for you, sticking to the base fonts is your best bet.

    Disclaimer: Yes, I do know that Arial and Helvetica are not exactly similar, but they are similar enough for most users to not notice the difference.

    Leading

    The amount of space between two lines of text is the leading. You want the leading of your paragraph text (line-height in CSS speak) to be at least 140% of the font size to make sure it is easily readable. Any less and your text is going to be much harder to read and – more imporantly – to scan through.

    Text leading makes a huge difference to the readability of your text

    Localization

    If you plan to translate your app into oither languages – and you really should – it is best to test the interface early on with different scripts. At the very least, the amount of space a certain message requires can vary drastically across different scripts. The East Asian scripts use fewer words on an average but need a bigger font size, Indian (Indic) scripts also need to be slightly bigger to be readable and middle-eastern scripts (like Arabic) go from right to left instead of the usual left-to-right.

    Wrapping Up

    That’s about it for now. I hope these tips covered enough basics for you to start applying them in your projects right away. As with most design-related disciplines, there are no hard and fast rules to follow, and everyone has their own take on how things should work. So if you disagree with any of my suggestions above – or even if you agree with them but have a different perspective – let’s hear about them in the comments.

    Next up, we will take all of this wisdom and try applying it to an actual interface. Stay tuned!


  2. Michael James Williams says:
    October 20, 2011 at 1:45 am
    This entry is part 3 of 3 in the series Box2D for Flash and AS3

    In the first two parts of this series, we created two simple types of object, rendered using Flash’s display list. In this part, we’ll see how to extend this to let us create as many different types of object as we want, without our code getting all tangled up!

    I recommend reading this series from the start, but if you want to start here, then grab this zip file — it contains the source code from the end of the the second part. (The Download button above contains the source code from the end of this part.)


    Step 1: New Balls Please

    Let’s take a quick look at where we left off:

    Bunch of wheels and crates bouncing around. The wheels don’t all have the same properties; each wheel has a random size, restitution, friction, and density. Ditto for the crates.

    That’s been fine for testing, but now let’s make things a little less random. We’ll start by replacing the wheels with tennis balls, which all have the same properties.

    First, draw a tennis ball (or get a photo of one). Here’s mine:

    To make yours consistent with mine, make sure that it’s called TennisBall.png, that you save it in \lib\, that it’s 35x35px, and that it has a transparent background. (You can change any of these points, if you wish, but you’ll have to figure out how to modify your code accordingly.)

    Embed the PNG into your Main.as file, just like we’ve done before:

    
    
    [Embed(source='../lib/TennisBall.png')]
    public var TennisBall:Class;
    

    Now, create two arrays: one for your tennis ball Box2D objects, and one for the corresponding images:

    
    
    public var tennisBallArray:Array;
    public var tennisBallImages:Array;
    
    
    
    tennisBallArray = new Array();
    tennisBallImages = new Array();
    

    (This is all much the same as we did in the second part of this series, so take another look at that if you need a refresher.)

    Now we need a function to create a single tennis ball. Here’s what we use to create a single wheel:

    
    
    private function createWheel(mRadius:Number, pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var wheelBodyDef:b2BodyDef = new b2BodyDef();
    	wheelBodyDef.type = b2Body.b2_dynamicBody;
    	wheelBodyDef.position.Set(pxStartX * pxToM, pxStartY * pxToM);
    	var wheelBody:b2Body = world.CreateBody(wheelBodyDef);
    	var circleShape:b2CircleShape = new b2CircleShape(mRadius);
    	var wheelFixtureDef:b2FixtureDef = new b2FixtureDef();
    	wheelFixtureDef.shape = circleShape;
    	wheelFixtureDef.restitution = (Math.random() * 0.5) + 0.5;
    	wheelFixtureDef.friction = (Math.random() * 1.0);
    	wheelFixtureDef.density = Math.random() * 20;
    	var wheelFixture:b2Fixture = wheelBody.CreateFixture(wheelFixtureDef);
    
    	var startingVelocity:b2Vec2 = new b2Vec2(mVelocityX, mVelocityY);
    	wheelBody.SetLinearVelocity(startingVelocity);
    
    	wheelArray.push(wheelBody);
    
    	var wheelImage:Bitmap = new SimpleWheel();
    	wheelImage.width = mRadius * 2 * mToPx;
    	wheelImage.height = mRadius * 2 * mToPx;
    	var wheelSprite:Sprite = new Sprite();
    	wheelSprite.addChild(wheelImage);
    	wheelSprite.x = pxStartX;
    	wheelSprite.y = pxStartY;
    	wheelImages.push(wheelSprite);
    	this.addChild(wheelSprite);
    	wheelSprite.addEventListener(MouseEvent.CLICK, onClickWheelImage);
    }
    

    We can copy this and modify it to our needs. Since all tennis balls will have the same properties (size, restitution, friction, and density), we don’t need the mRadius argument, and we don’t need to use random numbers anywhere. It’s hard to guess what values of restitution and so on will be correct, so just have a go – we can always correct them later.

    Here’s my createTennisBall() function:

    
    
    private function createTennisBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var tennisBallBodyDef:b2BodyDef = new b2BodyDef();
    	tennisBallBodyDef.type = b2Body.b2_dynamicBody;
    	tennisBallBodyDef.position.Set(pxStartX * pxToM, pxStartY * pxToM);
    	var tennisBallBody:b2Body = world.CreateBody(tennisBallBodyDef);
    	var circleShape:b2CircleShape = new b2CircleShape(35 * .5 * pxToM);
    	var tennisBallFixtureDef:b2FixtureDef = new b2FixtureDef();
    	tennisBallFixtureDef.shape = circleShape;
    	tennisBallFixtureDef.restitution = 0.8;
    	tennisBallFixtureDef.friction = 0.75;
    	tennisBallFixtureDef.density = 1.0;
    	var tennisBallFixture:b2Fixture = tennisBallBody.CreateFixture(tennisBallFixtureDef);
    
    	var startingVelocity:b2Vec2 = new b2Vec2(mVelocityX, mVelocityY);
    	tennisBallBody.SetLinearVelocity(startingVelocity);
    
    	tennisBallArray.push(tennisBallBody);
    
    	var tennisBallImage:Bitmap = new TennisBall();
    	var tennisBallSprite:Sprite = new Sprite();
    	tennisBallSprite.addChild(tennisBallImage);
    	tennisBallSprite.x = pxStartX;
    	tennisBallSprite.y = pxStartY;
    	tennisBallImages.push(tennisBallSprite);
    	this.addChild(tennisBallSprite);
    	//tennisBallSprite.addEventListener(MouseEvent.CLICK, onClickWheelImage);
    }
    

    A few things to note:

    • The b2CircleShape() constructor is expecting to receive the radius of the tennis ball, in meters, and I don’t want to squash or enlarge the image I’ve made. I guess I could look up the radius of an actual tennis ball, enter this value in here, and alter the pxToM scale factor to make everything else fit, but instead I’ve just told the constructor to convert the pixel radius of my tennis ball image to meters.
    • Restituion is the bounciness of the object, on a scale of 0 to 1; tennis balls are pretty bouncy so I’ve set this quite high.
    • Friction is also between 0 and 1; tennis balls are quite rough so I set this fairly high, too.
    • Density is not limited to any particular range; tennis balls are mostly air, so I set this to the same value as my crates (which I’m also assuming are empty).
    • Unlike in createWheel(), there’s no need to resize the image (as I mentioned above), so I’ve deleted those lines.
    • I’ve just commented the onClickWheelImage event listener out for now, as it’s not relevant.

    Try to compile the SWF. It should work – if it didn’t, you missed something out – but since we aren’t actually calling createTennisBall() from anywhere, nothing will be different.


    Step 2: Creating Tennis Balls

    Let’s just remove the wheels straight away, and replace them with tennis balls. Change this code, in getStarted():

    
    
    for (var i:int = 0; i < 20; i++)
    {
    	createWheel(
    		Math.random() * 0.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    …to this:

    
    
    for (var i:int = 0; i < 20; i++)
    {
    	createTennisBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    Note that the first argument has been deleted, since we don’t manually set the size any more, but all other arguments remain the same. Try it out:

    Hmm… not quite right. Ah, of course – we didn’t add any code to render the tennis balls. We’ll do that next. Change onTick() from this:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var wheelImage:Sprite;
    	for each (var wheelBody:b2Body in wheelArray)
    	{
    		wheelImage = wheelImages[wheelArray.indexOf(wheelBody)];
    		wheelImage.x = (wheelBody.GetPosition().x * mToPx) - (wheelImage.width * 0.5);
    		wheelImage.y = (wheelBody.GetPosition().y * mToPx) - (wheelImage.height * 0.5);
    	}
    
    	var crateImage:Sprite;
    	for each (var crateBody:b2Body in crateArray)
    	{
    		crateImage = crateImages[crateArray.indexOf(crateBody)];
    		crateImage.x = (crateBody.GetPosition().x * mToPx);// - (crateImage.width * 0.5);
    		crateImage.y = (crateBody.GetPosition().y * mToPx);// - (crateImage.height * 0.5);
    		crateImage.rotation = crateBody.GetAngle() * radToDeg;
    	}
    }
    

    …to this:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var tennisBallImage:Sprite;
    	for each (var tennisBallBody:b2Body in tennisBallArray)
    	{
    		tennisBallImage = tennisBallImages[tennisBallArray.indexOf(tennisBallBody)];
    		tennisBallImage.x = (tennisBallBody.GetPosition().x * mToPx) - (tennisBallImage.width * 0.5);
    		tennisBallImage.y = (tennisBallBody.GetPosition().y * mToPx) - (tennisBallImage.height * 0.5);
    	}
    
    	var crateImage:Sprite;
    	for each (var crateBody:b2Body in crateArray)
    	{
    		crateImage = crateImages[crateArray.indexOf(crateBody)];
    		crateImage.x = (crateBody.GetPosition().x * mToPx);// - (crateImage.width * 0.5);
    		crateImage.y = (crateBody.GetPosition().y * mToPx);// - (crateImage.height * 0.5);
    		crateImage.rotation = crateBody.GetAngle() * radToDeg;
    	}
    }
    

    (It’s really just a case of doing a find-and-replace, switching “wheel” to “tennisBall”.) Try the SWF now:

    Better, but we don’t have any rotation (we didn’t need it before, because the wheels were all rotationally symmetric). Add that now:

    
    
    var tennisBallImage:Sprite;
    for each (var tennisBallBody:b2Body in tennisBallArray)
    {
    	tennisBallImage = tennisBallImages[tennisBallArray.indexOf(tennisBallBody)];
    	tennisBallImage.x = (tennisBallBody.GetPosition().x * mToPx) - (tennisBallImage.width * 0.5);
    	tennisBallImage.y = (tennisBallBody.GetPosition().y * mToPx) - (tennisBallImage.height * 0.5);
    	tennisBallImage.rotation = tennisBallBody.GetAngle() * radToDeg;
    }
    

    Ah. Remember we had this problem with the crates? Remember how we solved it? Have a go at doing the same here, on your own. My solution is below if you want to check:

    
    
    private function createTennisBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var tennisBallBodyDef:b2BodyDef = new b2BodyDef();
    	tennisBallBodyDef.type = b2Body.b2_dynamicBody;
    	tennisBallBodyDef.position.Set(pxStartX * pxToM, pxStartY * pxToM);
    	var tennisBallBody:b2Body = world.CreateBody(tennisBallBodyDef);
    	var circleShape:b2CircleShape = new b2CircleShape(35 * .5 * pxToM);
    	var tennisBallFixtureDef:b2FixtureDef = new b2FixtureDef();
    	tennisBallFixtureDef.shape = circleShape;
    	tennisBallFixtureDef.restitution = 0.8;
    	tennisBallFixtureDef.friction = 0.75;
    	tennisBallFixtureDef.density = 1.0;
    	var tennisBallFixture:b2Fixture = tennisBallBody.CreateFixture(tennisBallFixtureDef);
    
    	var startingVelocity:b2Vec2 = new b2Vec2(mVelocityX, mVelocityY);
    	tennisBallBody.SetLinearVelocity(startingVelocity);
    
    	tennisBallArray.push(tennisBallBody);
    
    	var tennisBallImage:Bitmap = new TennisBall();
    	var tennisBallSprite:Sprite = new Sprite();
    	tennisBallSprite.addChild(tennisBallImage);
    	tennisBallImage.x -= tennisBallImage.width / 2;
    	tennisBallImage.y -= tennisBallImage.height / 2;
    	tennisBallSprite.x = pxStartX;
    	tennisBallSprite.y = pxStartY;
    	tennisBallImages.push(tennisBallSprite);
    	this.addChild(tennisBallSprite);
    	//tennisBallSprite.addEventListener(MouseEvent.CLICK, onClickWheelImage);
    }
    
    //...
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var tennisBallImage:Sprite;
    	for each (var tennisBallBody:b2Body in tennisBallArray)
    	{
    		tennisBallImage = tennisBallImages[tennisBallArray.indexOf(tennisBallBody)];
    		tennisBallImage.x = (tennisBallBody.GetPosition().x * mToPx);// - (tennisBallImage.width * 0.5);
    		tennisBallImage.y = (tennisBallBody.GetPosition().y * mToPx);// - (tennisBallImage.height * 0.5);
    		tennisBallImage.rotation = tennisBallBody.GetAngle() * radToDeg;
    	}
    
    	var crateImage:Sprite;
    	for each (var crateBody:b2Body in crateArray)
    	{
    		crateImage = crateImages[crateArray.indexOf(crateBody)];
    		crateImage.x = (crateBody.GetPosition().x * mToPx);// - (crateImage.width * 0.5);
    		crateImage.y = (crateBody.GetPosition().y * mToPx);// - (crateImage.height * 0.5);
    		crateImage.rotation = crateBody.GetAngle() * radToDeg;
    	}
    }
    

    Test it out:

    Ace.


    Step 3: Creating Bowling Balls

    I’d like to add three more types of ball: a bowling ball, a basketball, and a rubber ball. As you can see from the above, it’s a pain to do the same thing over and over again. We’ll add the bowling ball next, and try to simplify the process so we don’t have to keep making this irritating little changes.

    Here’s my bowling ball image. Again, feel free to use your own, but try to make it 60x60px with the name BowlingBall.png:

    Embed the image and add the necessary arrays:

    
    
    [Embed(source='../lib/BowlingBall.png')]
    public var BowlingBall:Class;
    
    //...
    
    public var bowlingBallArray:Array;
    public var bowlingBallImages:Array;
    
    //...
    
    bowlingBallArray = new Array();
    bowlingBallImages = new Array();
    

    Write a createBowlingBall() function:

    
    
    private function createBowlingBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var bowlingBallBodyDef:b2BodyDef = new b2BodyDef();
    	bowlingBallBodyDef.type = b2Body.b2_dynamicBody;
    	bowlingBallBodyDef.position.Set(pxStartX * pxToM, pxStartY * pxToM);
    	var bowlingBallBody:b2Body = world.CreateBody(bowlingBallBodyDef);
    	var circleShape:b2CircleShape = new b2CircleShape(60 * .5 * pxToM);
    	var bowlingBallFixtureDef:b2FixtureDef = new b2FixtureDef();
    	bowlingBallFixtureDef.shape = circleShape;
    	bowlingBallFixtureDef.restitution = 0.0;	//not bouncy
    	bowlingBallFixtureDef.friction = 0.0;	//very smooth
    	bowlingBallFixtureDef.density = 20.0;	//very heavy
    	var bowlingBallFixture:b2Fixture = bowlingBallBody.CreateFixture(bowlingBallFixtureDef);
    
    	var startingVelocity:b2Vec2 = new b2Vec2(mVelocityX, mVelocityY);
    	bowlingBallBody.SetLinearVelocity(startingVelocity);
    
    	bowlingBallArray.push(bowlingBallBody);
    
    	var bowlingBallImage:Bitmap = new BowlingBall();
    	var bowlingBallSprite:Sprite = new Sprite();
    	bowlingBallSprite.addChild(bowlingBallImage);
    	bowlingBallImage.x -= bowlingBallImage.width / 2;
    	bowlingBallImage.y -= bowlingBallImage.height / 2;
    	bowlingBallSprite.x = pxStartX;
    	bowlingBallSprite.y = pxStartY;
    	bowlingBallImages.push(bowlingBallSprite);
    	this.addChild(bowlingBallSprite);
    	//bowlingBallSprite.addEventListener(MouseEvent.CLICK, onClickWheelImage);
    }
    

    …and create the actual objects:

    
    
    for (var i:int = 0; i < 20; i++)
    {
    	createTennisBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBowlingBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    Phew. Okay, now for the rendering. Let’s take another look at our rendering code so far:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var tennisBallImage:Sprite;
    	for each (var tennisBallBody:b2Body in tennisBallArray)
    	{
    		tennisBallImage = tennisBallImages[tennisBallArray.indexOf(tennisBallBody)];
    		tennisBallImage.x = (tennisBallBody.GetPosition().x * mToPx);// - (tennisBallImage.width * 0.5);
    		tennisBallImage.y = (tennisBallBody.GetPosition().y * mToPx);// - (tennisBallImage.height * 0.5);
    		tennisBallImage.rotation = tennisBallBody.GetAngle() * radToDeg;
    	}
    
    	var crateImage:Sprite;
    	for each (var crateBody:b2Body in crateArray)
    	{
    		crateImage = crateImages[crateArray.indexOf(crateBody)];
    		crateImage.x = (crateBody.GetPosition().x * mToPx);// - (crateImage.width * 0.5);
    		crateImage.y = (crateBody.GetPosition().y * mToPx);// - (crateImage.height * 0.5);
    		crateImage.rotation = crateBody.GetAngle() * radToDeg;
    	}
    }
    

    Notice anything? Thanks to the change we made in the last step – to fix the rotation problem – the two highlighted sections are almost identical; just swap out the word “tennisBall” for “crate” in each case and they’re a perfect match.

    This suggests that we could combine them into a single loop, which could be used to render all objects. That way, we wouldn’t need to create a new loop to render the bowling balls. Let’s look at this next.


    Step 4: Rendering in a Single Loop

    To do this, we just need to combine the tennisBallArray and crateArray into a single array. It’s easier if I show you:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var generalB2BodyArray:Array = new Array();
    	generalB2BodyArray = generalB2BodyArray.concat(tennisBallArray, crateArray);
    	var generalImages:Array = new Array();
    	generalImages = generalImages.concat(tennisBallImages, crateImages);
    
    	var generalImage:Sprite;
    	for each (var generalBody:b2Body in generalB2BodyArray)
    	{
    		generalImage = generalImages[generalB2BodyArray.indexOf(generalBody)];
    		generalImage.x = (generalBody.GetPosition().x * mToPx);
    		generalImage.y = (generalBody.GetPosition().y * mToPx);
    		generalImage.rotation = generalBody.GetAngle() * radToDeg;
    	}
    }
    

    See how that works? In lines 6-10, we create a couple of new arrays: one contains all the tennis ball and crate b2Body objects, and the other contains all the tennis ball and crate Sprites. Most importantly, they contain them in the same order – if the 17th element of generalImages[] is a tennis ball, then the 17th eleemnt of generalB2BodyArray[] is the same tennis ball’s b2Body.

    The for loop then does exactly the same as the two before it did; it’s just way more general. Try it out:

    The bowling ball images don’t move, but look how easy it is to add them to the renderer:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var generalB2BodyArray:Array = new Array();
    	generalB2BodyArray = generalB2BodyArray.concat(tennisBallArray, crateArray, bowlingBallArray);
    	var generalImages:Array = new Array();
    	generalImages = generalImages.concat(tennisBallImages, crateImages, bowlingBallImages);
    
    	var generalImage:Sprite;
    	for each (var generalBody:b2Body in generalB2BodyArray)
    	{
    		generalImage = generalImages[generalB2BodyArray.indexOf(generalBody)];
    		generalImage.x = (generalBody.GetPosition().x * mToPx);
    		generalImage.y = (generalBody.GetPosition().y * mToPx);
    		generalImage.rotation = generalBody.GetAngle() * radToDeg;
    	}
    }
    

    That’s all it takes! Check it out:

    It’s beginning to run a little slowly on my machine, so I’m going to reduce the number of objects from 60 to 30:

    
    
    for (var i:int = 0; i < 10; i++)
    {
    	createTennisBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBowlingBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    There’s more room for them now, too:


    Step 5: Creating Basketballs

    Basketballs, next. My image is 75x75px and called Basketball.png:

    As usual, start by embedding the image as a class:

    
    
    [Embed(source='../lib/Basketball.png')]
    public var Basketball:Class;
    

    Now we’ll add the two arrays for the basketball b2Body objects and Sprites. Except… wait. Why do we need a separate array for these?

    We don’t, actually! Not any more. Let’s combine all our b2Body objects into one array, and all our Sprites into another. Change this:

    
    
    public var crateArray:Array;
    public var crateImages:Array;
    public var tennisBallArray:Array;
    public var tennisBallImages:Array;
    public var bowlingBallArray:Array;
    public var bowlingBallImages:Array;
    

    …to this:

    
    
    public var generalB2BodyArray:Array;
    public var generalImages:Array;
    

    Change this:

    
    
    wheelArray = new Array();
    wheelImages = new Array();
    crateArray = new Array();
    crateImages = new Array();
    tennisBallArray = new Array();
    tennisBallImages = new Array();
    bowlingBallArray = new Array();
    bowlingBallImages = new Array();
    

    …to this:

    
    
    generalB2BodyArray = new Array();
    generalImages = new Array();
    

    In every create«Whatever» function, change the equivalent of this:

    
    
    tennisBallArray.push(tennisBallBody);
    

    …to this:

    
    
    generalB2BodyArray.push(tennisBallBody);	//or .push(crateBody), or whatever
    

    …and this:

    
    
    tennisBallImages.push(tennisBallSprite);
    

    …to this:

    
    
    generalImages.push(tennisBallSprite);	//or .push(crateSprite), or whatever
    

    We can make onClickWheelImage() applicable to all types of objects very easily now; just change this one line:

    
    
    private function onClickWheelImage(event:MouseEvent):void
    {
    	var spriteThatWasClicked:Sprite = event.target as Sprite;
    	var relatedBody:b2Body = wheelArray[wheelImages.indexOf(spriteThatWasClicked)];
    	var centerX:Number = spriteThatWasClicked.x + (spriteThatWasClicked.width / 2);
    	var centerY:Number = spriteThatWasClicked.y + (spriteThatWasClicked.height / 2);
    	var xDistance:Number = centerX - event.stageX;
    	var yDistance:Number = centerY - event.stageY;
    	var xImpulse:Number = 60 * xDistance * pxToM;	//I picked 60 simply because
    	var yImpulse:Number = 60 * yDistance * pxToM;	//it "felt right" to me
    	relatedBody.ApplyImpulse(
    		new b2Vec2(xImpulse, yImpulse),
    		relatedBody.GetPosition()
    	);
    }
    

    …like so:

    
    
    private function onClickWheelImage(event:MouseEvent):void
    {
    	var spriteThatWasClicked:Sprite = event.target as Sprite;
    	var relatedBody:b2Body = generalB2BodyArray[generalImages.indexOf(spriteThatWasClicked)];
    	var centerX:Number = spriteThatWasClicked.x + (spriteThatWasClicked.width / 2);
    	var centerY:Number = spriteThatWasClicked.y + (spriteThatWasClicked.height / 2);
    	var xDistance:Number = centerX - event.stageX;
    	var yDistance:Number = centerY - event.stageY;
    	var xImpulse:Number = 60 * xDistance * pxToM;	//I picked 60 simply because
    	var yImpulse:Number = 60 * yDistance * pxToM;	//it "felt right" to me
    	relatedBody.ApplyImpulse(
    		new b2Vec2(xImpulse, yImpulse),
    		relatedBody.GetPosition()
    	);
    }
    

    Finally, in onTick(), we can delete the lines highlighted below:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var generalB2BodyArray:Array = new Array();
    	generalB2BodyArray = generalB2BodyArray.concat(tennisBallArray, crateArray, bowlingBallArray);
    	var generalImages:Array = new Array();
    	generalImages = generalImages.concat(tennisBallImages, crateImages, bowlingBallImages);
    
    	var generalImage:Sprite;
    	for each (var generalBody:b2Body in generalB2BodyArray)
    	{
    		generalImage = generalImages[generalB2BodyArray.indexOf(generalBody)];
    		generalImage.x = (generalBody.GetPosition().x * mToPx);
    		generalImage.y = (generalBody.GetPosition().y * mToPx);
    		generalImage.rotation = generalBody.GetAngle() * radToDeg;
    	}
    }
    

    Compile your SWF to make sure it works:

    If it doesn’t, it’s probably due to a missed array somewhere; just check your error messages and try again.

    That took a while, but it makes it much simpler to add new objects. We’re gradually streamlining the whole process.

    There’s another simplification we can make to these arrays, though…


    Step 6: Linking Images to b2Body Objects

    Why do we have the generalImages[] array? It’s simply so that we can link a b2Body to its associated image, and vice-versa. But there’s a better way to do this.

    Every b2Body has an internal “user data” object – this can be set to any object you like, and can be retrieved from anywhere. We can set this to point to the b2Body object’s Sprite.

    It’s simple to do; in each create«Whatever»() function, alter the equivalent of this line:

    
    
    generalImages.push(tennisBallSprite);
    

    …to the equivalent of this:

    
    
    tennisBallBody.SetUserData(tennisBallSprite);
    

    Then, in onTick(), instead of finding the image from an array, we can find it using the user data:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var generalImage:Sprite;
    	for each (var generalBody:b2Body in generalB2BodyArray)
    	{
    		generalImage = generalBody.GetUserData() as Sprite;
    		generalImage.x = (generalBody.GetPosition().x * mToPx);
    		generalImage.y = (generalBody.GetPosition().y * mToPx);
    		generalImage.rotation = generalBody.GetAngle() * radToDeg;
    	}
    }
    

    (If you wanted to, you could replace the user data with a sprite sheet and use blitting to render the objects here. It’s quite simple to do so, with this structure.)

    You could actually remove the generalImages[] array altogether now… apart from one thing: it’s still used in onClickWheelImage() to get a reference from the image to the b2Body.

    We could just comment onClickWheelImage() out, because we’re not using it right now, but that would be lazy. And this raises a good point, anyway: we need to be able to find any image’s associated b2Body. Unfortunately, we’re using the Sprite class, and it doesn’t have a built-in “user data” – but we could give it one.

    Create a new class, called B2Sprite, extending Sprite, in your \src\ folder:

    
    
    package
    {
    	import flash.display.Sprite;
    
    	public class B2Sprite extends Sprite
    	{
    
    		public function B2Sprite()
    		{
    
    		}
    
    	}
    
    }
    

    (I’ve used a capital B to distinguish it from the official Box2D classes.)

    Create a b2Body property:

    
    
    package
    {
    	import Box2D.Dynamics.b2Body;
    	import flash.display.Sprite;
    
    	public class B2Sprite extends Sprite
    	{
    		public var body:b2Body;
    
    		public function B2Sprite()
    		{
    
    		}
    
    	}
    
    }
    

    Because this extends Sprite, it’ll act exactly the same as a Sprite, except with that extra property that we need.

    Now, in every create«Whatever»() function, change the equivalent of this code:

    
    
    var tennisBallSprite:Sprite = new Sprite();
    

    …to this:

    
    
    var tennisBallSprite:B2Sprite = new B2Sprite();
    

    Also, wherever you have the equivalent of this line:

    
    
    tennisBallBody.SetUserData(tennisBallSprite);
    

    …add another line underneath it, to create a connection from the B2Sprite to the b2Body:

    
    
    tennisBallBody.SetUserData(tennisBallSprite);
    tennisBallSprite.body = tennisBallBody;
    

    Then, you can alter onClickWheelImage(), like so:

    
    
    private function onClickWheelImage(event:MouseEvent):void
    {
    	if (event.target is B2Sprite)
    	{
    		var spriteThatWasClicked:B2Sprite = event.target as B2Sprite;
    		var relatedBody:b2Body =  spriteThatWasClicked.body;
    		var centerX:Number = spriteThatWasClicked.x + (spriteThatWasClicked.width / 2);
    		var centerY:Number = spriteThatWasClicked.y + (spriteThatWasClicked.height / 2);
    		var xDistance:Number = centerX - event.stageX;
    		var yDistance:Number = centerY - event.stageY;
    		var xImpulse:Number = 60 * xDistance * pxToM;	//I picked 60 simply because
    		var yImpulse:Number = 60 * yDistance * pxToM;	//it "felt right" to me
    		relatedBody.ApplyImpulse(
    			new b2Vec2(xImpulse, yImpulse),
    			relatedBody.GetPosition()
    		);
    	}
    }
    

    Now that you’ve done all of that, you can uncomment out the lines that add event listeners for onClickWheelImage() (in the tennis ball and bowling ball creation functions), and try out your SWF:

    Click a tennis ball or bowling ball to see the effect.

    Rename the onClickWheelImage() function to onClickClickableImage(). If you like, you could try making the crates clickable, too!


    Step 7: Creating Basketballs (Still)

    Hey, weren’t we adding basketballs? Let’s get back to that.

    So, we’ve removed the image array, which means we were about to write the createBasketball() function. But, wait… I can’t help but wonder whether we need the generalB2BodyArray[].

    It turns out that we don’t. The b2world contains a list of all b2Body objects inside it, so the array is unnecessary. We’ll just make a quick change – I promise – and then we can add the basketball.

    This list is not an array. It works like this:

    1. You request world.GetBodyList(), and this gives you the first b2Body object in the list.
    2. With this body, you call .GetNext() to retrieve the next b2Body object in the list.
    3. If .GetNext() returns null, you’ve reached the end of the list.

    Have a go at re-writing the onTick() rendering code to use this list instead of the generalB2BodyArray[]. Here’s my solution if you want to check:

    
    
    private function onTick(a_event:TimerEvent):void
    {
    	world.Step(0.025, 10, 10);
    	world.DrawDebugData();
    
    	var currentBody:b2Body = world.GetBodyList();
    	var currentImage:B2Sprite;
    	while (currentBody != null)
    	{
    		if (currentBody.GetUserData() is B2Sprite)	//important, since the boundaries don't have associated images
    		{
    			currentImage = currentBody.GetUserData() as B2Sprite;
    			currentImage.x = (currentBody.GetPosition().x * mToPx);
    			currentImage.y = (currentBody.GetPosition().y * mToPx);
    			currentImage.rotation = currentBody.GetAngle() * radToDeg;
    		}
    		currentBody = currentBody.GetNext();
    	}
    }
    

    (I’ve taken the opportunity to add some additional checks and change the name of some variables; you don’t have to do this, but it’s probably easier if you do, to keep our code consistent.)

    You can now remove all references to generalB2BodyArray[]. Make sure you test your SWF to check it still runs fine:

    Creating that basketball is now pretty simple. First, write createBasketball():

    
    
    private function createBasketball(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var basketballBodyDef:b2BodyDef = new b2BodyDef();
    	basketballBodyDef.type = b2Body.b2_dynamicBody;
    	basketballBodyDef.position.Set(pxStartX * pxToM, pxStartY * pxToM);
    	var basketballBody:b2Body = world.CreateBody(basketballBodyDef);
    	var circleShape:b2CircleShape = new b2CircleShape(75 * .5 * pxToM);
    	var basketballFixtureDef:b2FixtureDef = new b2FixtureDef();
    	basketballFixtureDef.shape = circleShape;
    	basketballFixtureDef.restitution = 0.6;	//fairly bouncy
    	basketballFixtureDef.friction = 0.4;	//a little rough
    	basketballFixtureDef.density = 2.5;	//pretty light
    	var basketballFixture:b2Fixture = basketballBody.CreateFixture(basketballFixtureDef);
    
    	var startingVelocity:b2Vec2 = new b2Vec2(mVelocityX, mVelocityY);
    	basketballBody.SetLinearVelocity(startingVelocity);
    
    	var basketballImage:Bitmap = new Basketball();
    	var basketballSprite:B2Sprite = new B2Sprite();
    	basketballSprite.addChild(basketballImage);
    	basketballImage.x -= basketballImage.width / 2;
    	basketballImage.y -= basketballImage.height / 2;
    	basketballSprite.x = pxStartX;
    	basketballSprite.y = pxStartY;
    	basketballBody.SetUserData(basketballSprite);
    	this.addChild(basketballSprite);
    	basketballSprite.body = basketballBody;
    	basketballSprite.addEventListener(MouseEvent.CLICK, onClickClickableImage);
    }
    

    …then, create a whole bunch of them:

    
    
    for (var i:int = 0; i < 10; i++)
    {
    	createTennisBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBowlingBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBasketball(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    Done! Try it:

    He shoots, he scores.


    Step 8: Making Object Construction Easier

    Every time we write a new create«Whatever»() function, we copy and paste an old one. They’re almost identical. And, as you’ve seen, that usually means we can improve our code structure to prevent us from having to copy and paste the same lines over and over again; it means there’s a better way to do things, which will make it easier for us to create new objects in the future.

    Look at this:

    
    
    private function createTennisBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var tennisBallBodyDef:b2BodyDef = new b2BodyDef();
    	tennisBallBodyDef.type = b2Body.b2_dynamicBody;
    	tennisBallBodyDef.position.Set(pxStartX * pxToM, pxStartY * pxToM);
    	var tennisBallBody:b2Body = world.CreateBody(tennisBallBodyDef);
    	var circleShape:b2CircleShape = new b2CircleShape(35 * .5 * pxToM);
    	var tennisBallFixtureDef:b2FixtureDef = new b2FixtureDef();
    	tennisBallFixtureDef.shape = circleShape;
    	tennisBallFixtureDef.restitution = 0.8;
    	tennisBallFixtureDef.friction = 0.75;
    	tennisBallFixtureDef.density = 1.0;
    	var tennisBallFixture:b2Fixture = tennisBallBody.CreateFixture(tennisBallFixtureDef);
    
    	var startingVelocity:b2Vec2 = new b2Vec2(mVelocityX, mVelocityY);
    	tennisBallBody.SetLinearVelocity(startingVelocity);
    
    	var tennisBallImage:Bitmap = new TennisBall();
    	var tennisBallSprite:B2Sprite = new B2Sprite();
    	tennisBallSprite.addChild(tennisBallImage);
    	tennisBallImage.x -= tennisBallImage.width / 2;
    	tennisBallImage.y -= tennisBallImage.height / 2;
    	tennisBallSprite.x = pxStartX;
    	tennisBallSprite.y = pxStartY;
    	tennisBallBody.SetUserData(tennisBallSprite);
    	tennisBallSprite.body = tennisBallBody;
    	this.addChild(tennisBallSprite);
    	tennisBallSprite.addEventListener(MouseEvent.CLICK, onClickClickableImage);
    }
    

    I’ve been using it as the template for all my b2Body creation functions. Here’s how they all boil down:

    
    
    private function create«Whatever»(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	//create body def and set its starting position
    	//create body
    	//create shape and set its type and size
    	//create fixture def and set its properties
    	//create fixture
    	//set object's starting velocity
    	//create instance of image and add it to stage at correct position
    	//link image to body (and vice-versa)
    	//add required event listener to image
    }
    

    For our round objects, some of these steps are identical, and most of them only differ by a couple of parameters or instance names. So, what if we could inherit all that identical code from some general createRoundObject() function?

    We can’t do exactly that, but we can do something similar. Create a new folder in \src\ called \builders\, and create a new class inside that called RoundObjectBuilder.as:

    
    
    package builders
    {
    
    	public class RoundObjectBuilder
    	{
    
    		public function RoundObjectBuilder()
    		{
    
    		}
    
    	}
    
    }
    

    This is going to take a b2world and create a b2Body, so add appropriate code for that:

    
    
    package builders
    {
    	import Box2D.Dynamics.b2Body;
    	import Box2D.Dynamics.b2World;
    
    	public class RoundObjectBuilder
    	{
    		public var body:b2Body;
    		protected var world:b2World, pxToM:Number;
    
    		public function RoundObjectBuilder(world:b2World, pxToM:Number)
    		{
    			this.world = world; 		//sets this.world to parameter called world
    			this.pxToM = pxToM;
    		}
    
    	}
    
    }
    

    It’s going to create a round object, so we’ll give it a function to create such a shape:

    
    
    package builders
    {
    	import Box2D.Collision.Shapes.b2Shape;
    	import Box2D.Collision.Shapes.b2CircleShape;
    	import Box2D.Dynamics.b2Body;
    	import Box2D.Dynamics.b2World;
    
    	public class RoundObjectBuilder
    	{
    		public var body:b2Body;
    		protected var world:b2World, pxToM:Number;
    		protected var shape:b2Shape;
    
    		public function RoundObjectBuilder(world:b2World, pxToM:Number)
    		{
    			this.world = world;
    			this.pxToM = pxToM;
    		}
    
    		public function createShape():void
    		{
    			shape = new b2CircleShape(mRadius);
    		}
    	}
    
    }
    

    (Where’s the radius? You’ll see…)

    It’s going to create a fixture def, so create a function for that, too:

    
    
    package builders
    {
    	import Box2D.Collision.Shapes.b2Shape;
    	import Box2D.Collision.Shapes.b2CircleShape;
    	import Box2D.Dynamics.b2Body;
    	import Box2D.Dynamics.b2FixtureDef;
    	import Box2D.Dynamics.b2World;
    
    	public class RoundObjectBuilder
    	{
    		public var body:b2Body;
    		protected var world:b2World, pxToM:Number;
    		protected var shape:b2CircleShape;
    		protected var fixtureDef:b2FixtureDef;
    
    		public function RoundObjectBuilder(world:b2World, pxToM:Number)
    		{
    			this.world = world;
    			this.pxToM = pxToM;
    		}
    
    		public function createShape():void
    		{
    			shape = new b2CircleShape(mRadius);
    		}
    
    		public function createFixtureDef():void
    		{
    			fixtureDef = new b2FixtureDef();
    			fixtureDef.shape = shape;
    			fixtureDef.restitution = restitution;
    			fixtureDef.friction = friction;
    			fixtureDef.density = density;
    		}
    	}
    
    }
    

    (Where do we define the properties? Again, you’ll see…)

    It’s going to create a body def, too:

    
    
    package builders
    {
    	import Box2D.Collision.Shapes.b2Shape;
    	import Box2D.Collision.Shapes.b2CircleShape;
    	import Box2D.Dynamics.b2Body;
    	import Box2D.Dynamics.b2BodyDef;
    	import Box2D.Dynamics.b2FixtureDef;
    	import Box2D.Dynamics.b2World;
    
    	public class RoundObjectBuilder
    	{
    		public var body:b2Body;
    		protected var world:b2World, pxToM:Number;
    		protected var shape:b2CircleShape;
    		protected var fixtureDef:b2FixtureDef;
    		protected var bodyDef:b2BodyDef;
    
    		public function RoundObjectBuilder(world:b2World, pxToM:Number)
    		{
    			this.world = world;
    			this.pxToM = pxToM;
    		}
    
    		public function createShape():void
    		{
    			shape = new b2CircleShape(mRadius);
    		}
    
    		public function createFixtureDef():void
    		{
    			fixtureDef = new b2FixtureDef();
    			fixtureDef.shape = shape;
    			fixtureDef.restitution = restitution;
    			fixtureDef.friction = friction;
    			fixtureDef.density = density;
    		}
    
    		public function createBodyDef(mStartX:Number, mStartY:Number):void
    		{
    			bodyDef = new b2BodyDef();
    			bodyDef.type = b2Body.b2_dynamicBody;
    			bodyDef.position.Set(mStartX, mStartY);
    		}
    	}
    
    }
    

    It’s going to create an actual body and fixture, and set the body’s initial velocity:

    
    
    package builders
    {
    	import Box2D.Collision.Shapes.b2Shape;
    	import Box2D.Collision.Shapes.b2CircleShape;
    	import Box2D.Common.Math.b2Vec2;
    	import Box2D.Dynamics.b2Body;
    	import Box2D.Dynamics.b2BodyDef;
    	import Box2D.Dynamics.b2Fixture;
    	import Box2D.Dynamics.b2FixtureDef;
    	import Box2D.Dynamics.b2World;
    
    	public class RoundObjectBuilder
    	{
    		public var body:b2Body;
    		protected var world:b2World, pxToM:Number;
    		protected var shape:b2CircleShape;
    		protected var fixtureDef:b2FixtureDef;
    		protected var bodyDef:b2BodyDef;
    		protected var fixture:b2Fixture;
    		protected var startingVelocity:b2Vec2;
    
    		public function RoundObjectBuilder(world:b2World, pxToM:Number)
    		{
    			this.world = world;
    			this.pxToM = pxToM;
    		}
    
    		public function createShape():void
    		{
    			shape = new b2CircleShape(mRadius);
    		}
    
    		public function createFixtureDef():void
    		{
    			fixtureDef = new b2FixtureDef();
    			fixtureDef.shape = shape;
    			fixtureDef.restitution = restitution;
    			fixtureDef.friction = friction;
    			fixtureDef.density = density;
    		}
    
    		public function createBodyDef(mStartX:Number, mStartY:Number):void
    		{
    			bodyDef = new b2BodyDef();
    			bodyDef.type = b2Body.b2_dynamicBody;
    			bodyDef.position.Set(mStartX, mStartY);
    		}
    
    		public function createBody():void
    		{
    			body = world.CreateBody(bodyDef);
    		}
    
    		public function createFixture():void
    		{
    			fixture = body.CreateFixture(fixtureDef);
    		}
    
    		public function setStartingVelocity(mVelocityX:Number, mVelocityY:Number):void
    		{
    			startingVelocity = new b2Vec2(mVelocityX, mVelocityY);
    			body.SetLinearVelocity(startingVelocity);
    		}
    	}
    
    }
    

    Next, we add the image:

    
    
    package builders
    {
    	import Box2D.Collision.Shapes.b2Shape;
    	import Box2D.Collision.Shapes.b2CircleShape;
    	import Box2D.Common.Math.b2Vec2;
    	import Box2D.Dynamics.b2Body;
    	import Box2D.Dynamics.b2BodyDef;
    	import Box2D.Dynamics.b2Fixture;
    	import Box2D.Dynamics.b2FixtureDef;
    	import Box2D.Dynamics.b2World;
    	import flash.display.Bitmap;
    
    	public class RoundObjectBuilder
    	{
    		public var body:b2Body;
    		protected var world:b2World, pxToM:Number;
    		protected var shape:b2CircleShape;
    		protected var fixtureDef:b2FixtureDef;
    		protected var bodyDef:b2BodyDef;
    		protected var fixture:b2Fixture;
    		protected var startingVelocity:b2Vec2;
    		protected var sprite:B2Sprite;
    
    		public function RoundObjectBuilder(world:b2World, pxToM:Number)
    		{
    			this.world = world;
    			this.pxToM = pxToM;
    		}
    
    		public function createShape():void
    		{
    			shape = new b2CircleShape(mRadius);
    		}
    
    		public function createFixtureDef():void
    		{
    			fixtureDef = new b2FixtureDef();
    			fixtureDef.shape = shape;
    			fixtureDef.restitution = restitution;
    			fixtureDef.friction = friction;
    			fixtureDef.density = density;
    		}
    
    		public function createBodyDef(mStartX:Number, mStartY:Number):void
    		{
    			bodyDef = new b2BodyDef();
    			bodyDef.type = b2Body.b2_dynamicBody;
    			bodyDef.position.Set(mStartX, mStartY);
    		}
    
    		public function createBody():void
    		{
    			body = world.CreateBody(bodyDef);
    		}
    
    		public function createFixture():void
    		{
    			fixture = body.CreateFixture(fixtureDef);
    		}
    
    		public function setStartingVelocity(mVelocityX:Number, mVelocityY:Number):void
    		{
    			startingVelocity = new b2Vec2(mVelocityX, mVelocityY);
    			body.SetLinearVelocity(startingVelocity);
    		}
    
    		public function setImage():void
    		{
    			sprite = new B2Sprite();
    			var bitmap:Bitmap = new Image();
    			sprite.addChild();
    			bitmap.x -= bitmap.width / 2;
    			bitmap.y -= bitmap.height / 2;
    			body.SetUserData(sprite);
    			sprite.body = body;
    		}
    
    		public function linkImageAndBody():void
    		{
    			body.SetUserData(sprite);
    			sprite.body = body;
    		}
    	}
    
    }
    

    Do you see where we’re going with this? You might have guessed that we’ll eventually create an instance of RoundObjectBuilder and then call createShape(), createFixtureDef(), and so on, all in the right order, with the right parameters, then retrieve the b2Body object after everything’s set up. That’s correct, but there is a little more to it than that.


    Step 9: Creating a Specific Builder

    First, create protected variables to hold all the properties that are missing:

    
    
    public var body:b2Body;
    protected var world:b2World, pxToM:Number;
    protected var shape:b2CircleShape;
    protected var fixtureDef:b2FixtureDef;
    protected var bodyDef:b2BodyDef;
    protected var fixture:b2Fixture;
    protected var startingVelocity:b2Vec2;
    protected var sprite:B2Sprite;
    protected var mRadius:Number;
    protected var restitution:Number, friction:Number, density:Number;
    protected var Image:Class;
    

    Now, create a new class, in your \builders\ folder, called TennisBallBuilder.as, and make sure it extends RoundObjectBuilder:

    
    
    package builders
    {
    	import Box2D.Dynamics.b2World;
    
    	public class TennisBallBuilder extends RoundObjectBuilder
    	{
    
    		public function TennisBallBuilder(world:b2World, pxToM:Number)
    		{
    			super(world, pxToM);
    		}
    
    	}
    
    }
    

    (Remember, super() will run the code in the constructor function of RoundObjectBuilder, because we extended it.)

    Now, underneath that call to super(), set the restitution, friction, and density of the tennis ball:

    
    
    package builders
    {
    	import Box2D.Dynamics.b2World;
    
    	public class TennisBallBuilder extends RoundObjectBuilder
    	{
    
    		public function TennisBallBuilder(world:b2World, pxToM:Number)
    		{
    			super(world, pxToM);
    			restitution = 0.8;
    			friction = 0.75;
    			density = 1.0;
    		}
    
    	}
    
    }
    

    Next, embed the tennis ball image, and use it to set the Image class which will be used to create the bitmap; also, set the radius:

    
    
    package builders
    {
    	import Box2D.Dynamics.b2World;
    
    	public class TennisBallBuilder extends RoundObjectBuilder
    	{
    		[Embed(source='../../lib/TennisBall.png')]
    		public var TennisBall:Class;
    
    		public function TennisBallBuilder(world:b2World, pxToM:Number)
    		{
    			super(world, pxToM);
    			restitution = 0.8;
    			friction = 0.75;
    			density = 1.0;
    
    			Image = TennisBall;
    			mRadius = 35 * 0.5 * pxToM;
    		}
    
    	}
    
    }
    

    So now we have a class that encapsulates all of the information and all the functions needed to create a tennis ball. We’ve just got to put it all together. Modify Main.createTennisBall() like so:

    
    
    private function createTennisBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var tennisBallBuilder:TennisBallBuilder = new TennisBallBuilder(world, pxToM);
    	tennisBallBuilder.createShape();
    	tennisBallBuilder.createFixtureDef();
    	tennisBallBuilder.createBodyDef(pxStartX * pxToM, pxStartY * pxToM);
    	tennisBallBuilder.createBody();
    	tennisBallBuilder.createFixture();
    	tennisBallBuilder.setStartingVelocity(mVelocityX, mVelocityY);
    	tennisBallBuilder.setImage();
    	tennisBallBuilder.linkImageAndBody();
    
    	var tennisBallSprite:B2Sprite = tennisBallBuilder.body.GetUserData() as B2Sprite;
    	tennisBallSprite.x = pxStartX;
    	tennisBallSprite.y = pxStartY;
    	this.addChild(tennisBallSprite);
    	tennisBallSprite.addEventListener(MouseEvent.CLICK, onClickClickableImage);
    }
    

    If you test your SWF, you’ll see that this still works:

    But so what? We haven’t gained much here. In fact, we’ve ended up with more code than we started with, and it still requires copying and pasting.

    Time for one more improvement. Create a new class, in \builders\, called RoundObjectDirector.as:

    
    
    package builders
    {
    
    	public class RoundObjectDirector
    	{
    
    		public function RoundObjectDirector()
    		{
    
    		}
    
    	}
    
    }
    

    Here’s how this will work:

    1. We’ll tell the RoundObjectDirector to use a specific RoundObjectBuilder.
    2. We’ll tell the RoundObjectDirector to create a new round object.
    3. The RoundObjectDirector will do so, using the RoundObjectBuilder that we specified, and will return said object.

    Here’s the code:

    
    
    package builders
    {
    	import Box2D.Dynamics.b2Body;
    
    	public class RoundObjectDirector
    	{
    		protected var roundObjectBuilder:RoundObjectBuilder;
    
    		public function RoundObjectDirector()
    		{
    
    		}
    
    		public function setRoundObjectBuilder(builder:RoundObjectBuilder):void
    		{
    			this.roundObjectBuilder	= builder;
    		}
    
    		public function createRoundObject(mStartX:Number, mStartY:Number, mVelocityX:Number, mVelocityY:Number):b2Body
    		{
    			roundObjectBuilder.createShape();
    			roundObjectBuilder.createFixtureDef();
    			roundObjectBuilder.createBodyDef(mStartX, mStartY);
    			roundObjectBuilder.createBody();
    			roundObjectBuilder.createFixture();
    			roundObjectBuilder.setStartingVelocity(mVelocityX, mVelocityY);
    			roundObjectBuilder.setImage();
    			roundObjectBuilder.linkImageAndBody();
    			return roundObjectBuilder.body;
    		}
    
    	}
    
    }
    

    See how most of the code in createRoundObject() is taken from our Main.createNewTennisBall() function? All you have to do is replace “tennisBall” with “roundObject” in each case. (Well, okay, I’ve also changed all measurements to be in meters rather than pixels, since we’re not dealing with any images here.)

    Now we can modify Main.createNewTennisBall() like so:

    
    
    private function createTennisBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var tennisBallBuilder:TennisBallBuilder = new TennisBallBuilder(world, pxToM);
    	var roundObjectDirector:RoundObjectDirector = new RoundObjectDirector();
    	roundObjectDirector.setRoundObjectBuilder(tennisBallBuilder);
    	var tennisBallBody:b2Body = roundObjectDirector.createRoundObject(pxStartX * pxToM, pxStartY * pxToM, mVelocityX, mVelocityY);
    
    	var tennisBallSprite:B2Sprite = tennisBallBody.GetUserData() as B2Sprite;
    	tennisBallSprite.x = pxStartX;
    	tennisBallSprite.y = pxStartY;
    	this.addChild(tennisBallSprite);
    	tennisBallSprite.addEventListener(MouseEvent.CLICK, onClickClickableImage);
    }
    

    (Note that I’ve converted the starting positions to pixels here, before passing them to the Director.)


    Step 10: Creating Rubber Balls

    Let’s create a brand new type of object, and see how much faster it is. We’ll use a super-bouncy rubber ball:

    Mine is 15x15px and called RubberBall.png.

    First step: create a new class, extending RoundObjectBuilder, to create the rubber ball:

    
    
    package builders
    {
    	import Box2D.Dynamics.b2World;
    
    	public class RubberBallBuilder extends RoundObjectBuilder
    	{
    		[Embed(source='../../lib/RubberBall.png')]
    		public var RubberBall:Class;
    
    		public function RubberBallBuilder(world:b2World, pxToM:Number)
    		{
    			super(world, pxToM);
    			restitution = 1.0;
    			friction = 0.0;
    			density = 5.0;
    
    			Image = RubberBall;
    			mRadius = 15 * 0.5 * pxToM;
    		}
    
    	}
    
    }
    

    Second step: create Main.createRubberBall():

    
    
    private function createRubberBall(pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	var rubberBallBuilder:RubberBallBuilder = new RubberBallBuilder(world, pxToM);
    	var roundObjectDirector:RoundObjectDirector = new RoundObjectDirector();
    	roundObjectDirector.setRoundObjectBuilder(rubberBallBuilder);
    	var rubberBallBody:b2Body = roundObjectDirector.createRoundObject(pxStartX * pxToM, pxStartY * pxToM, mVelocityX, mVelocityY);
    
    	var rubberBallSprite:B2Sprite = rubberBallBody.GetUserData() as B2Sprite;
    	rubberBallSprite.x = pxStartX;
    	rubberBallSprite.y = pxStartY;
    	this.addChild(rubberBallSprite);
    	rubberBallSprite.addEventListener(MouseEvent.CLICK, onClickClickableImage);
    }
    

    Third step: create the actual objects:

    
    
    for (var i:int = 0; i < 10; i++)
    {
    	createTennisBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBowlingBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBasketball(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createRubberBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    That’s it. Easy.


    Step 11: Getting Even More General

    I can’t help myself. I have to make one more simplification.

    Did you notice that Main.createRubberBall() and Main.createTennisBall() are almost identical? The only things that differ are the type of RoundObjectBuilder and the variable names.

    Let’s combine them into a single function: Main.createRoundObject():

    
    
    private function createRoundObject(roundObjectBuilder:RoundObjectBuilder, pxStartX:Number, pxStartY:Number, mVelocityX:Number, mVelocityY:Number):void
    {
    	roundObjectDirector.setRoundObjectBuilder(roundObjectBuilder);
    	var body:b2Body = roundObjectDirector.createRoundObject(pxStartX * pxToM, pxStartY * pxToM, mVelocityX, mVelocityY);
    
    	var sprite:B2Sprite = body.GetUserData() as B2Sprite;
    	sprite.x = pxStartX;
    	sprite.y = pxStartY;
    	this.addChild(sprite);
    	sprite.addEventListener(MouseEvent.CLICK, onClickClickableImage);
    }
    

    I’ve also made roundObjectDirector a protected variable, belonging to Main, so that we don’t have to keep creating a new one:

    
    
    protected var roundObjectDirector:RoundObjectDirector = new RoundObjectDirector();
    

    Delete the createTennisBall() and createRubberBall() functions.

    Now we can alter the code that creates objects, from this:

    
    
    for (var i:int = 0; i < 10; i++)
    {
    	createTennisBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBowlingBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createBasketball(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createRubberBall(
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	);
    	createCrate(
    		Math.random() * 1.5,
    		Math.random() * (stage.stageWidth - 20) + 10,
    		Math.random() * (stage.stageHeight - 20) + 10,
    		(Math.random() * 100) - 50,
    		0
    	)
    }
    

    …to this:

    
    
    var tennisBallBuilder:TennisBallBuilder = new TennisBallBuilder(world, pxToM);
    var rubberBallBuilder:RubberBallBuilder = new RubberBallBuilder(world, pxToM);
    for (var i:int = 0
  3. Kah Shiu Chong says:
    October 20, 2011 at 2:10 am
    This entry is part 3 of 3 in the series Kinematics

    Premium members, rejoice! It’s time for another Activetuts+ Premium tutorial. This time, you’ll learn how to use forward kinematics to create a robotic arm – in this case, the example is for an excavator, but you can use the techniques you’ll learn in all sorts of situations. It follows on nicely from our previous tutorials on linear kinematics and inverse kinematics. Read on to see what you’ll learn…

    Forward Kinematics (FK) is a positioning algorithm. It’s not as complicated as it sounds if you associate it to sequence of actions from an excavator operator’s point of view. Beginning with the node closest to it, the operator configures the orientation of each node in the hope that the scoop will reach the location intended. Often, several attempts are made before achieving success. FK is an algorithm to perform such task.

    In this tutorial, we shall attempt the implementation of FK and apply it onto an excavator from a 2D side view. Having understood this algorithm, one can easily adapt it to a 3D environment. Enjoy!


    Preview

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

    Press the space key to scroll through nodes (the current one is marked by a red bracket). While you are at it, press the arrow keys to change the angle.

    This tutorial covers the following:

    • Explanation for FK’s Mathematical background.
    • Hard-coded implementation of the FK.
    • Object-oriented class to implement FK algorithm.
    • Demonstration of FK class used in a project.
    • Graphics (as seen above) applied to the demonstration.

    Active Premium Membership

    Activetuts+ Premium Membership

    We run a Premium membership system which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium, Photo Premium, and the new Mobile Premium too. If you’re a Premium member, you can log in and download the tutorial. If you’re not a member, you can of course join today!

    Also, don’t forget to follow @envatoactive on twitter and grab the Activetuts+ RSS Feed to stay up to date with the latest tutorials and articles.


  4. Ian Yates says:
    October 20, 2011 at 2:37 am

    Twice a month, we revisit some of our best posts from throughout the history of Activetuts+. This week’s retro-Active post as originally posted on the 8th of November, 2010; since then we’ve seen Microsoft announce that Windows 8 will support HTML5 for native apps, Adobe move further and further into the mobile area, and the release of HTML5 multimedia tools such as Edge. Things are certainly different – how have the experts’ predictions held up?

    The subject of Flash, HTML5, Silverlight, RIAs and all that surrounds them continues to be debated across the net. It’s a sensitive issue as we’ve discovered; our recent roundup post certainly opened a can of worms and touched a raw nerve with a few folk!

    Today, we’re going to put that behind us and approach the discussion in a more sensible fashion. Read on to see what some of the most respected members of our community have to say on the matter.


    The Contributors

    A huge thanks to everyone who gave up their time in contributing to this article. We’ve collected commentary from Authors, Designers, Developers, UI & UX Architects, Evangelists and Community Experts from all sides of the fence. Here they are, in no particular order.

    Jump to any Section of this page quickly by following a link below:

    • Alan Klement Powerflasher Developer
    • Keith Peters Flash/ActionScript Developer, Author & Speaker
    • Bruce Lawson Web Evangelist for Opera
    • Jonathan Campos Director of Software Development at Dedo Inc. & Adobe Community Professional
    • Stray Flash & AIR Programmer
    • Tom Green Flash Educationalist & Author
    • Romin Irani Software Developer
    • Joseph Labrecque Senior Multimedia Application Developer & Adobe Education Leader
    • Rich Clark User Interaction Designer & Creator of html5doctor.com
    • Jack Doyle Founder of GreenSock Tweening Platform
    • Rich Tretola Adobe Community Expert, Author & Speaker
    • Paul Neave Interaction Designer
    • Rob Larsen Interface Architect, Isobar
    • Kevin Suttle Flash Platform User Experience Developer
    • Mike Taulty Microsoft UK
    • Steve Fulton 8bitrocket.com
    • Remy Sharp All Round Supporter of Make Believe Animals
    • James Whittaker UI/UX Architect TweetDeck Inc. & Adobe Community Professional

    Megaphone Icon by silenceplease available on GraphicRiver.


    Alan Klement
    Powerflasher Developer

    We are expected to be innovators and that means pushing ourselves outside of our comfort zones from time to time.

    Lately, it seems cooler heads are slowly prevailing when it comes to the “HTML5 vs Flash” debate. The consensus is shifting toward choosing “the right tool for the right job” and that is how it should be for everyone. We’re all craftsmen and professionals – not tool-smiths and laborers. Perhaps the most fun, and most intimidating, part of our job as creators is to be willing to explore new and better ways of engaging those who enjoy what we create. Does a painter use only one brush or a dentist use only a drill?

    We are expected to be innovators and that means pushing ourselves outside of our comfort zones from time to time. The question to ask yourself is, ‘Am I choosing the best tool that fits the project’s needs?

    Alan Klement
    web: http://blog.alanklement.com
    twitter: @alanklement


    Keith Peters
    Flash/ActionScript Developer, Author & Speaker

    You fear what you don’t understand. The more you learn, the less you fear.

    I think the whole argument of technology X vs. technology Y is stupid and childish and anyone who gets all defensive about their technology – or offensive about some other technology – is mainly showing off their own lack of confidence or certainty in their own future. I know Flash very well. I can do Flex. I can code up just about anything on the iPhone. I’ve dabbled in Android. I’m currently learning Silverlight and XNA for Windows Phone 7 development. You fear what you don’t understand. The more you learn, the less you fear.

    HTML and JavaScript can currently do many things that you really needed Flash for years ago. That will only grow. I think the ideal of being able to do more things without relying on third party plugins is a good thing. But we are a long way from getting rid of them altogether. That said, I’d hate to have to do all my coding in JavaScript as it currently stands. While AS3 has a lot of room for improvement, it has grown a lot in the last decade. Coding in JS is like going back to AS1. If JavaScript looked more like AS3, I’d be a lot more interested in diving into HTML5.

    Keith Peters
    web: http://www.bit-101.com
    twitter: @bit101


    Bruce Lawson
    Web Evangelist for Opera

    A professional developer evaluates the client, the task and the audience and chooses the tool accordingly.

    The big misconception is that it’s either HTML5 or Flash/Silverlight. Flash in particular is part of the Web’s ecosystem, and we’ll need to be able to render Flash content for ever. It would be a tragedy if future generations were not able to enjoy the Kenya song.

    HTML5 even legalises the <embed> tag so adding plugin content to HTML5 pages can be done without making the page invalid.

    Some HTML5 technologies can replace some uses of Flash: scripted graphics can be achieved using <canvas> for example, and interacting with videos through script is (arguably) easier to achieve using HTML5. It’s important, though, that we now have a choice; previously, for video or animations you were pretty much limited to plugins; now there is an open standards choice as well.

    Some things can’t be as easily achieved in HTML5 as they can using plugins. AS I alluded to in my Five things that carrots can do that HTML5 can’t video, the choice of technology should be based on what you’re trying to achieve. A professional developer evaluates the client, the task and the audience and chooses the tool accordingly.

    Bruce Lawson
    blog: http://www.brucelawson.co.uk
    buy my book: http://introducinghtml5.com
    twitter: @brucel


    Jonathan Campos
    Director of Software Development at Dedo Inc. & Adobe Community Professional

    Neither HTML5 nor Flash is without flaw.

    As a previous Javascript application developer and current Flash application developer I have followed the arguments about HTML5 with a passing interest and little more. HTML5 will carve out room on the RIA landscape, but as with every piece of technology, HTML5 has it’s strengths and it’s weaknesses. A switch to HTML5 doesn’t ensure you will be free of bugs, performance issues, or testing. It just means you will be checking for bugs, optimizing performance, and testing on a different base language and with different tool sets. Neither HTML5 nor Flash is without flaw.

    As a Javascript developer turned Flash developer, I can say from my own experience that you can do almost everything you could do in Flash in Javascript. However, it takes longer, is more difficult, and requires more testing on multiple browsers and environments.

    Working with the Flash Player on large scale multitouch devices and multiscreen development, I can tell you that there are things we do now that HTML5 just can’t do yet. As such, we will continue to watch HTML5 grow but for us we are happy with the capabilities provided to us through the Flash Player and Adobe AIR.

    Jonathan Campos
    work: http://www.dedoinc.com
    blog: http://www.unitedmindset.com/jonbcampos
    twitter: @jonbcampos


    Stray
    Flash & AIR Programmer

    Deciding the technology your users might want to use your site/app in is only the first step.

    In the short term, I see HTML5 taking on Flash in creating over-designed ego-driven micro-sites. The clients we’ve been turning down on these projects for a couple of years don’t even bother us Flash devs anymore. They’re ruining the lives of HTML5 devs instead! Thanks Steve – we owe you for that one.

    My little company mostly builds big Air apps – tuition and instruction for the engineering industry. These types of applications leverage the full power of flash development: a grown-up set of technologies and tools, and the incredible flexibility of the Flash timeline. This is Flash’s strength over HTML5 – audio, video, text, multilayer animation, interaction and the application they’re sitting in all playing together.

    The other strength flash has is a mature tool set and some great frameworks and libraries. Increasingly generous open-source development is lifting the game of whole chunks of the community. A lot of us are really good at what we do and getting better every day.

    Deciding the technology your users might want to use your site/app in is only the first step. Building real software is hard. And it’s different from building websites. The number of pathways through a really rich application or game is mind-blowing. Not blowing-our-own-minds building this stuff is what flash devs have become good at. We’ve learned through making a lot of mistakes – HTML5 devs haven’t had that opportunity yet.

    I predict a lot of high-profile HTML5 project fails – anyone remember boo.com?

    Stray
    web: http://flair-flash-flex-air.blogspot.com
    twitter: @stray_and_ruby


    Tom Green
    Flash Educationalist & Author

    I truly see the browser as a doomed technology.

    The jury is still out on whether HTML is a Flash-killer. Over the years, I have seen too many of these “emergent technologies” touted as the “App_Name_Goes_Here- killer” to get myself worked up about it.

    I found it rather fascinating, though, to see a demo of an app during the “Sneaks” at Max this year that essentially recompiled a swf into an HTML5 file. Again, there is a lot of “perception” between demo and release (Macromedia/Adobe’s Fixation on on Flash Lite for Mobile a few years back, for example) to get myself too worked up. The implications of this sort of thing, though, are rather interesting.

    The ability to cross-compile a swf to an HTML5 file gets Flash onto Apple’s devices without a lot of extra work and essentially gets Flash/Air/Flex projects driven by the Flash Player on to practically every device on the planet. Even then I truly see the “browser” as a doomed technology. We are undergoing a fundamental shift away from browser-based presentations to apps that don’t necessarily need to be delivered through an ethernet cable or viewed on a PC or laptop to be experienced.

    The challenge around this multiscreen “environment” that just popped up is aimed more at designers than the codies. The codies quite rightfully claim they can “Write-Once/Deploy Everywhere” which is true because it is code and data. The danger in that is though it is true, it is also wrong. As I pointed out during a RIM Focus Group at Max when I asked this question: “Do you really think the app on your Blackberry Torch is going to look equally stunning on the 60″ inch Samsung monitor over there, my MacBook Pro, your Dell PC laptop and that guy’s Motorola?” What I was getting at is the real issue is a design issue because designers will have to play close attention to the Presentation layer than simply whipping something up in Flex. Think about it for a minute. Apps look great when they are on a screen roughly the size of a business card but you simply can’t expect that content to scale up in orders of magnitude without sacrificing quality or something else. I find it rather interesting that no one has started talking about this issue and I can pretty well guarantee it will come up later rather than sooner.

    Tom Green
    web: http://www.tomontheweb.ca
    twitter: @TomGreen


    Romin Irani
    Software Developer

    HTML5 lowers my barrier to start creating powerful browser applications today

    I think the biggest misconception is to think in terms of “Flash is going to die” or “HTML5 is not going to succeed” and so on. Given the way the world works, neither of them are going to be clear winners or losers. Every developer knows that to create a compelling application to reach out to as wide an audience as possible, you need to cater to both sides. For e.g. you cannot assume that HTML5 will be present on all browsers, similarly you cannot assume that Flash will be present everywhere. You have to design for a fallback mechanism and that I believe is ingrained.

    Flash is powerful. The graphics capabilities, the Charting support and its current reach is excellent. Where I think it stands out and will stay its ground today is not in features but two things:

    1. Plenty of excellent developer tools, IDEs that are available
    2. The huge developer ecosystem.

    Both of these are well entrenched. HTML5 is still evolving, once it is finalized can one expect more tools.

    In summary, HTML5 lowers my barrier to start creating powerful browser applications today. HTML, CSS and JS are all I need to get started. I am particularly excited by the set of Javascript APIs that come along with HTML5 i.e. Geolocation, Offline support, Storage, etc that allow me to address key architectural aspects in my application to make my browser apps more powerful. The other area I am waiting for wider acceptance is Web Sockets, that could be a game changer for a lot of gaming applications.

    Romin Irani
    blog: http://iromin.wordpress.com
    check out: http://www.oreillynet.com
    twitter: @iRomin


    Joseph Labrecque
    Senior Multimedia Application Developer & Adobe Education Leader

    Why would anyone expect HTML, as a specification, to stand still?

    Ever since the inception of this debate, I’ve held the position that the majority of dialogue around “HTML vs. Flash” is an intentional misrepresentation of facts and usage. There is no better example of this than Steve Jobs’ counterfactual letter, “Thoughts on Flash”; a message clearly designed to provide ignorant media outlets and technology zealots with cleverly crafted soundbytes used to encourage a position against Flash as a viable platform on the web and on devices.

    HTML5 is the natural progression of the HTML specification. As such, it poses no threat to the Flash Platform because HTML and Flash have always existed as complimentary technologies. Why would anyone expect HTML, as a specification, to stand still? In my opinion, it has done so for far too long and is overdue an abundance of rich, new features. Does this in any way harm Flash as a platform? Of course not; Flash advances at a much faster rate than HTML, unrestrained by standards bodies and bickering between opposing corporations. The addition of capabilities with HTML only augments embedded Flash in the browser, as these new capabilities (geolocation data, for example) can be fed into a Flash interface through local connection or via initialization variables.

    I actually find it humorous that the fate of Flash is called into question at this time of great advances. Flash Player 10.1 took a long time to emerge since a massive rewrite was required to allow a good experience across desktops, mobile devices, and eventually the digital living room. Now that this foundation has been set, we are seeing some startling growth across numerous areas of platform implementation. The beginnings of which can be seen in the upcoming 3D “Molehill” APIs, the super-performant StageVideo classes, the first glimpses of multi-threading, and upcoming 64-bit runtimes across Windows, Linux, and Mac OS. This doesn’t even consider advances in the AIR runtime and associated frameworks.

    It’s a great time to be a Flash developer – and a great time for HTML too!

    Joseph Labrecque
    blog: http://inflagrantedelicto.memoryspiral.com
    twitter: @JosephLabrecque


    Rich Clark
    User Interaction Designer & Creator of html5doctor.com

    ..it’s likely proprietary solutions will always be somewhat ahead of the curve when compared to open standards..

    Both Adobe & Microsoft seem to be working towards embracing HTML5. Just look at IE9, it’s come on leaps and bounds from previous versions of the browser. If Adobe can get on board and develop a decent IDE for working with <canvas> and SVG then they’ll be onto a winner as well.

    There’s maybe not been a shift [in disciplines where Flash is used] but there likely will be a shift in the not too distant future. I don’t think that there’s much doubt that Flash will continue to push the boundaries of what’s possible online. Companies like Adobe can afford innovate, improve and release new products more rapidly in comparison to an organisation like the W3C who have to work with implementers, authors and users while still maintaining backwards compatibility. That’s why it’s likely proprietary solutions will always be somewhat ahead of the curve when compared to open standards – it’s the nature of the beast.

    Video & Audio are the main areas that HTML5 will start to outgrow Flash I imagine. In fact, some would have you believe that a large percentage of HTML5 _compatible_ video already exists.

    Probably the biggest misconception is defining HTML5. It seems to be whatever you want it to be – that annoys me. Especially when people lump together CSS3, Web Fonts, SVG, etc all into HTML5. It would be preferable for people to use the phrase ‘Open Standards’ or similar but we’re probably too far down the line for that now. When you see daily newspapers using the term ‘HTML5′ you know it ain’t gonna happen ;)

    [I'm looking forward to] the fact that the web will move away from the need for proprietary plugins (and associated software) that are replaced by Open Standards that anyone with a text editor can work with.

    Rich Clark
    web: http://richclarkdesign.com
    twitter: @rich_clark


    Jack Doyle
    Founder of GreenSock Tweening Platform

    ..despite the hype around HTML5, Flash is doing great.

    The HTML5 vs. Flash topic has become far too divisive. HTML5 is an evolving standard that promises some exciting capabilities, but it is most definitely not a Flash killer. HTML and Flash have always coexisted but I believe that 3 things are primarily responsible for the recent crusade against Flash: Apple’s refusal to support it in iOS, HTML5’s proposed <Video> tag, and CSS3’s animation capabilities. I’ve addressed each one in the full article on my site (cut here for brevity).

    True craftsmen use different tools for different tasks. Developers are no different. Consider the objectives of each project and choose the appropriate technology. Don’t avoid Flash just because Steve Jobs insulted it or because it’s the trendy thing to do. And don’t use Flash just because it is what you’re comfortable with. I have seen plenty of sites which have been built 100% in Flash for no apparent reason. That’s absurd. Likewise, some developers burn through insane amounts of hours trying to accomplish something with HTML/CSS/JavaScript, making lots of compromises just to avoid Flash. Use Flash if it does the job better (and the reality is that Flash is far superior to HTML/CSS/JavaScript for certain tasks). Otherwise, stick with HTML/CSS/JavaScript which are more search engine friendly and accessible. HTML5 is another great tool for our toolbox, but it certainly doesn’t supplant Flash altogether.

    For the Flash developers out there, the sky isn’t falling. In fact, despite the hype around HTML5, Flash is doing great. Better than ever. I firmly believe that it will continue to be a major player in web and mobile development. Adobe has got some great stuff up their sleeve too, so stay tuned.

    For more thoughts check out Flash vs. HTML5: Faux Drama on my site.

    Jack Doyle
    web: http://blog.greensock.com
    twitter: @tweenlite


    Rich Tretola
    Adobe Community Expert, Author & Speaker

    The biggest misconception is that you can use HTML5 to do anything that can be done with Adobe Flash. At this point, this is not even close to true.

    The rise of HTML5 is an exciting one as it will continue the transformation of the web to a much more rich and interactive experience. Although there is a perception that Adobe and Microsoft both have technologies that compete with HTML5, in my opinion Flash and Silverlight should be used to compliment and not compete with HTML5.

    There’s certainly been a shift in disciplines where Flash is used; Apple’s decision not to include the Flash player on iOS (iPhone, iPad) has led to many companies reconsidering the use of Flash for creating content that can also be created with HTML. This decision is a simple one based on cost of development; by going with HTML5 over Flash, a single application can be created to target all major platforms.

    Before Adobe MAX 2010, I would have argued that HTML5 is ideal for building rich web applications where Adobe Flex currently resides as a tool of choice for many developers. However, after seeing the Adobe sneak peeks and what Adobe has been able to accomplish in the conversion of Flash animation to traditional assets, CSS, and JavaScript it appears the sky is the limit for what can be transitioned to HTML5.

    Since the Flash player will continue to evolve at a much faster pace than HTML5 (which has taken years and is still in progress), it will always offer more options for developers. I also believe that Apple will eventually agree to allow the Flash player on its iOS which will reverse the trend I mentioned earlier.

    Eventually though, Flash and HTML5 will redefine their space in web development with each being used for what it does best. I look forward to the merging of these technologies into a collaborative development space which will ultimately continue to make the user experience a more interactive one.

    Rich Tretola
    web: http://blog.everythingflex.com
    check out: http://twittapolls.com
    twitter: @richtretola


    Paul Neave
    Interaction Designer

    It’s not about the tools or the platform, it’s about the idea.

    There’s no such battle as Flash vs HTML. It’s Flash and HTML. Flash is just one of the many tools in the toolbox, and like any tool it needs to be used in the right way for the right job. And it’s the role of the developer to decide which tool is appropriate.

    The thing I love about Flash most is its cross-platform nature. But its major problem is that it’s a plug-in. It’s a closed off black box and not a native part of the web, despite what Adobe says when it refers to the “full web”. Flash is an augmentation; an extension to add features originally missing from HTML. There was a technological land grab and Flash got there first. But HTML/CSS/JavaScript is encroaching on Flash’s territory fast and within a year we’ll have a web that can do pretty much everything Flash can, if not more. Even 3D is coming to the web soon with WebGL. The only major thing lacking will be device support for webcams and microphones, but that’s on the roadmap.

    So why on earth would anyone write code for a plug-in when the browser can handle it all natively? You could argue that Adobe’s tooling is better. But more often than not, this is when Flash developers get emotional and call JavaScript a “toy language”, and HTML/CSS a cesspool of hacks and incompatibility. But that isn’t true, and it certainly isn’t going to help.

    The Flash work I do these days is mostly device specific rather than generic. Perhaps Flash is becoming less cross-platform and more niche. We now have more devices, browsers and operating systems to deal with than ever before. The good news is that Flash is not going to go away. Flash may become more niche, but it’s relevance will simply shift, not shrink.

    To Flash developers I say: remember why you’re doing this. It’s not about the tools or the platform, it’s about the idea. Never stop creating, and never stop learning!

    Paul Neave
    web: http://www.neave.com
    twitter: @neave


    Rob Larsen
    Interface Architect, Isobar

    [I'm] excited by how far HTML5 has come over the past couple of years

    Personally, I come at this from two angles. There’s the part of me that wants to expand the use of web standards wherever possible and wants to put those technologies to use early and often. That guy is excited by how far HTML5 has come over the past couple of years, with hundreds of developers working long hours to fill in the implementation gaps, allowing us to use some of the most exciting technologies, like Canvas, today. I’m working on a project right now that utilizes a Canvas charting component. That would have been Flash just a couple of years ago. That’s exciting.

    There’s another part of me, the pragmatist, that realizes there’s a limit to what we SHOULD be doing with HTML5 right now, at least in a production environment and a limit to what we will be able to do in the future. I’m responsible to clients, co-workers and users to get the best site or application out the door as efficiently as possible. From that perspective, Flash is a powerful, mature option that I’d be silly to ignore.

    Rob Larsen
    web: http://htmlcssjavascript.com
    twitter: @robreact


    Kevin Suttle
    Flash Platform User Experience Developer

    We’re all working together towards the same goal: the best possible content experiences for our users.

    When I first started in this industry, the tech tabloids hadn’t yet skewed it with terms like “technology wars” and other poorly-researched sensationalism. We just saw the web as a single, wide-open medium, and you know what? It still is.

    HTML5/CSS3 is beginning to extend the web experience for many desktop and mobile browsers. The Flash Platform continues daily to push the limits of desktop applications, mobile devices, tablets, television, and hardware that doesn’t really fit in any one category. As both developers and users, we need to ignore the hype, use the right tool for the job, and remember that we’re all working together towards the same goal: the best possible content experiences for our users.

    Kevin Suttle
    web: http://kevinsuttle.com
    twitter: @kevinSuttle


    Mike Taulty
    Microsoft UK

    The reality is that Silverlight occupies a strong position even in a future world where every user has an HTML5 capable browser.

    It’s common to see “HTML5″ browsers and RIA frameworks like Silverlight presented as an “either/or” choice with the success of one necessitating the hasty demise of the other. The reality is that Silverlight occupies a strong position even in a future world where every user has an “HTML5″ capable browser.

    Silverlight applications can run both in and outside of the browser and offer elevated trust options. The runtime remains cross-browser (IE6,IE7,IE8,IE9, Safari, Chrome, FireFox) and cross-platform (Windows7,Vista,XP,OS X) where it provides a consistent experience. Silverlight also provides a framework for building apps for the new Windows Phone 7 devices to get re-use of code and skills.

    Today, HTML based clients offer the greatest possibility of a client reaching across devices and platforms as HTML browsers are ubiquitous albeit with challenges around using a single set of markup in all browsers. Microsoft’s committed to web standards and is doing a tonne of work in IE9 around “HTML5″ to build a performant implementation in a clean, safe browser that does more to enable this idea of “one markup”.

    As that works gets released and IE9 and other “HTML5″ browsers become the default over time, then developers will be able to take this reach approach across those new HTML5 features like video, audio, canvas, offline storage and so on.

    However, there are still a rich set of capabilities that an “HTML5″ browser doesn’t have which show up in a framework like Silverlight and those sit in 3 main areas of premium media experiences, casual gaming and business applications. Applications need those kinds of capabilities even in an “HTML5″ world and Silverlight will take that forward, innovating at pace.

    For more detailed information on the future of Silverlight – see this longer post from the Silverlight team.

    Mike Taulty
    blog: http://mtaulty.com
    twitter: @mtaulty


    Steve Fulton
    8bitrocket

    I’m looking forward to more great opportunities to make a good living from making cool stuff.

    Adobe needs to make tools to create HTML5 content, that’s just obvious. I’d like to see the Flash IDE export both .swfs and HTML5/JavaScipt/Canvas. Obviously you would have to make concessions for what the HTML5 Canvas can support, but for things like ad units and animations with click-through it should be a no-brainer. Adobe’s reaction though has been a bit defensive, which I think is a mistake. Microsoft is embracing HTML5 in IE 9, but I’m still not sure how much they really believe in it. They have many enterprise customers, and the concept of using Visual Studio to build both your front and backend of the web site is very compelling for them.

    From what I’ve seen, Adobe is taking Flash into the games market in a big way. There are things they showed at Max this year that would be extremely difficult to do in HTML5, and even if you could do them, they would only be supported by a very small subset of browsers. I would also look to Adobe focusing on Air as the delivery mechanism for content to multiple platforms.

    Saying that, I do think HTML5 will take some ground from Flash. For example, content that is consumable by mobile devices where developers currently use Flash to develop only because there is no better alternative. Ad units, simple (and I do mean simple) audio and video players, drop-down navigation, animated overlays, etc. Flash will retain its position in the Games market and Air applications, Flex based apps, e-learning, and applications where the content and code needs to be secure for monetization.

    Biggest misconceptions? Flash is dead. HTML5 sucks. Silverlight is lame. Hyperbole is the realm of the Steve Jobs in the world, developer’s don’t need it. We should think about how we can make use of any decent technology to solve problems.

    Steve Fulton
    web: http://www.8bitrocket.com
    twitter: @8bitrocket


    Remy Sharp
    All Round Supporter of Make Believe Animals

    Both Flash and HTML5 haters are going to be left behind, and frankly good riddance.

    Both Flash and HTML5 haters are going to be left behind, and frankly good riddance. Flash for a long time has been plugging the holes in browsers for us via custom fonts, drawing APIs, SVG support, sockets, video and much more. HTML5 and related specs, for the most part formalises those technologies so that we don’t have to rely on plugins to play a video – and seriously how many flash developers think “Flash” amounts to being able to play a video?

    The biggest misconception I run into is that HTML5 is this single silver bullet that will return the unicorns to the fields and the phoenix to the skies. It’s not. In fact the HTML5 specification is a collection of APIs (the HTML component aside), so it’s not the silver bullet, nor do we need browsers to support every single API before we start making use of just one of them, such as the canvas API, video or perhaps the history API. We should use the right technology for the job, and that’s still true if Flash is the right technology for the job.

    Remy Sharp
    web: http://remysharp.com
    buy my book: http://introducinghtml5.com
    twitter: @rem


    James Whittaker
    UI/UX Architect TweetDeck Inc. & Adobe Community Professional

    I’m hoping that as developers and designers we have learnt from all the bad things that were done in the early days of Flash.

    HTML5 and Flash. Both have really passionate communities surrounding them who actively promote and enjoy sharing code, techniques and solutions. The Flash Platform community is amazing and from personal experience many Flash and Flex dev’s are keen to get a more detailed understanding of HTML5 and JavaScript, they are always looking to learn new stuff, be challenged and see how it could fit into their workflow. Also, don’t forget that many people, including myself, love working with both technologies.

    At TweetDeck our flagship desktop application is built using Adobe Flex and deployed cross platform using Adobe AIR. Adobe AIR was the best and fastest way to build consistent cross platform apps that integrated with the OS using either Flash or HTML. Our application is one of the largest distributed AIR apps in existence and we have really pushed what the platform can do and been amazed with the results.

    We are also busy building an HTML5 version of TweetDeck for deployment as a web app using the Google Chrome Web Store. This will pack the same (if not more!) detailed feature set as the AIR client so it’s giving us a real sense of how these two technologies stack up against each other. For me, the new CSS3 animations and transitions have been really fun to try out.

    Flash has been around for a long time. From animations to tacky skip intro screens it is now a credible platform for building enterprise level apps for desktop and mobile. HTML5 is still very new, I’m hoping that as developers and designers we have learnt from all the bad things that were done in the early days of Flash and don’t repeat them in HTML5.

    Let’s stop arguing and get down to creating amazing experiences.

    James Whittaker
    blog: http://JamesWhittaker.com
    work: http://www.TweetDeck.com
    check out: http://RefreshingApps.com
    twitter: @jmwhittaker


    Your Turn

    You’ve heard it from the horses’ mouths, now let’s see how you feel about what they’ve had to say. We want to hear your comments! Let’s try and keep this discussion civil though..

    Remember, this roundup was originally posted in November, 2010. A lot can change in that time!


  5. Jaron Franklin Fort says:
    October 20, 2011 at 3:33 am

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

    You could use this to build a standard standard chat room app, with a page devoted to it, or you could run it alongside another piece of Flash content, like Kongregate does with its games.



    Final Result Preview

    Let’s take a look at the interface of the final result we will be working towards (this demo does not function as an actual chat client):

    Here’s a video demo that shows it in action:



    Step 1: Prerequisites

    This tutorial assumes that you have some experience with PHP. You must be have Wamp Server installed on your system and you should also be somewhat familiar with PhpMyAdmin. If you do not have WAMP you can download it here. You will also need to download the Openfire Jabber Server and the XIFF API library from the Ignite Realtime website. I will walk you through the Openfire installation process. Finally you will need the latest version of Java installed on your operating system and Flash CS4 or later. I will be using Flash CS5 Professional in this tutorial. If you do not have the latest version of Java, you can download the latest version here.



    Step 2: Setting Up Our Database

    Make sure that Wamp Server is running on your computer and navigate to http://localhost/phpmyadmin/ in your web browser.

    Create a new database called MyContentSite using PhpMyAdmin.

    create the main database

    Create a new table in the MyContentSite database called myMembers with eight fields.

    the mymembers table

    After the myMembers table has been sucessfully created by PhpMyAdmin, create the following fields:

    • uid
    • first_name
    • last_name
    • my_username
    • my_password
    • email
    • status_message
    • country

    Your screen should look as follows:

    members fields 1

    Let me break down each field. The uid field should be of type INT. You can change the field’s type from the Type column. Make this field the primary index and set this field to auto-increment itself. Do this by selecting the PRIMARY option underneath the INDEX column within this fields row. Then check the checkbox under the Auto-Increment column. This field represents the userID of the current member of our website. The first_name, last_name, my_username, my_password, email, and country fields should be have the datatype or VARCHAR and the Length/Value should be set to 255.

    Note: The my_password fields shown in the images hold an MD5 of the user’s password. You may choose to store passwords plain without any encryption but for this tutorial I will be using hashed passwords.

    members fields 2

    Finally, the status_message field should be of the of type MEDIUMTEXT.

    Once you have created the all of the fields click the save button.

    ssaved members fields

    Now we are ready to create two dummy accounts that we will use to login to our website and join chat rooms later in this tutorial. Click on the Insert tab. You will be presented with a form for creating a new row in the table.

    Leave the uid field empty because we want this field to automatically increment itself. Set the first_name to Jane and the last_name field to Doe. Set the my_username to janedoe with all lower cass letters. For the my_password field, we’ll be using the hashed value for our password which is tutsplus in all lower case letters. Type ca28ad0733a3dde9dc1f30e32718d209 into the my_password field. You can set the email field to an email address of your choosing and the status_message field to whatever you’d like. Set the country field to whatever country you’d like as well. When you are finished click on the save button . Repeat this process to create an account for a John Doe with the my_username field set to johndoe123 in all lower case letters. Use the same password as before.

    jane doe account
    john doe account
    saved accounts


    Step 2: Installing Openfire

    Once you have downloaded Openfire from the Ignite Realtime website, run the installation exe file (or dmg file if you are using a Mac).

    initializing installer

    Select your langauge.

    choose your language

    Click Next to continue.

    begin installation

    Accept the License Agreement.

    terms of use

    Choose a directory and click Next to continue.

    installation directory

    Select a Start Menu folder.

    start menu folder

    Click Next to begin the installation.

    extraction

    Once the installation has completed, click Finish to to run Openfire. The Openfire service will start automatically when the program is run. Click the Launch Admin button when Openfire has finished booting.

    installation complete
    Openfire starting up
    Openfire running

    Now we will set up Openfire. Select your preferred language and click Continue.

    choose language

    Leave the Admin Console Port field and Secure Admin Console Port field to their default values. For this tutorial leave the Domain field to it’s default value as well. You can change this later to your website’s domain. Click Continue.

    server settings

    Select the Standard Database Connection option and click Continue.

    database settings

    Under Database Driver Presets, choose MySQL. Type com.mysql.jdbc.Driver in the JDBC Driver Class field. Change [host-name] to localhost and change [database-name] to mycontentsite in the Database URL field. Set Username and Password to your MySQL database’s username and password. For this tutorial I used the default username for MySQL which is root and the Password field remains blank. Click Continue to move on.

    mysql setup 1
    mysql setup 2

    Leave the Profile Settings to Default. Click Continue to move on.

    profile settings

    Choose an email address for your Administrator Account and a password then continue.

    admin password

    We are now done the setup process. You may now login to the admin console. Use the default username admin and the password the you chose during setup.


    Step 3: Setting Up the Chat Rooms

    Our application allow users to communicate within chat rooms. But for this to happen our users must have chat rooms to join. Let’s create the chat rooms using the Openfire Admin Console. If you haven’t already, start Openfire Server. Log in the Openfire’s Admin Console. Navigate to the Group Chat Rooms page by clicking on the Group Chat tab.

    chat room home

    Click Create New Room on the left hand side of the screen. Fill out the details as you see them in the image below.

    new chat room

    When you are finished, click on the Save Changes button. If the room was created successfully, you should see a message and a Green check.

    room creation

    Follow the same steps to create two more chat rooms.

    another room
    last room
    all chat rooms

    Step 4: Integrating Openfire with MySQL

    In this tutorial, our make-believe website uses a MySQL database to store data about each user. Openfire can be integrated with an external database, a MySQL database in this case. First we must configure Openfire to do this.

    Open the openfire.xml file using Notepad or preferrably a rich text editor such as Notepad++ as I mentioned before. The file will be located in the Openfire/conf/ folder within the Program Files directory folder on your PC.

    
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!--
        This file stores bootstrap properties needed by Openfire.
        Property names must be in the format: "prop.name.is.blah=value"
        That will be stored as:
            <prop>
                <name>
                    <is>
                        <blah>value</blah>
                    </is>
                </name>
            </prop>
    
        Most properties are stored in the Openfire database. A
        property viewer and editor is included in the admin console.
    -->
    <!-- root element, all properties must be under this element -->
    <jive>
      <adminConsole>
        <!-- Disable either port by setting the value to -1 -->
        <port>9090</port>
        <securePort>9091</securePort>
      </adminConsole>
      <locale>en</locale>
      <!-- Network settings. By default, Openfire will bind to all network interfaces.
          Alternatively, you can specify a specific network interfaces that the server
          will listen on. For example, 127.0.0.1. This setting is generally only useful
           on multi-homed servers. -->
      <!--
        <network>
            <interface></interface>
        </network>
        -->
      <connectionProvider>
        <className>org.jivesoftware.database.EmbeddedConnectionProvider</className>
      </connectionProvider>
      <database>
        <defaultProvider>
          <driver>com.mysql.jdbc.Driver</driver>
          <serverURL>jdbc:mysql://localhost:3306/mycontentsite</serverURL>
          <username>root</username>
          <password/>
          <testSQL>select 1</testSQL>
          <testBeforeUse>true</testBeforeUse>
          <testAfterUse>true</testAfterUse>
          <minConnections>5</minConnections>
          <maxConnections>25</maxConnections>
          <connectionTimeout>1.0</connectionTimeout>
        </defaultProvider>
      </database>
      <setup>true</setup>
    </jive>
    

    This is what my openfire.xml file looks like. Your openfire.xml file should look similar to mine. Here is a link to the Openfire Custom Database Integration Guide on the Ignite Realtime website. You will noticed that you are instructed to make changes directly to the openfire.xml configuration file in this guide.

    Do not make any changes to this file unless it does not resemble mine.

    Note: It is very likely that your openfire.xml file will be using DefaultConnectionProvider. If it is, you may have trouble logging in to the Admin Console. Try to log in with the default first. If the password you specified during setup doesn’t work, use the default password to login. The default username is admin and the default password is admin as well.

    If you can’t log in, change DefaultConnectionProvider to EmbeddedConnectionProvider. Then restart Openfire and try to log in again. If you are still having trouble, run the setup to Openfire again. Change the setup tag’s value from false to true within the openfire.xml file. Then restart Openfire to run the setup again. Do this as a last resort – this shouldn’t be necessary.

    I have followed the steps on the Ignite Realtime website countless times only to find myself in a hole later on. One of the problems I faced was that users couldn’t connect to the server and when I tried to fix the problem in the admin console, I couldn’t log in. In fact the only thing I can conceive of that might be more frustrating than the problems that I faced was being stuck inside of a Saw trap.

    I don’t want you to go through what I had to so please follow the following steps carefully. Openfire has a brilliant way of editing and creating properties that I find to be a lot more efficient than having to edit an xml file on your system.

    Log into Openfire’s Admin Console. Click the System Properties link on the right hand side of the main page.

    system properties

    Your server’s System Properties page should look something like this.

    Important: If your System Properties page is missing some or all of the properties within the image below, you can add the properties in manually. When we modify a property in the tutorial, if you don’t have the property that we are modifying, just use the same steps that you would to modify a property to create the property instead. Otherwise, if you already have a property that we are creating, just modify the property with the values that I specify.

    Towards the bottom of the screen you will see a section with the title Add new property. It has two fields. The first field Property Name. The second field is Property Value. Within the Property Name field, type in jdbcProvider.driver and within the Property Value field, type com.mysql.jdbc.Driver into the field. Click on the Save Property button when you are finished. You will be following these steps to create more properties as well as to modify existing properties.

    jdbcProvider driver

    Create a property called jdbcProvider.connectionString with the value jdbc:mysql://localhost/mycontentsite?user=root&password=.

    jdbcProvider connection string

    Now we are going to make our first modification to an existing property. Click on the Edit link that correspondes to the provider.auth.className property. Change its value to org.jivesoftware.openfire.auth.JDBCAuthProvider using the Edit property table. Click the Save Property button when you are finished.

    provider auth classname

    Create a new property with the name jdbcAuthProvider.passwordSQL. Give it a value of SELECT my_password FROM mymembers WHERE my_username=?. This property’s value is the MySQL query string that will be used to authenticate a user.

    Note: Notice that it contains a question mark (?). The question mark will be replaced with the value inside the username field.

    jdbcAuthProvider passwordSQL

    Create a new property called jdbcAuthProvider.passwordType. Give it a value of md5.

    jdbcAuthProvider passwordType

    Note: The jdbcAuthProvider properties will be hidden if you have followed the steps correctly.

    property saved

    Create a new property called admin.authorizedUsernames. The value should be the jid of the usernames that you would like to be able to log into the Admin Console with.

    Note: Look at the image below. Notice that the Jane and John Doe’s jid’s are their usernames concatenated with an @ sign and the server’s XMPP domain.

    authorized usernames

    Modify the property provider.user.className by changing its value to org.jivesoftware.openfire.user.JDBCUserProvider.

    provider user className

    Create a new property called jdbcUserProvider.loadUserSQL with the value SELECT first_name,email FROM mymembers WHERE my_username=?.

    jdbcUserProvider loadUserSQL

    Create a new property called jdbcUserProvider.userCountSQL and give it the value SELECT COUNT(*) FROM mymembers.

    jdbcUserProvider userCountSQL

    Create a new property called jdbcUserProvider.allUsersSQL. Set the value to SELECT my_username FROM mymembers.

    jdbcUserProvider allUsersSQL

    Create a new property called jdbcUserProvider.searchSQL. Give it the value SELECT my_username FROM mymembers.

    jdbcUserProvider searchSQL

    Create a new property called usernameField. Set its value to my_username.

    username field

    Create a new property called nameField. Set its value to first_name.

    name field

    Create a new property called emailField. Set its value to email.

    email field

    Now that we have added and modified the properties needed we can log out of the Admin Console. Restart Openfire and attempt to log back into the Admin Console with an actual user.

    Access denied!

    Now try to log in with the username, admin.

    Access denied again! What’s going on here?

    Let’s take a look at the openfire.xml file. Yours should look the same as it did before. We need to add the modifications to the xml file. I have found that by making modifications in the Admin Console first, then changing the openfire.xml file after, is more consistent than just making changes to the xml. As I described before, I just couldn’t log in using a client or into the Admin Console after I had made these modifications.

    Change your openfire.xml file so that it looks like this.

    
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!--
        This file stores bootstrap properties needed by Openfire.
        Property names must be in the format: "prop.name.is.blah=value"
        That will be stored as:
            <prop>
                <name>
                    <is>
                        <blah>value</blah>
                    </is>
                </name>
            </prop>
    
        Most properties are stored in the Openfire database. A
        property viewer and editor is included in the admin console.
    -->
    <!-- root element, all properties must be under this element -->
    <jive>
      <adminConsole>
        <!-- Disable either port by setting the value to -1 -->
        <port>9090</port>
        <securePort>9091</securePort>
      </adminConsole>
      <locale>en</locale>
      <!-- Network settings. By default, Openfire will bind to all network interfaces.
          Alternatively, you can specify a specific network interfaces that the server
          will listen on. For example, 127.0.0.1. This setting is generally only useful
           on multi-homed servers. -->
      <!--
        <network>
            <interface></interface>
        </network>
        -->
      <connectionProvider>
        <className>org.jivesoftware.database.DefaultConnectionProvider</className>
      </connectionProvider>
      <database>
        <defaultProvider>
          <driver>com.mysql.jdbc.Driver</driver>
          <serverURL>jdbc:mysql://localhost:3306/mycontentsite?user=root&amp;password=</serverURL>
          <username>root</username>
          <password/>
          <testSQL>select 1</testSQL>
          <testBeforeUse>true</testBeforeUse>
          <testAfterUse>true</testAfterUse>
          <minConnections>5</minConnections>
          <maxConnections>25</maxConnections>
          <connectionTimeout>1.0</connectionTimeout>
        </defaultProvider>
      </database>
      <jdbcProvider>
        <driver>com.mysql.jdbc.Driver</driver>
        <connectionString>jdbc:mysql://localhost/mycontentsite?user=root&amp;password=</connectionString>
      </jdbcProvider>
      <provider>
        <auth>
          <className>org.jivesoftware.openfire.auth.JDBCAuthProvider</className>
        </auth>
        <user>
          <className>org.jivesoftware.openfire.user.JDBCUserProvider</className>
        </user>
      </provider>
      <jdbcAuthProvider>
        <passwordSQL>SELECT my_password FROM mymembers WHERE my_username=?</passwordSQL>
        <passwordType>md5</passwordType>
      </jdbcAuthProvider>
      <jdbcUserProvider>
        <loadUserSQL>SELECT first_name,email FROM mymembers WHERE my_username=?</loadUserSQL>
        <userCountSQL>SELECT COUNT(*) FROM mymembers</userCountSQL>
        <allUsersSQL>SELECT my_username FROM mymembers</allUsersSQL>
        <searchSQL>SELECT my_username FROM mymembers WHERE</searchSQL>
        <usernameField>my_username</usernameField>
        <nameField>first_name</nameField>
        <emailField>email</emailField>
      </jdbcUserProvider>
      <setup>true</setup>
      <admin>
    	<authorizedUsernames>janedoe, johndoe123</authorizedUsernames>
      </admin>
    </jive>
    

    Make sure to change you are using the DefaultConnectionProvider instead of the EmbeddedConnectionProvider then close Openfire and restart it. Attempt to log into the Admin Console as a member from your website’s database. I logged in as John Doe. If done correctly, you should be back in the Admin Console and the username should be in the top right hand corner of the home page.

    Note: Before moving on, make sure that all of the properties within the openfire.xml file are showing up on the System Properties of the Admin Console. If they aren’t you now know how to add them in manually.

    logged in

    Step 5: PHP

    We need to use PHP to grab data from a MySQL database and present the data to Flash. For those of you who are new to PHP I will briefly explain what each script accomplishes. Let’s start with the MySQLConnection class.

    The MySQLConnection class connects to and disconnects from a MySQL database.

    
    
    
    	class MySQLConnection {
    
    		private $db_host = "localhost"; // Your Websites domain
    		private $db_user = "root"; // Your databases username
    		private $db_pass = ""; // Your databases password
    		private $db_name = "mycontentsite"; // The name of your database
    		private $connected = 0;
    
    		public function connect() {
    
    			mysql_connect($this->db_host, $this->db_user, $this->db_pass) or die ( "Error: Script aborted. Could not connect to database." );
    			mysql_select_db($this->db_name) or die ( "Error: Script aborted. No database selected." );
    			$this->connected = 1;
    			session_start();
    		}
    
    		public function close() {
    
    			mysql_close();
    			$this->connected = 0;
    		}
    
    		public function get_connected() {
    
    			return $this->connected;
    		}
    	}
    

    The LoginManager class handles user logins. A user can be authenticated then logged in and out with this class.

    
    
    
    	require_once "MySQLConnection.php";
    
    	class LoginManager {
    
    		public function __construct() {
    
    		}
    
    		public function login( $username, $password ) {
    
    			$username = strip_tags( $username );
    
    			$username = stripslashes( $username );
    
    			$username = mysql_real_escape_string( $username );
    
    			$passHash = md5( $password ); // Applies MD5 encoded hash to the password
    
    			$connection = new MySQLConnection();
    			$connection->connect();
    
    			$sql = "SELECT * FROM mymembers WHERE my_username = '$username' AND my_password = '$passHash' LIMIT 1";
    			$query = mysql_query( $sql );
    
    			if ($query) {
    
    				$count = mysql_num_rows( $query );
    			}
    			else {
    
    				die ( mysql_error() );
    			}
    
    			if ( $count > 0 ) {
    
    				while ( $row = mysql_fetch_array( $query ) ) {
    
    					$_SESSION['username'] = $username;
    					$_SESSION['pw'] = $password;
    					$uid = $row['uid'];
    					session_name( $username . $uid );
    					setcookie( session_name(), '', time() + 42000, '/' );
    					$connection->close();
    					die ( "login=1" );
    				}
    
    				die ( "login=0&error=Invalid username or password" );
    
    			}
    			else {
    
    				$connection->close();
    				die ( "login=0&error=Invalid username or password" );
    			}
    		}
    
    		public function checkLogin() {
    
    			if ( isset ( $_SESSION['username'] ) && isset ( $_SESSION['pw'] ) ) {
    
    				$user = $_SESSION['username'];
    				$pw = $_SESSION['pw'];
    				die ( "login=1&username=$user&password=$pw" );
    			}
    			else {
    
    				die ( "login=0" );
    			}
    		}
    
    		public function logout() {
    
    			setcookie(session_name(), '', time() - 42000, '/');
    			if ( isset( $_SESSION['username'] ) ) unset( $_SESSION['username'] );
    			if ( isset( $_SESSION['pw'] ) ) unset( $_SESSION['pw'] );
    
    			//Destroy session
    			session_destroy();
    
    			//return result to Flash (swf)
    			die ("logout=1");
    		}
    	}
    

    We call upon login.php to log the user in and logout.php to log the user out using the LoginManager class. To check to see if a user is logged in we call the check_login.php script.

    
    
    
        // login.php
    
    	require_once "classes/LoginManager.php";
    
    	if (isset($_POST['username']) && $_POST['password']) {
    
    		login();
    	}
    
    	function login() {
    
    		$username = $_POST['username'];
    		$password = $_POST['password'];
    		unset($_POST['username']);
    		unset($_POST['password']);
    
    		$login = new LoginManager();
    		$login->login( $username, $password) ;
    	}
    
    
    
    
        // logout.php
    
    	require_once "classes/LoginManager.php";
    
    	$login = new LoginManager();
    	$login->logout();
    
    
    
    
        // check_login.php
    
    	require_once "classes/LoginManager.php";
    
    	session_start();
    
    	$login = new LoginManager();
    	$login->checkLogin();
    	exit();
    

    The final script that is called from ActionScript is the grab_user_data.php script that is used to select the user’s data from our MySQL database.

    
    
    
    	require_once "classes/MySQLConnection.php";
    
    	if ( isset( $_POST['username'] ) ) {
    
    		$connection = new MySQLConnection();
    		$connection->connect();
    		$username = $_POST['username'];
    		$sql = "SELECT * FROM mymembers WHERE my_username = '$username' LIMIT 1";
    		$query = mysql_query( $sql );
    
    		while ( $row = mysql_fetch_array( $query ) ) {
    
    			$uid = $row['uid'];
    			$xml = '<user id="' . $uid . '">' . "\n";
    			$xml .= "	<firstName>" . $row['first_name'] . "</firstName>\n";
    			$xml .= "	<lastName>" . $row['last_name'] . "</lastName>\n";
    			$xml .= "	<country>" . $row['country'] . "</country>\n";
    			$xml .= "	<statusMessage>" . $row['status_message'] . "</statusMessage>\n";
    			$xml .= "</user>\n";
    		}
    
    		echo $xml;
    		$connection->close();
    		exit();
    	}
    

    These PHP scripts serve a very important role in our application but are very basic.


    Step 6: Setting Up Flash

    Open up Flash Professional. Set the document class to ChatApp. Set the size of the stage to 550 x 400.

    setup_flash

    Note: I like to use a framerate of 30 FPS but our application doesn’t have any animation so you can use whatever framerate works best for you.


    Step 7: Build the Client’s User Interface

    From the Components panel, select and drag a Button component on to the stage. Position the button so that it sits in the top right corner of the stage. Set the instance name of the button to logoutBtn. Add another button in the bottom right of the stage and set its instance name to sendBtn.

    button component
    buttons on stage

    Add a List compenent to the stage. Position it directly beneath logoutBtn and resize the component so that it fits nicely between both buttons. Set its instance name to list.

    list on stage

    We’ll be using logoutBtn to logout of the user’s session and sendBtn to allow our users to send messages. The List will display all of the online users within the current chat room. When an item in the list is clicked, the user’s profile will be loaded.

    Now we need a component that will display incoming and outgoing chat messages as well as a textfield that our users can use to input new messages. Add a TextArea component to the stage. Resize and position it to take up most of the remainder of the stage, leaving room for an input textfield at the bottom that is the same height as sendBtn. Set the instance name to displayTxt.

    text area component
    text area on stage

    Finally we need to add a TextInput component to the stage. Position the component directly beneath displayTxt and to the left of sendBtn. Set the instance name to inputTxt.

    text input component

    Select all of the components on the stage. Convert the selection to a symbol. The symbol should be a MovieClip named UserInterface. Select the Export for ActionScript option. The Class field should read UserInterface. Set the instance name to our new symbol to ui. Finally name the current layer of the main timeline interface. This will help you organize your project better.

    all components on stage
    user interface symbol
    ui instance
    interface layer

    Step 8: The Login Screen

    Our chat application would be useless if user’s couldn’t log in to our application. Let’s build the login screen. Create a new layer on the Main Timeline. Name the layer login.

    login layer

    Using the Rectangle tool, draw a rectangle on the stage that is the same size as the stage. The rectangle’s stoke should be set to 0. The rectangle should not have a line and should be filled black with a tranparency of 50%.

    darkbox on stage
    color picker 1
    color picker 2

    Highlight the black rectangle and convert it to a new MovieClip symbol called DarkBox. We will use this object to darken the screen while the log in components are being displayed. Set the instance name of the DarkBox object to darkBox.

    darkbox symbol
    darkbox instance

    Add two InputText components, two Label components, and a Button component to the stage. Make sure you aren’t adding these objects on top of the interface layer. Position the components as they are in the image below with the username field first then the password field.

    Set the instance name of the first lable to userLabel and set the instance name of the second label to passLabel. Set the instance name for the first input text field to usernameTxt and set the instance name of the second input text field to passwordTxt. Set the instance name of the button to loginBtn.

    Use the Text tool to add a Dynamic TextField to the stage. Set the text size to 18 and make the text color Red. Set the instance name to errorTxt. Position errorTxt beneath loginBtn as seen below.

    login screen elements

    We are going to convert everything on the login layer to a single new MovieClip symbol named LoginScreen but before we can do this we need to lock everything on the interface layer so we do not accidently select an object of that layer. Lock the interface layer by selecting the Lock Layer button next to the layer. When the layer is locked you will see a symbol of a lock next to the layer.

    You may now safely select all of the objects on the login layer that we just created, and convert the selection to a symbol with a linkage of LoginScreen. Set the instance name to loginScreen.

    login screen component
    stage with elements

    Step 9: Creating the Profile Window

    Lock and hide all of the current layers on the Main Timeline. Create a new layer and call it profile info.

    Note: This is just a layer that we will use for development. You may delete this layer at the end of this step if you wish.

    profile info layer

    Using the Rectangle tool, draw a rectangle with the radius of each corner set to 10.00. The rectangle should have a fill identical to the DarkBox object (Black with a transpareny of 50%) and a fully opaque White line with a stroke value of 4.00. I set the color of the stage to a Burnt Orange in the image below so that you can see how everything should look more clearly.

    rounded rectangle

    Add a Dynamic Text to the stage directly on top of the rectangle. Position and resize the text field so that it takes up most of the rectangle’s area but leaves room for a button. Set the instance name of the text field to txt. Make sure that the text color is White and the size of the text is at least 18px.

    text field
    unfinished profile window
    an added button

    Add a new Button component on top of the rectangle and set the instance name to closeBtn.

    highlighted profile window

    Select all of the object’s on the profile info layer and convert them to a MovieClip symbol named ProfileWindow. Check the field Export for ActionScript so that this symbol has a linkage of ProfileWindow. Now remove the ProfileWindow object from the stage. We will be instantiating this object with code.

    profile window symbol

    Step 10: Our First ActionScript Code

    Create a new ActionScript file and name it ChatApp.as. Add the following lines of code to the class.

    
    
    package {
    
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.events.ErrorEvent;
    	import flash.display.StageScaleMode;
    	import flash.display.StageAlign;
    	import flash.events.TimerEvent;
    	import flash.utils.Timer;
    	import flash.system.Security;
    	import flash.external.ExternalInterface;
    	import org.igniterealtime.xiff.core.XMPPConnection;
    	import org.igniterealtime.xiff.events.ConnectionSuccessEvent;
    	import org.igniterealtime.xiff.events.LoginEvent;
    	import org.igniterealtime.xiff.events.DisconnectionEvent;
    	import org.igniterealtime.xiff.events.XIFFErrorEvent;
    	import org.igniterealtime.xiff.events.RoomEvent;
    	import org.igniterealtime.xiff.events.IncomingDataEvent;
    	import org.igniterealtime.xiff.events.OutgoingDataEvent;
    
    	public class ChatApp extends Sprite {
    
    		private static const SERVER:String = "tutorial-f5d57edaa";//= "[host name] // Your server's host name here
    		private static const PORT:Number = 5222; // Your servers public port here
    		private static const RESOURCE:String = "MyContentSite";//[resource name] // Resource name	ex.: ==> MyJabberApp
    		private static const DEFAULT_ROOM:String = "Main Lobby";
    
    		private var grabber:LoginCredentialsGrabber;
    		private var userData:UserDataGrabber;
    		private var connection:XMPPConnection;
    		private var requireLogin:Boolean;
    		private var roomName:String;
    
    		public function ChatApp() {
    
    			super();
    			if (stage) init()
    			else addEventListener(Event.ADDED_TO_STAGE, onAdded);
    		}
    
            private function init():void {
    
    			stage.align = StageAlign.TOP_LEFT;
    			stage.scaleMode = StageScaleMode.NO_SCALE;
    			loginScreen.visible = false;
    			loginScreen.userLabel.text = "username";
    			loginScreen.passLabel.text = "password";
    			ui.visible = false;
    
    			UserDataExtension.enable();
    			grabber = new LoginCredentialsGrabber();
    			userData = new UserDataGrabber();
    
    			var flashVars:Object = this.loaderInfo.parameters;
    
    			if ( flashVars.hasOwnProperty( "room" ) ) {
    
    				roomName = flashVars.room;
    			}
    
    			checkLogin();
    		 }
    
            private function onAdded( e:Event ):void {
    
    			removeEventListener(Event.ADDED_TO_STAGE, onAdded);
    			init();
    		}
    	}
    }
    

    Within the code above we check to see if the stage exists in the class constructor. If the stage does not exist, we listen for the ADDED_TO_STAGE event and the onAdded event handler method is called when the stage is available. The onAdded method simply stops listening for the ADDED_TO_STAGE event and calls the init method. If the stage exists we skip this first step and just call the init method which initialized our application.

    We initialize the stage and the loginScreen, and we make the UserInterface object (ui) invisible. You may notice the enable method from the UserDataExtension class being called. We will write this class later but for now just know that it is very important to remember to always call this method when instantiating the application. The enable method registers our custom extension(the class) with the ExtensionClassRegistry class in the XIFF library. We’ll talk more about this later.

    Instantiate a new instance of the LoginCredentialsGrabber class and assign it to the grabber variable. Also instantiate a new instance of the UserDataGrabber class and assign it to the userData variable. We will write these classes later also. When our SWF file is embeded in a web page we want our application to connect to a specific chat room that is related to the content on the page. Later we are going to pass the name of the chat room, that our app should connect to, into the flashVars parameter at embed time. But for now we’ll just first check to see if the variable exists and then we grab the value and assign it to the roomName variable. Finally we run the checkLogin method which is self-explanatory.


    Step 11: Checking Whether the User Is Logged In

    Write the checkLogin method in the Document Class( ChatApp ).

    
    
    private function checkLogin():void {
    
    	grabber.addEventListener( Event.COMPLETE, onLoginCredentials );
    	grabber.grab();
    }
    

    As you can see the method is very simple. This is because all of the functionality is encapsulated within the LoginCredentialsGrabber class. Listen for the COMPLETE event to be dispatched so that the onLoginCredentials event handler method can be called. Call the grab method on LoginCredentialsGrabber object. This methods checks to see whether the user is logged in – or, more specifically, it checks to see whether the user’s session exists.

    Next, we’ll write the onLoginCredentials method.

    (Note: We are still in the Document class.)

    
    
    private function onLoginCredentials( e:Event ):void {
    
    	grabber.removeEventListener( Event.COMPLETE, onLoginCredentials );
    
    	if ( grabber.isLoggedIn ) {
    
    		// Connect to Openfire
    		ui.visible = true;
    		connect( grabber.username, grabber.password );
    	}
    	else {
    
    		// Display login
    		displayLogin();
    	}
    }
    

    This method is also really simple. The LoginCredentialsGrabber checks to see if the user is logged in by grabbing the session cookies using PHP. PHP renders out data to the LoginCredentialsGrabber object and the data is parsed.

    Note: We will be writing the LoginCredentialsGrabber class next. All we need to do now is check to see if the user is logged in. If they are we display the user interface and call the connect method to connect to Openfire. We pass the user’s username and password into the connect method as required parameters. If the user is not logged in we display the Login Screen.


    Step 12: Grabbing Login Credentials

    Write the LoginCredentialsGrabber class.

    
    
    package {
    
    	import flash.events.Event;
    	import flash.events.EventDispatcher;
    	import flash.net.URLLoader;
    	import flash.net.URLRequest;
    	import flash.net.URLVariables;
    	import flash.net.URLRequestMethod;
    
    	public class LoginCredentialsGrabber extends EventDispatcher {
    
    		private static const PASSCODE:String = "letmein123";
    		private static const SOURCE:String = "http://localhost/mycontentsite/scripts/check_login.php&quot;;
    
    		private var _data:*;
    		private var _username:String;
    		private var _password:String;
    		private var _isLoggedIn:Boolean;
    
    		public function LoginCredentialsGrabber() {
    
    			super();
    		}
    
    		public function grab():void {
    
    			var loader:URLLoader = new URLLoader();
    			var req:URLRequest = new URLRequest( SOURCE + "?cb=" + new Date().time );
    
    			loader.addEventListener( Event.COMPLETE, onComplete );
    			loader.load( req );
    		}
    
    		private function onComplete( e:Event ):void {
    
    			e.target.removeEventListener( Event.COMPLETE, onComplete );
    			_data = e.target.data;
    			var results:URLVariables = new URLVariables( _data.toString() );
    
    			if ( results.login == "1" ) {
    
    				_isLoggedIn = true;
    				_username = results.username;
    				_password = results.password;
    			}
    			else {
    
    				_isLoggedIn = false;
    			}
    
    			dispatchEvent( new Event( Event.COMPLETE ) );
    		}
    
    		public function get data():* {
    
    			return _data;
    		}
    
    		public function get isLoggedIn():Boolean {
    
    			return _isLoggedIn;
    		}
    
    		public function get username():String {
    
    			return _username;
    		}
    
    		public function get password():String {
    
    			return _password;
    		}
    	}
    }
    

    We have two constants and four read-only properties before the constructor method. The SOURCE constant is a String that represents the location of the PHP script that checks to see if the user is logged in. We also store the passcode needed to execute the PHP script in a constant. When the grab method is called the URLLoader object loads the PHP script passing the passcode with the URLRequest and the script returns data back to flash. The data is a set of url variables that we can parse using the URLVariables class. If a user is logged in, the PHP script will give us the user’s username and password so that we can use this information to connect the user to Openfire. Finally we provide getter methods to grant read-only access to outside code.


    Step 13: Display the Login Screen

    Write the displayLogin method in the Document class(ChatApp.as).

    
    
    private function displayLogin():void {
    
    	// Displays the login screen
    	loginScreen.visible = true;
    	loginScreen.addEventListener( LoginManager.LOGIN, onLoggingIn );
    }
    

    We set the loginScreen‘s visible property to true and wait for the loginScreen to dispatch LOGIN event. Then the onLoggingIn method is called. Let’s write this method now.

    
    
    private function onLoggingIn( e:Event ):void {
    
    	ui.visible = true;
    	connect( loginScreen.manager.username, loginScreen.manager.password );
    }
    

    We make the user interface visible and then we call the connect method.

    Important: Notice that we are using the username and password from the loginScreen‘s manager object(loginScreen.manager) instead of the grabber object’s username and password as we did in the onLoginCredentials method.


    Step 14: Connecting to Openfire

    At last, we can write the connect method. The method accepts two required parameters: the first is the user’s username and the second is the users’s password.

    
    
    private function connect( username:String, password:String ):void {
    
    	connection = new XMPPConnection();
    	connection.username = username;
    	connection.password = password;
    	connection.server = SERVER;
    	connection.port = PORT;
    	connection.resource = RESOURCE;
    	connection.addEventListener( ConnectionSuccessEvent.CONNECT_SUCCESS, onConnected );
    	connection.addEventListener( LoginEvent.LOGIN, onLogin );
    	connection.addEventListener( DisconnectionEvent.DISCONNECT, onDisconnected );
    	connection.addEventListener( XIFFErrorEvent.XIFF_ERROR, onXiffError );
    	connection.addEventListener( IncomingDataEvent.INCOMING_DATA, onIncomingData );
    	connection.addEventListener( OutgoingDataEvent.OUTGOING_DATA, onOutgoingData );
    	connection.connect( XMPPConnection.STREAM_TYPE_FLASH );
    }
    

    Instantiate the XMPPConnection object and assign it to the connection variable. Set the user’s username and password along with the server(SERVER) and the resource(RESOURCE). Then add event listeners to the connection object. Finally we call the connect method on the XMPPConnection object.

    Write the following methods:

    
    
    private function onConnected( e:ConnectionSuccessEvent ):void {
    
    	trace( "connected" );
    }
    
    private function onLogin( e:LoginEvent ):void {
    
    	trace( "logged in" );
    	ui.connection = connection;
    	grabUserData();
    	startTimer();
    }
    
    private function onDisconnected( e:DisconnectionEvent ):void {
    
    	trace( "disconnected" );
    	loginScreen.visible = true;
    	ui.visible = false;
    	loginScreen.displayError( "disconnected" );
    }
    
    private function onXiffError( e:XIFFErrorEvent ):void {
    
    	trace("Error: " + e.errorMessage);
    	if ( loginScreen.visible ) loginScreen.displayError( e.errorMessage );
    }
    
    private function onIncomingData( e:IncomingDataEvent ):void {
    
    	trace( e.data.toString() );
    }
    
    private function onOutgoingData( e:OutgoingDataEvent ):void {
    
    	trace( e.data.toString() );
    }
    

    The onConnected, onIncomingData, and onOutgoingData methods can have many different uses but for this tutorial we will only use them to trace output so that we can debug our application when and if we need to(specifically if their is a problem connecting to the server). The onDisconnected method makes the loginScreen visible and displays an error to the user notifying them that their connection was lost. The onLogin method prepares the User Interface for XMPP chat by assigning the XMPPConnection object to the connection property within the ui object. This allows the UserInterface object to call methods directly from the XMPPConnection object through a reference. Now that the user is logged into the Jabber server(Openfire), we can start working toward logging the user into a chat room but first we need to identify exactly who our user is. We call the grabUserData method to do so. Finally we call the startTimer method.


    Step 15: Grabbing User Data

    By now the user’s session cookie is stored in the user’s browser and the user is logged into the Jabber server. Now we need to grab basic information about our user. We know the user’s username, so we can use it to access additional information about the user that is stored in our MySQL database. Create the grabUserData method in the Document class.

    
    
    private function grabUserData():void {
    
    	userData.addEventListener( Event.COMPLETE, joinRoom );
    	userData.grab( connection.username );
    }
    

    All of the magic happens within the UserDataGrabber class. All we have to do is call the grab method and listen for the COMPLETE event. Note that the grab method on the UserDataGrabber object accepts one parameter: the user’s username. Use the user’s username from the connection instance.

    This class wouldn’t have any magic right now because it doesn’t exist yet. Let’s write this class now. Create a new class called UserDataGrabber that extends flash.events.EventDispatcher.

    
    
    package {
    
    	import flash.events.Event;
    	import flash.events.EventDispatcher;
    	import flash.net.URLLoader;
    	import flash.net.URLRequest;
    	import flash.net.URLVariables;
    
    	public class UserDataGrabber extends EventDispatcher {
    
    		private static const SOURCE:String = "http://localhost/mycontentsite/scripts/grab_user_data.php&quot;; // Replace with your own php script
    
    		private var _data:*;
    		private var _uid:String;
    		private var _firstName:String;
    		private var _lastName:String;
    		private var _username:String;
    		private var _country:String;
    		private var _statusMessage:String;
    
    		public function UserDataGrabber() {
    
    			super();
    		}
    
    		public function grab( username:String ):void {
    
    			var loader:URLLoader = new URLLoader();
    			var req:URLRequest = new URLRequest( SOURCE + "?cb=" + new Date().time );
    			var vars:URLVariables = new URLVariables();
    
    			_username = username;
    			vars.username = username;
    			req.data = vars;
    			req.method = "POST";
    			loader.addEventListener( Event.COMPLETE, onComplete );
    			loader.load( req );
    		}
    
    		private function onComplete( e:Event ):void {
    
    			e.target.removeEventListener( Event.COMPLETE, onComplete );
    			_data = e.target.data;
    			trace( "User Data:\n" + data );
    			var user:XML = new XML( _data );
    			_uid = user.@id.toString();
    			_firstName = user.firstName.toString();
    			_lastName = user.lastName.toString();
    			_country = user.country.toString();
    			_statusMessage = user.statusMessage.toString();
    			dispatchEvent( new Event( Event.COMPLETE ) );
    		}
    
    		public function get data():* {
    
    			return _data;
    		}
    
    		public function get uid():String {
    
    			return _uid;
    		}
    
    		public function get firstName():String {
    
    			return _firstName;
    		}
    
    		public function get lastName():String {
    
    			return _lastName;
    		}
    
    		public function get username():String {
    
    			return _username;
    		}
    
    		public function get country():String {
    
    			return _country;
    		}
    
    		public function get statusMessage():String {
    
    			return _statusMessage;
    		}
    
    	}
    }
    

    First we create a const that stores the location to the PHP script as a string. We created the grab_user_data.php script earlier. This is the script that performs a query in the database using a specified username to fetch and echo out the user’s data as xml.

    Next we create our variables. I always place an underscore (_) in front of the name of any private or protected variable (property) that will be read-only – o,r in some rare cases, write-only. All of the variables in this class read-only. We use getter methods to permit read-only access to each variable.

    All variables are set when the xml data, which is rendered out from the php file, is parsed with the exception of the _username variable which is set from the username parameter of the grab method.

    Now for the grab method. Nothing complicating here. Create a new URLLoader object, a new URLRequest object and a new URLVariables object. The URLRequest constructor accepts one parameter, the url that you would like to load data from. In this case, the url is stored in the SOURCE constant. I’m sure by now you’ve noticed that the the string ?cb= concatenated with the current time has been concatenated with the SOURCE. The cb stands for cache buster. This prevents our script from being loaded from out of a cache (memory).

    Initialize URLRequest object and the URLVariables object. The URLVariables object holds that the username variable that the php script needs to perform a query in the database. This variable is passed along with the URLRequest. Call the URLLoader‘s load method and listen for the COMPLETE event to be dispatched from loader so that the onComplete event handler method can be called.

    In the onComplete method, create a new XML object. Pass the data assigned from the URLLoader object(e.target in this case) into the constructor’s parameter. Set the class’s variables and dispatch the COMPLETE event.


    Step 16: The LoginScreen Class

    Up to this point, we have assumed that the user is already logged in. If the user isn’t logged in we display the loginScreen. The LoginScreen class will have methods encapsulated within it that handle the user’s login status. Create the LoginScreen class. The class must extend the MovieClip class since it is linked to a library symbol of that type.

    
    
    package {
    
    	import flash.display.MovieClip;
    	import flash.events.MouseEvent;
    	import flash.events.Event;
    	import flash.events.ErrorEvent;
    	import flash.events.KeyboardEvent;
    	import
  6. Carlos Yanez says:
    October 20, 2011 at 3:54 am

    It’s Premium tutorial time! In this tutorial, available exclusively to members of Tuts+ Premium, you’ll learn how to create your own version of the classic Whack-a-Mole game – only, our unfortunate creatures of choice will be worms. You’ll be able to modify the speed of the game and the hit boxes of the worms.


    Preview

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

    Click the worms to whack ‘em! You can alter the speed and the hit box size in the Options menu. Of course, if you follow the tutorial, you’ll have much more control over these settings.


    Active Premium Membership

    Activetuts+ Premium Membership

    We run a Premium membership system which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium, Photo Premium, and the new Mobile Premium too. If you’re a Premium member, you can log in and download the tutorial. If you’re not a member, you can of course join today!

    Also, don’t forget to follow @envatoactive on twitter and grab the Activetuts+ RSS Feed to stay up to date with the latest tutorials and articles.


  7. Joseph Clover says:
    October 20, 2011 at 4:12 am

    In this tutorial, we will draw a selection rectangle with the mouse (as seen in strategy games such as StarCraft and Command and Conquer), and we will also learn how to select units with the rectangle!


    Final Result Preview

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

    Click and drag with your mouse to draw a rectangle that will select any soldier that it touches.


    Step 1: The Setup

    If you are using Flash, create a new ActionScript 3.0 file with the size ’550 x 400′. However, if you are not using the Flash IDE and are using another such as FlashDevelop or Flash Builder, this tutorial contains the SWC files so you can use MovieClips from within your IDE of preference. If you are curious on how to import MovieClips with your IDE, check out the Beginner’s Guide to FlashDevelop and Beginner’s Guide to FDT!

    I should also note that I have included the FLA file in case you do not wish to draw any of your own material.


    Step 2: Creating the Document Class

    Ok, now you may be a little confused if you haven’t really worked with classes before. If you wish to learn more about why classes are important in programming, check out this article by kirupa, or this guide to the document class.

    Create a new ‘ActionScript 3.0 Class’ and give it the name ‘SelectionDemo’. When the file has been created, save it as ‘SelectionDemo.as’. You should save files all the time. I can not stress this enough but the amount of times I have forgot to save work that I have done and lost it all doesn’t bear thinking about. So please, do save the files!

    If you are using an IDE that generates the code for you when you create the class, you should have most of the code below. However, you must still add the lines that I have highlighted:

    
    
    package
    {
    
    	import flash.display.MovieClip;
    
    	public class SelectionDemo extends MovieClip
       	{
    
    		public function SelectionDemo()
            	{
    
    		}
    
    	}
    
    }
    

    We are not done yet however! If you are using the Flash IDE, navigate to the ‘Properties Panel’ and set the ‘DocumentClass’ to ‘SelectionDemo’. If you are wondering what that does, it means that when your application/game is run by the Flash Player, this Class will be the Main class that manages the game. Cool, huh?

    Exporting the Unit

    Run the program; if you get no errors then you should be good to go!


    Step 3: Creating the Rectangle

    Now we should be ready to make the Rectangle! This part will contain a few functions, that’s all. Below is the code for drawing the rectangle:

    
    
    package  {
    
    	// IMPORTING THE CLASSES WE NEED
    	import flash.display.MovieClip;
    	import flash.events.MouseEvent;
    	import flash.geom.Rectangle;
    	import flash.display.Sprite;
    
    	public class SelectionDemo extends MovieClip {
    
    		public var selectionRect:Rectangle; // Will hold the data for our rectangle.
    		public var selectionSprite:Sprite = new Sprite(); // Making a new Sprite to draw the rectangle.
    
    		public function SelectionDemo() {
    
    			//Adding listeners
    			stage.addEventListener(MouseEvent.MOUSE_DOWN, SetStartPoint);
    
    		}
    
    		public function SetStartPoint( me:MouseEvent ):void
    		{
    
    			selectionRect = new Rectangle( stage.mouseX, stage.mouseY ); // Creating the selection rectangle.
    
    		}
    
    	}
    
    }
    

    Now, it’s kind of useless having a rectangle that we cannot see, right? Exactly, so let’s get started!


    Step 4: Drawing the Rectangle

    Great, now we must draw the rectangle to the screen using the selectionSprite variable you seen in the last snippet. Why use a sprite, you ask? All Sprites contain a graphics object, which in turn contains a method called drawRect() this allows us to easily draw a rectangle dynamically in AS3.

    Below, I have placed the code for drawing the rectangle, with comments:

    
    
    package  {
    
    	// IMPORTING THE CLASSES WE NEED
    	import flash.display.MovieClip;
    	import flash.events.MouseEvent;
    	import flash.geom.Rectangle;
    	import flash.display.Sprite;
    	import flash.events.Event;
    
    	public class SelectionDemo extends MovieClip {
    
    		public var selectionRect:Rectangle; // Will hold the data for our rectangle.
    		public var selectionSprite:Sprite = new Sprite(); // Making a new Sprite to draw the rectangle.
    		public var isMouseHeld:Boolean; // Will tell us whether the mouse button is Up/Down
    
    		public function SelectionDemo() {
    
    			//Initializing
    
    			isMouseHeld = false; // The mouse is not held yet.
    			stage.addChild(selectionSprite); // Adding the selectionSprite to the stage.
    
    			stage.addEventListener(MouseEvent.MOUSE_DOWN, SetStartPoint); // Listen for mouse hold.
    			stage.addEventListener(MouseEvent.MOUSE_UP, RemoveRectangle); // Listen for mouse release.
    			stage.addEventListener(Event.ENTER_FRAME, UpdateGame); // Run this function every frame (24 FPS).
    
    		}
    
    		public function SetStartPoint( me:MouseEvent ):void
    		{
    
    			selectionRect = new Rectangle( stage.mouseX, stage.mouseY ); // Creating the selection rectangle.
    			isMouseHeld = true; // The mouse is now held.
    
    		}
    
    		public function RemoveRectangle( me:MouseEvent ):void
    		{
    
    			isMouseHeld = false; // The mouse is no longer held.
    
    		}
    
    		public function UpdateGame( e:Event ):void
    		{
    
    			selectionSprite.graphics.clear(); // Clear the rectangle so it is ready to be drawn again.
    
    			if( isMouseHeld )
    			{
    				selectionRect.width = stage.mouseX - selectionRect.x; // Set the width of the rectangle.
    				selectionRect.height = stage.mouseY - selectionRect.y; // Set the height of the rectangle.
    				selectionSprite.graphics.lineStyle(3, 0x3B5323, 0.6); // Set the border of the rectangle.
    				selectionSprite.graphics.beginFill( 0x458B00, 0.4 ); // Set the fill and transparency of the rectangle.
    				selectionSprite.graphics.drawRect( selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height ); // Draw the rectangle to the stage!
    				selectionSprite.graphics.endFill(); // Stop filling the rectangle.
    			}
    
    		}
    
    	}
    
    }
    

    If you have that code, run your application and watch it work!


    Step 5: Draw a Unit

    In flash, create a new MovieClip and draw a Unit. In the first frame, just draw a unit; in the second frame, add a green circle under the unit or anything that lets the player know that the unit has been selected. It should look something like this:

    Unit MovieClips

    I also just drew a quick grassy background on the stage to make it look nice :)


    Step 6: Exporting the Unit

    Now you have created the MovieClip, right-click the symbol in your Library and select Properties. Check the boxes that say ‘Export to ActionScript’ and ‘Export in Frame 1′. Then, give it the name ‘Unit’. Your properties should look something like this:

    Exporting the Unit

    Note: when you click ‘OK’, you may get a warning because no such class “Unit” exists yet. If so, click OK and we shall fix this now by making a new class!


    Step 7: Creating the Unit Class

    Remember before when you exported the Unit MovieClip? This is where we create the class for that MovieClip. So create a new ActionScript class file named ‘Unit.as’ and place this code within the class:

    
    
    package
    {
    
    	import flash.display.MovieClip;
    
    	public class Unit extends MovieClip
    	{
    
    		public var isActive:Boolean; // Tells us whether the unit is selected or not.
    
    		public function Unit()
    		{
    
    			isActive = false; // The unit has not been selected yet.
    			gotoAndStop(1); // Go to and stay on the first frame ( no selection ring ).
    
    		}
    
    	}
    
    }
    

    Ahead, comrades!


    Step 8: Placing the Units

    Now it is time to add the Units to the stage and give them a position. Also, we are going to place each Unit in an ‘Array’. An array is basically a list which allows us to access the things inside it using an index. A great example of arrays is right at Republic of Code; they’ve also been explained here in AS3 101: Arrays.

    Here is the updated code for ‘SelectionDemo.as’. First, we add a new public Array called unitList just after the other variables:

    
    
    public var selectionRect:Rectangle; // Will hold the data for our rectangle.
    public var selectionSprite:Sprite = new Sprite(); // Making a new Sprite to draw the rectangle.
    public var isMouseHeld:Boolean; // Will tell us when the mouse is Up/Down
    public var unitList:Array; // All the units will be held in here
    

    Then, we update the Main function by placing a function called PlaceUnits(15);. We will create this in a moment.

    
    
    public function SelectionDemo() {
    
    	//Initializing
    	isMouseHeld = false; // The mouse is not held yet.
    	stage.addChild(selectionSprite); // Adding the selectionSprite to the stage.
    	PlaceUnits(15); // Calling a function to place the units on the stage.
    
    	//Adding listeners
    	stage.addEventListener(MouseEvent.MOUSE_DOWN, SetStartPoint); // Listen for mouse hold.
    	stage.addEventListener(MouseEvent.MOUSE_UP, RemoveRectangle); // Listen for mouse release.
    	stage.addEventListener(Event.ENTER_FRAME, UpdateGame); // Run this function every frame (24 FPS).
    
    }
    

    Time to make the function! Ok, we will place this function after the UpdateGame(e:Event):void function and what this function will do is add the amount of units you specified in the brackets to the stage. We will also add the units to the list and give them random positions on the stage while making sure they cannot spawn off the stage.

    
    
    public function PlaceUnits( amount:int ):void
    {
    
    	unitList = new Array(); //Making a new Array(list) to hold all the Units.
    
    	for( var i:int = 0; i < amount; i++ ) // Run whatever is inside the brackets 'amount' times.
    	{
    		var unit:Unit = new Unit(); // Creating a new unit.
    		unit.x = Math.random() * (550 - unit.width); // Setting a random X Position.
    		unit.y = Math.random() * (400 - unit.height); // Setting a random Y Position.
    		stage.addChild(unit); // Adding the new unit to the stage.
    		unitList.push( unit ); // Placing the unit in the Array(list).
    	}
    
    }
    

    When you run this, you should have 15 units randomly placed. Time to move on and program the unit selection.


    Step 9: Z-Sorting!

    When you run the game, you will probably see that there is a strange overlap of the units. Let’s fix it! This is extremely easy and will only require a small change to the PlaceUnits() function.

    Basically, what we need to do is add all the units to an Array (list) and then sort the list based on the Y (vertical position) of the units. The lower the Y property, the further backwards it should be. We will change the PlaceUnits() function to:

    
    
    public function PlaceUnits( amount:int ):void
    {
    
    	unitList = new Array(); //Making a new Array(list) to hold all the Units.
    
    	for( var i:int = 0; i < amount; i++ ) // Run whatever is inside the brackets 'amount' times.
    	{
    		var unit:Unit = new Unit(); // Creating a new unit.
    		unit.x = Math.random() * (550 - unit.width); // Setting a random X Position.
    		unit.y = Math.random() * (400 - unit.height); // Setting a random Y Position.
    		unitList.push( unit ); // Placing the unit in the Array(list).
    	}
    
    	unitList.sortOn("y", Array.NUMERIC); // Sorting the list in order of the 'y' properties!
    
    	for( var j:int = 0; j < amount; j++ ) // We will run through this loop again to add the units.
    	{
    		stage.addChild( unitList[j] ); // This adds the 'sorted' unit to the stage.
    	}
    
    }
    

    There we have it… no more overlaps!


    Step 10: Selecting Units

    Now, each frame we will check whether any units have been selected; if they have then we will make their selection ring appear.

    Edit the UpdateGame() function to the following:

    
    
    public function UpdateGame( e:Event ):void
    {
    
    		selectionSprite.graphics.clear(); // Clear the rectangle so it is ready to be drawn again.
    
    		if( isMouseHeld )
    		{
    			selectionRect.width = stage.mouseX - selectionRect.x; // Set the width of the rectangle.
    			selectionRect.height = stage.mouseY - selectionRect.y; // Set the height of the rectangle.
    			selectionSprite.graphics.lineStyle(3, 0x3B5323, 0.6); // Set the border of the rectangle.
    			selectionSprite.graphics.beginFill( 0x458B00, 0.4 ); // Set the fill and transparency of the rectangle.
    			selectionSprite.graphics.drawRect( selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height ); // Draw the rectangle to the stage!
    			selectionSprite.graphics.endFill(); // Stop filling the rectangle.
    			CheckForSelection(); // We will check to see if any units have been selected.
    		}
    
    }
    

    As you can see, we added a function called CheckForSelection(). Let’s create that function after the others:

    
    
    public function CheckForSelection():void
    {
    
    	for each( var unit:Unit in unitList ) // For every unit that is in the Unit Array(list)...
    	{
    
    		if( unit.hitTestObject( selectionSprite ) ) // If the selectionSprite is touching the Unit.
    		{
    			unit.select(); // Make the unit selected.
    		}
    		else
    		{
    			unit.deselect(); // De-select the unit.
    		}
    
    	}
    
    }
    

    As you can see in the highlighted lines, the select() and deselect() functions do not exist. Open up ‘Unit.as’ and let’s put them in:

    
    
    package
    {
    
    	import flash.display.MovieClip;
    
    	public class Unit extends MovieClip
    	{
    
    		public var isActive:Boolean; // Tells us whether the unit is selected or not.
    
    		public function Unit()
    		{
    
    			isActive = false; // The unit has not been selected yet.
    			gotoAndStop(1); // Go to and stay on the first frame ( no selection ring ).
    
    		}
    
    		public function select():void
    		{
    			isActive = true; // The unit is selected.
    			gotoAndStop(2); // Show the ring.
    		}
    
    		public function deselect():void
    		{
    			isActive = false; // The unit is not selected.
    			gotoAndStop(1); // Do not show the ring.
    		}
    
    	}
    
    }
    

    Run the game and all should be working!


    Step 11: Challenges

    Now that you have sucessfully completed this tutorial, I now have some challenges for you to follow. Feel free to skip them, but following them will help you learn.

    Beginner:

    • Spawn 25 units instead of 15
    • Change the colour and border of the rectangle

    Intermediate:

    • All of the above
    • Add a TextField under the unit and make it display the unit’s name ONLY when selected.
    • Play a sound when a unit is selected

    Advanced:

    • All of the above
    • When the player clicks a position, make selected units move to that position. (Hint: use an Array to know what units are selected.)

    Only do the challenges you feel comfortable with!


    Conclusion

    Thankyou for reading this tutorial and I hope you learned something new. Also, I would also like to thank Tomas Banzas for the art he did!

    If you have completed some of the challenges and would like to show off the results, please post a link in the comments – I’d love to see them!


  8. David Appleyard says:
    October 20, 2011 at 4:28 am

    We’re immensely pleased to announce that, after months of waiting, a new member of the AppStorm network has landed: Windows.AppStorm! Read on to find out more about what this fantastic new site has to offer…

    Complimenting Mac.AppStorm, Web.AppStorm, iPhone.AppStorm, iPad.AppStorm, and Android.AppStorm, our new Windows site will be offering reviews and roundups covering the entire Windows ecosystem, including Windows Phone 7, and games, along with tips and tricks to get the most from Windows.

    We know that many Tuts+ readers use Windows devices every day and want to provide you with a fantastic resource for everything Windows related. We’re incredibly excited to bring you excellent Windows content of the high quality you’ve come to expect from AppStorm – daily reviews, how-to’s, roundups, news, and opinion.


    Subscribe and Stay Up-to-Date!

    We have some absolutely fantastic posts lined up over the coming weeks, and we’d hate for you to miss out… There are a few different ways to subscribe to Windows.AppStorm – hopefully one of the following options will work for you!

    • Subscribe to our RSS feed
    • Follow @windowsappstorm on Twitter
    • Sign up for Email Updates
    • Stay up-to-date on Facebook

    Get Stuck In

    Windows Reviews

    As a treat for all newcomers to Windows.AppStorm here are a some links to articles published in the interim, you won’t be disappointed!

    • 90+ Incredibly Useful Windows 7 Apps & Tips
    • 25 Absolutely Gorgeous Windows Phone 7 Apps
    • 12 Fantastic Windows Alternatives to Mac & iLife Apps
    • 25 Beautifully Designed Windows Apps
    • The AppStorm PC Builder’s Guide – Summer 2011

    Head over to Windows.AppStorm…



  9. Activetuts+ Editor says:
    October 20, 2011 at 4:41 am

    Are you an RIA developer? Do you make Flash games or Unity games? Do you know some cool tips or techniques that you’re always surprised your colleagues don’t know? You sound like the perfect person to contribute to Activetuts+!

    We’re on the lookout for new writers and screencasters, so read on to find out more…


    What We’re Looking For

    Right now, we’re putting out a general call for Quick Tips.

    A Quick Tip is a short article or screencast – we’re talking about a thousand words, five steps, or a few minutes – that covers one bite-size subject.

    For example, a Quick Tip could cover a small library, one or two components, or a technique – each a useful topic for which a full tutorial would be overkill.

    We’ve also published Quick Tips that cover individual design patterns or error messages. You can see a full list on our Tips page.

    As you can see, we’re really low on Unity, Silverlight, and HTML5 Quick Tips, and even our Flash stockpile has dried up over the last few weeks. We pay $50 for every Quick Tip that we publish, and if you submit an idea now there’s a good chance we’ll even be able to publish it this month!


    Pitch a Quick Tip

    Got an idea? Great! Pitch it to us (in about a paragraph or so) using the following form:

    Pitch your Quick Tip idea

    You can read more about the sort of topics we cover on Activetuts+ in our Author Guidelines – though if you’ve been reading the site for a while, you’ve probably got a good idea already.

    As long as you’ve got an original, useful idea and can string a decent English sentence together, there’s a high chance your Quick Tip pitch will be accepted, so don’t be shy.

    (For longer-form tutorial pitches, we do prefer to see some example of your previous work: projects you’ve worked on, blog posts you’ve written, presentations you’ve given, and so on. For Quick Tips, this isn’t necessary – although we’re still interested!)

    We’re looking forward to reading your pitches.


  10. Jason McElwaine says:
    October 20, 2011 at 5:21 am

    ActiveDen’s latest community-organised contest has just taken place. The theme was “Widget/Apps” and we had a number of outstanding entries, with $1,450 prize money up for grabs. We had a lot of fun with the contest and are thrilled to be offering the entries for free exclusively here on Activetuts+!


    The Winner: Lion’s NeatList AIR App

    Lion’s NeatList is a cool AIR app to keep track of your daily tasks. It also took home $1,000 for first prize!

    NeatList AIR App
    Download This Entry
    Demo View It Online

    Check out Lion’s ActiveDen Portfolio


    RimV’s Flickr Box AIR App

    Flickr Box is a cross platform AIR mobile app that runs on Android, iOS and RIM Playbook. Built by 3D legend RimV.

    Flickr Box AIR App
    Download This Entry
    Demo View It Online

    Check out RimV’s ActiveDen Portfolio


    FlashEdge’s 3D Flickr Gallery

    Coming in third was this amazing 3D gallery built by FlashEdge.

    3D Flickr Gallery
    Download This Entry
    Demo View It Online

    Check out FlashEdge’s ActiveDen Portfolio


    Kontrast’s Survey/Feedback/Quiz Form

    Build your own interactive form with this great entry from Kontrast.

    Flash Feedback Form
    Download This Entry
    Demo View It Online

    Check out Kontrast’s ActiveDen Portfolio


    RubenBristian’s Media Love Widget

    Create an online YouTube Poll with this awesome widget by RubenBristian.

    Flash Poll Widget
    Download This Entry
    Demo View It Online

    Check out Ruben’s ActiveDen Portfolio


    PezFlash’s Snakes & Apples

    Catch the dreaded Apples with this fun game by PezFlash.

    Flash Game
    Download This Entry
    Demo View It Online

    Check out PezFlash’s ActiveDen Portfolio


    RabidFlash’s YouTube Comment Widget

    Load YouTube comments with this cool widget by RabidFlash.

    Youtube Comments
    Download This Entry
    Demo View It Online

    Check out RabidFlash’s ActiveDen Portfolio


    Zefs’ Envato API AIR App

    View ActiveDen forum threads, the latest featured files and so much more with this awesome AIR app from Zefs.

    Envato API AIR App
    Download This Entry
    Demo View It Online

    Check out Zefs’ ActiveDen Portfolio


    ZoomIt’s Flash Testimonial Rotator

    Create a cool Flash Testimonial Rotator with this XML driven widget from Zoomit.

    Flash Testomonials
    Download This Entry
    Demo View It Online

    Check out ZoomIt’s ActiveDen Portfolio


    Sergibh’s Flash Horoscope Widget

    Present daily horoscopes with this neat component from Sergibh. Mobile App included.

    Flash Horoscope Component
    Download This Entry
    Demo View It Online

    Check out Sergibh’s ActiveDen Portfolio


    CodingJack’s ChangeStar Envato API AIR App

    Track your Envato marketplace file ratings with this easy to use AIR app.

    Envato API AIR App
    Download This Entry
    Demo View It Online

    Check out CodingJack’s ActiveDen Portfolio


    More Info

    Some entries do not include ActionScript source. Feel free to use the entries in your client projects but resale of any kind is not permitted.

    Want to read more about the fun we had? Check out the competition threads over on the ActiveDen forums here and here.


    The Competition Sponsors

    Big thanks to all of these guys for sponsoring the competition:

    Envato

    BitFade   PezFlash   ZoomIt

    LGLab   FlashEdge   Parker and Kent

    Special thanks to Zefs and PatrickJansen for their amazing work on the competition banner!


Leave a Reply

Click here to cancel reply.

search search search search search
Find an Article
Categories
  • Flash Video Training
  • Hints and Tips
  • Recommended
Please Support Our Sponsors
Recent Posts
  • Workshop Coding Challenge: Fix This Breakout Game
  • Enable the Latest AIR SDK in Flash Professional CS5.5+
  • Quick Tip: Versioning Your Files With Dropbox (via Webdesigntuts+)
  • Workshop: Nuclear Outrun – Critique
  • Understanding Variables, Arrays, Loops, and Null: The Post-it Note Analogy
Tag Cloud
2011 ActionScript Active Activetuts+ Adobe animation Basic Basix Best Build Button Character 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+ Tween 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 2012
M T W T F S S
« Apr    
 123456
78910111213
14151617181920
21222324252627
28293031  
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

  • 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