Nov 11, 2011
Posted on Nov 11, 2011 in Hints and Tips | 10 comments
Have you ever dived right in to developing a game, but found yourself having to constantly change aspects of the design or the gameplay due to a lack of planning? You should consider using a game design document: a guiding vision of the game as a whole, pulling together ideas and plans for the design, development, and business sides of your game.
Introduction
To put it simply: we like to tell stories. Some true, some not so much. But the point is that we have been crafting tales for a very long time, and as time went by these tales began to evolve, becoming more complex, with richer details, with more and more fantastic backgrounds and appealing plots. Whole new worlds were born from thin air, hammered into shape in the anvils of the human brain.
And as the stories grew in complexity, so did the tools used in their making. Art diverged into several different categories, music became more elaborated and movies found their way into the world. Technological enhancements allowed sharing of information, spreading art all around the globe. New fantasy worlds were created each day. Worlds so rich made people began to desire becoming a part of them. A new concept was being brought to life.
Although video games were first just about getting the highest score possible when faced with a determined task, developers soon realized the endless possibilities laying ahead of them. Playing a video game is more than simply sitting through another story. For the first time one could have a say in how the tale told itself. Players could take hold of characters and live the hardships of the journey themselves, diving into that particular world and mastering it, making theirs the protagonist’s conquests and failures.
A game has the potential to bond player and story in a way never seen before. This connection can be established in a variety of ways. Be it the fantastic landscapes in which the story unravels, the soundtracks or the well-constructed personality of a particular character. It forces the player to thrive in order to see more of what he wants.
Unfortunately, since a game is composed of so many different elements, different experts from different areas are required in its creation, making the coordination of the development process a rather tricky job. In order to help developers do their job, a document known as a GDD, or Game Design Document, is often employed.
A GDD is a tool that helps merging the components of a game together. It registers the general ideas of every aspect of it, from graphics design to story line. In short it registers the game concept, creating the closer feeling of the finished product.
Although the writing of a GDD is not a vital part of the creation process, it is of major help to the team of developers, especially when in major projects, involving large amounts of personnel. Also, there is not only one way of writing a GDD. In fact, GDDs differ vastly among game development companies, but as a general rule, most games are built around these documents.
So without further ado, here is what you need to know about this important tool.
Overview
A Game Design Document must teach everyone who reads it how the game that you’re talking about works. In order to do this, you need to explain not just the mechanics, but also how the game’s objects (characters, enemies, puzzles, weapons, environment, and so on) interact with each other, what your game is about, and how it looks. In a GDD, these points are discussed in some general sections.
Marketing
Marketing is a big section subdivided in many subsections that explain the major commercial aspects of the game, like public target, deadlines, competitors and selling points. This section is very helpful for business, since it shows what your game has in advantage over others and how it meets the consumer demand. In others words, it shows the game’s appeal.
High Concept
Before you start to tell the reader how your game works, you must clarify the core concept of your game, i.e., you must talk about the major aspects of your game in a very short way, so that the reader can anticipate what will be said in the GDD and pay attention to what is important to the game. For this, there is the High Concept section, which explains all of it, so that the reader won’t have to read many pages of the document just to know what your game is about.
For example: if you tell the reader that your project is a futuristic space shooter game, he will be able to imagine what kind of weapons, movements, enemies and others things will be used in the game.
Gameplay
This section is one of the most important in the GDD, because it explains how to control the objects in the game and how to make them interact with the other parts. Also, it explains how the player will execute the possible moves. Moreover, it’s interesting to comment the way that the game flows and what happens during the course of the game.
First Minutes
This is a subsection of the Gameplay section, and it exposes what the player will see in the game when it has just finished loading. It exposes the actions and reactions between the game and the players during this interval, helping understand the game’s progress throughout the gameplay and give a better idea of how to play it. It’s also an important subsection, since it will determine whether or not the game is fun.
Gameflow
This is a more detailed subsection of the Gameplay than the First Minutes. It describes all the options that the player can choose while he is playing. It’s a kind of flowchart that shows which reaction each option has, giving a picture of the game as a whole. Generally it shows a flow of screens (e.g. from the “Main menu” screen it goes to the “Select level” screen), but you can also put actions and consequences in it (e.g. if the player chooses the “Mage” character, all the backgrounds will have a “magical” feeling). It literally explains the way that the game flows, as the name suggests.
Victory Conditions
You also need to teach the reader in the Victory Conditions subsection, what must be done to win, when the player loses and under which conditions this happens. In other words, this section explains the goals of the game.
Number of Players
It’s important to specify how many people can play, because this implies the type of multiplayer – where applicable – that the game will support; for example: split-screen, LAN connections, Internet connections. Note: this section has influence over the Victory Conditions, since the players will need to do different things to win in a competition than in a cooperative game.
Art
Once you explained how to play your game, it’s import to show how your game will look like and which kind of art is behind it, since it’ll influence how the elements of your game’s universe will coexist, mixing the emotions of who is playing. This is a crucial point in the game’s marketing, because it shows the appearance of the game and the feelings it will pass to the player.
Technical Aspects
Another section that must be put in a GDD is the Technical aspects, since it defines the physical game requirements needed to play and specifies on which platforms the game will be developed, which engines will be used, and more. This affects the Marketing, as the kind of hardware used affects both the fanbase and the public target, i.e., the people who consume the game.
Is There a Formula?
All things said, you need to keep in mind that even if some general subsections are common between the GDDs, there is no static form to make this kind of document, and no such thing as a perfect formula. Every game designer has his own way to do this and you must discover yours. This is a hard job, but in this article we’ll give some tips explaining how to create each subsection of the GDD – however, it’s up to you to decide which of them are necessary to design your game.
Always be clear and concise in your text and use a lot of images, because they give the reader a faster and more real view about the game’s final result and they also ease the explanation about puzzles (if your game has them) and how characters, environment, monsters, screens, weapons and other objects from the game will work.
Moreover, you can also find new topics to add in your GDD, as long as it’s necessary to the understanding of the game’s core. Some things that deserve attention are the innovations and the particularities of your game. For example, if your game project brings up a new way of playing, or a specific graphic concept or if it’s focused in music (like a music game), you should discuss it in the document, to convince everyone why this innovation is a good idea.
Guidelines
A good way to start your Game Design Document is with the Marketing section, because it will be the section that your investor or client is interested in, thus allowing them to gain interest in your game faster. In indie game development, it is not a common section due to the common lack of investors, however, if you think in other projects not related to commercial purposes, such as a free game on App Store of Apple to help a charity institution, it’s important to keep track of plans related to the marketing aspect, since it will be really important to have a publishing plan.
After this, it’s important to put the High Concept, so the reader immediately will understand the core of the game and pay attention in the major aspects. You will figure out that in GDDs it’s common to always start with a basic and summarized definition of the game, and go on to present every detail step-by-step.
In the next section you should write about the Gameplay, which should include, as sub-sections, the First Minutes, the Game Flow, the Victory Conditions and Number of Players.
After that, you need to show how your game will look, so talk about the Art, using as many images as you can. In the end, you can talk about the Specific Sections, which should bring topics that explain: the innovations, the aspects that not necessarily all games have, like story, artificial intelligence, characters and others particulars things.
All the things said above are represented in the flowchart bellow, but it’s just a general schema and you can (and should) adapt to your game. Remember: there isn’t a perfect formula. Now that you have a kind of skeleton of the GDD, you will find in the Composition topic of this tutorial a more detailed explanation about what which section of a GDD holds.
Composition
Although there isn’t such a thing as a perfect formula for composing your GDD sections, it’s important for you to include some crucial topics in it, as well as avoid some major mistakes. This section teaches you how to detail the sections presented in the Overview topic, while showing examples of how it’s done and some common mistakes.
The Marketing Section
There is no correct way of dealing with this subject, since your objectives for it will depend on your game. It’s also not really needed; you can either concatenate it all in a major subsection or spread it across the document, as some of the topics discussed here have much in common with others elsewhere. Despite the way you choose to do it, some topics should always be addressed:
Target Audience
Who will play it? This is no ordinary section, so don’t settle for a simple “for children” description, for example. There are endless ways to “classify” gamers, and you must explore this. Comment on how it will appeal to each category and try not to leave anyone out; they might share little in common with your product, but they still share something.
Right:
Turret Defense will appeal to male gamers of ages 15 – 25 who typically play FPS and RTS PC titles. In particular, fans of Sci-Fi themed games, movies, and books will be immediately attracted to Turret Defense’s space adventure setting and theme.
Turret Defense will have an ESRB rating of T (Teen) for ESRB Content Descriptor of Violence, suitable for ages 13 or older. To conform to the wishes of the publisher, Turret Defense will not use blood or any other content that would lead to further ESRB Content Descriptors related to violence.
Wrong:
Turret Defense will appeal to a large audience. Based on the experience of similar games, it should be a huge financial success in the video games market. We plan to advertise it heavily with ads on games-related websites with huge traffic.
(“A large audience” isn’t a valid fanbase, and it doesn’t explain why they would enjoy it. No mention of the ERSB rating or whether the game has any age-restricted material.)
Another good example:
OrBlitz is expected to receive an ESRB rating of Everyone. The main target market will be puzzle games fans, but the game’s many original aspects will attract a wider audience, including people that prefer to buy action-based games. Real time strategy games fans could also be interested in the game for its tweakability and other similarities with RTS games. Because of the lack of graphic violence and the intuitive interfaces, this game can target women as well as men. The game is relatively cute and colorful, and is expected to appeal to both American and Japanese audiences due to the content in it.
Notice all the classifications in the example: gender, age, nationality and genre. Keep in mind that many more categories may arise depending on your game. Predictions on the ESRB rating are also welcomed, therefore some restrictions regarding violence, sexual content and language should be addressed if needed.
Platform
Extremely straight-forward section. Just enumerate the platforms that your game is being designed for. An estimate of the system requirements are also a good call. If needed, you can comment on porting the game and the difficulties involved.
Competitors
This is a key subsection of your document. In here you must compare your game to others already developed. It is important to give a small description of the game being compared to, and point the similarities between both. This is an excellent opportunity to expand the comparisons that were already made across the GDD and give the reader a better picture of what the game will actually be.
At the end summarise your product’s strong points and convince the reader why would your product sell despite its competitors. This is the trickiest part, because you must pick good opponents, otherwise the reader just won’t know what you are talking about, and still keep your game’s image shining; therefore a good writing is crucial. Your ‘adversaries’ also help on the notion of how big your market can be.
Milestone Schedule
The Milestone Schedule subsection is where you must define each necessary steps in order to develop the game, which is basically a timeline of the intended completion of phases of your game. Through that, not only you, but also the investors, can have a very rough estimate of the interval of time needed to complete the project.
Other Subsections
You may choose to add some heavy market-related topics such as Costs Overview, that can comprehend equipment costs, people costs, additional costs and expected profit.
Future Plans
Sometimes there are so many ideas to complement a game that some of it must be put aside in order to meet the tight schedule of development. This section is specifically made to store those ideas, so that you can work on it later depending on how things work out. DLCs, possible sequels, minor improvements to gameplay, graphics and so on, all comes in here. You can also gather some ideas of what to do with the game once it is finished.
Example:
- Add some side quests.
- Enable the character to jump.
- Make a movie telling your story as a developer.
The Introduction Section
The introduction section should provide the reader with a basic overview of the game itself, first with a light approach with the High Concept subsection and then with a broader one within the Summary subsection. You can also highlight the more innovative aspects of your game in a Key Features subsection.
High Concept
A one paragraph description of what your game is about. This should sound like the summary of a summary. Avoid any technical aspects, graphic or sound designs, complex gameplay features, or marketing details that aren’t strictly required (for example, if you’re making a rhythm game you should mention what kind of music style you will be using, whereas if your game is a puzzle you can just forget about music for now; it’s better to describe what type of puzzle the player will have to solve instead). The idea is to describe your game in the most non-technical and shortest way. A good tip is to use well-known games as examples for comparison, such as “X is a three-dimensional racing game with power-ups like Mario Kart”.
Right:
Scavenger Hunt is a three-dimensional arcade-style game where players race to collect items from a list before their opponents do.
Wrong:
Scavenger Hunt is a three-dimensional arcade game with puzzle elements set in a fictional neighborhood in the 50′s with cartoony graphics and music, where the player races to collect various home-related items from a given list in each stage, while using gags as powerups, before his opponents, which can be either CPU-controlled when in singleplayer mode or human-controlled players in multiplayer mode.
(Keep it short and simple)
Summary Overview
A more detailed description of your game, with less restrictions than the High Concept subsection. Start with the core aspects of the gameplay, describing what role the player will take, what’s his goal, what he will have to do in order to accomplish it, what will hold him back and why the game will be entertaining.
Next, do a quick introduction to the game’s setting and a brief description of the history (if any). It’s always nice to use an image instead of describing what the graphics will look like, so if you don’t have any sketches or conceptual art you should just paste pictures with similar art to what you will be using (that includes screenshots of other games as well!).
Key Features
The best way to compose this is using short topics (i.e. bullet lists) instead of long paragraphs. Basically you should tell the reader right away about all of the creative ideas you had which you thought would make your game a great game.
Right:
– Simple yet powerful physics that provides surprising results from a set of simple rules.
– Amazing Hatched and Cel-Shaded graphics.
– Never seen before paint system where color spreads out to the world as the gameplay picks up speed to a frantic pace.
– Powerful land crafting abilities that allow you to build complex paths the orbs can take, like tunnels and bridges.
– Various game modes and scenarios to choose from, each of which feels like a totally different game, favoring action or reflection.
Wrong:
The game will have simple yet powerful physics that provides surprising results from a set of simple rules, while using amazing Hatched and Cel-Shaded graphics and a never seen before paint system where color spreads out to the world as the gameplay picks up speed to a frantic pace, when players build complex paths by using powerful land crafting abilities which the orbs can take, in various game modes and scenarios.
(Too many ideas at once makes the reader lose the train of thought.)
Third-Party Software Used
A little explanation of the programming languages, libraries and software you will be using to create your game, as well as the programs you will use to adjust your graphics and sound engines and any other engines your game may need (like a networking one for multiplayer games).
If you’re under some heavy software/hardware restrictions, you should specify that in here (i.e. if you’re making a game for Apple devices, you have to tell you’ll be using iOS-compatible technology). Also if your game is aimed at PCs and you have an idea what the minimum requirements will be you should note them here. Although the non-programming people of the project probably won’t understand what the heck a “NVIDIA Cg 1.2.1” is, they’ll have to know it by name since that’s what the game will run on.
The Gameplay Section
This section is designed to describe how the game will effectively work, describing the game’s objective as well as its elements (menus, victory conditions, enemies, powerups, stages, …), and the interaction between each one of these elements with the player. If you feel like one subsection, such as “Enemies”, has too much content to be just a subsection you may promote it to a section of its own.
First Minute
It’s interesting for you to describe what the player’s reaction is going to be like as soon as the game loads, such as describing whether he can start playing right away or if he can navigate through menus to change some options beforehand, whether the player will have to learn the controls by trial and error or a tutorial will be presented to him, whether all stages will be available at the get-go or if he will have to unlock them in progression, and so on. Given you have already planned some stages ahead, you could narrate a short run of the player clearing a stage, describing the enemies and/or puzzles he had to go through in said stage.
Right:
After the title screen the player is presented with a list of games he can join and an option to create a new one. After selecting the option to create a new game a list of predefined levels appears on the right of the screen. (…) After the settings are adjusted three other players join and the game begins. A timer counts down from five while the players get ready, using the small amount of money they start with to place a few blocks. As a simple beat plays in the background, the board rotates around the middle of the screen, revealing the layout of the level. (…) The player’s goals are on each corner of the board. (…) As soon as the count down reaches zero, ‘Go!’ is displayed in the middle of the screen and the orbs start falling from the cloud, creating havoc on their path. (…) The player quickly places a stone corner block on the edge of the level and the orb bounces off it, only to end up in the player’s goal followed by a familiar cashier sound. The player’s score and cash are updated to 200, and he starts going through the blocks he can now place (…).
Wrong:
The game begins with the players facing each other in opposite corners. Player 1 decides to use all his money from the get-go and wins the game by using well-placed stone blocks to earn points.
(Although being essentially how the game will run, it needs more details.)
Gameflow
A nice complement to the “First minute” would be the “Game Flow”, which is usually represented as a flowchart. In contrast to the previous subsection, this one won’t focus on the first impression but rather give an overview of the whole picture, showing step-by-step which actions the player can take from the moment the game is loaded to when the player hits the “exit button” – i.e., ends his gaming session – including the gameplay itself in a somewhat high concept.
Right:
(Example from Drexel Game Design’s Scavenger Hunt GDD.)
Wrong:
(Nothing THIS simple. Include, at least, all the screens that the player will run through!)
Victory Conditions
Here you state what is required for the player to clear a stage, win a match, or advance another level, whether your game is a puzzle, where the player advances to the next level when all pieces are combined in a certain way, or a sidescrolling shooter where the player advances a stage when he defeats the boss at the end, or whatever. Obviously, this depends entirely on what kind of game you’re designing.
Example:
In Space Invaders, the player advances to a new wave each time he destroys all enemies from the current wave. Since the waves are endless, the game will keep going until the player runs out of lives.
Graphics
You can’t really provide the reader with screenshots or video footage of something you may haven’t even designed yet, so in this subsection you should simply describe how do you plan to handle your graphical engine and maybe show some sketches of your game or a few drawings in the art style you intend to use. Planning the game HUD from the beginning will save you a lot of time later on, for example.
HUDs
The head-up-display is the in-game interface the player will have when playing the game. Rather than in-game menus like settings or inventory screens, this refers specifically to the floating windows and bars which don’t normally interact with the game and serve a information-only purpose. This includes health bars, mini-maps, time counters, equipped items and their amounts, money and etc. Although the size of the HUD will vary according to the game type (MMORPGs and RTSs will have big HUDs while sidescrollers and puzzles will have very small ones) keep in mind that a HUD shouldn’t occupy too much of the screen.
Example:
Sounds
On the other hand, one cannot sketch sounds, so you’ll just have to detail your sound engine here, and maybe the style of songs your game will use. Although for most games you will simply state that there will be different background music for different situations, it goes without saying that this subsection is most important for a rhythm game.
Controls
Stating which buttons/keys do what can be troublesome in the case where a single button does more than one action (i.e. The ‘A’ button in any 3D Zelda). Start by putting a simple picture of a controller or a keyboard with each button highlighted with their function in a more general sense. After that, if your game has advanced combos or something similar to that, explain them carefully, stating under which conditions each combo is “activated”.
Example:
(Image from CrunchTime Games Inc’s Shred Nedbula document.)
Game-Specific Subsections
Puzzles could have a “Pieces” subsection, sidescrollers will probably have a “Level Design” one, space shooters may have “Enemies” and so on. As the title in bold above says, each game will have their own specific subsections, and since we can’t compose a subsection for all the possible ones that one GDD can have, we will provide you with the three bold subsections presented here as examples.
Pieces
Suppose we have a puzzle game, where the player rotates different pieces in order to create a line of matching pieces to gain points. This would be a nice subsection to show some sketches of the many different types of pieces, as well as explaining their rotation pattern, stating their points value, and maybe describe their positioning placement. Pictures are welcome as always!
Example:
(Image from Colin Fahey’s Tetris article.)
Level Design
Now let’s pretend we have a typical 2D platformer. One of the core elements of the game is the stages the player has to go through. It’s important that each stage feels unique so the player won’t feel like he’s just repeating the same thing over and over again. On the other hand, the player should still be familiar with the flow of the stage, i.e. if there’s always a checkpoint somewhere halfway through it, or some collectible items along the way.
What are the different types of enemies, terrains, doodads and power ups and do they allow the level designers to come with many different stages? You could present some beta stage diagrams to illustrate how will they be carried out.
Example:
(Map from Super Metroid; image from jansenprice.com.)
Enemies
It’s very popular for space shooters to have many kinds of enemies, each one with different attacks and movement patterns, as well as different values for health, speed and targetable area. As such, it’s no surprise you would need an extra section to present all the game’s foes and their stats. Also, you could state some of their more obscure behaviour like shooting an extra beam when their health is low and so on.
Example:
(Image from CrunchTime Games Inc’s Shred Nedbula document.)
Plot
Many games are set in fictional worlds, each with their own geography, history and characters, in which the player will undoubtedly play a large role as the protagonist. If your game has a particularly interesting setting, it would be interesting to include a little insight on the game’s storyboard, describing the protagonist’s main events during his adventures and details about the lore.
Characters
Lots of games aren’t made of enemies alone. There may be a protagonist and allies to help him overcome his foes. For example, even a tower-defense game without a controlled character can still have side-characters like a tutorial-NPC giving you tips on how to overcome certain challenges at the beginning of each stage. If you do have a protagonist that the player controls, then what’s he like? Does he have any abilities and powers? Keep in mind that this shouldn’t feel like a “How to Play” subsection.
Artificial Intelligence
Any game will need a persisting world to handle all the player’s actions to the game and the other way around. That includes enemy movements, player controls, collision handling, time counting, random number generators and many other things one could need in a game. Although people not directly related to the programming may not understand this subsection entirely, they should at least grasp the basic of it. Most of all, keep the coding out of here and simply state the enemies’ moving patterns, the chain puzzle piece falling algorithm, maybe illustrate the combat system with a flowchart and so on.
Example:
The characters on the board will escape the orbs using simple pathfinding / flocking algorithms. Every level will use up to three different script files to issue commands to the animated characters. (…) Player bots will be used to simulate real players. This will allow any level to be played even if there are more goals than players. The decision process that the A.I. system is trying to solve is this:
– Should I place a new block? If so:
– Where do I place the block?
– What type / material should the block be?
Technical Aspects Section
The technical aspects consist of a series of game data, such as the system requirements on which it will play and the framework in which it was developed, the method or algorithm it was based on, and the maximum number of elements that can be rendered on screen. The graphical technical aspects consists of software used, modeling type, art style and others according to these topics.
The system requirements are the necessary computer settings for the game to be played, like the size it occupies on the computer’s HD and how much RAM is needed.
Another important technical aspect not to forget is the ESRB (Entertainment Software Rating Board) rating (or similar), already explained earlier. Some of the ratings are shown below.
To Include or Not to Include? When? Why?
Technical aspects interest the companies that will distribute it or that will use the technology developed in the game, so always add something in it if you’re showing this to someone that will approve or disapprove the game. There has to be some care when writing technical aspects. You can write something in the wrong subject. For example: limiting the platform and distribution game mode belongs to Marketing Aspects, not to Technical Aspects.
More Examples
For professional examples of Design Documents provided by the developers, we have: Shred Nebula, Play With Fire, Grim Fandango Puzzle Document, and many more avaliable at gamepitches.com.
For more material about the structure and composition of a GDD, one could try the featured Gamasutra article The Anatomy of a Design Document, Part 1 and Part 2; the self explanatory Creating a Great Design Document; and a more general How to write an effective Design Document, which isn’t about GDD, but about software development.
More on Game Design: The Two C’s of Video Game Design.
Moreover, there are other visions of how should documentation be done in the Game Industry, as seen in Game Design Logs and Return of the GDD. Although they seem to contradict what had been told here, this should fall in a case-by-case analysis considering team size, budget and deadlines.
Conclusion
For designers who need the approval of an investor: truth be told, before you can make any progress with an investor, you must first get his attention, and to do so, the following key points of your document must be in excellent shape.
High concept: you never get a second chance to make a first impression, and here is where you will make it. We have already given you the tools to make this section, now just remember to give its construction a high priority and point everything that makes your game more appealing here.
Pictures: do not be fooled that the reader will always go through your entire GDD, there are some documents that surpass a thousand pages (yes, this is true!). But he will surely take a better look if something catches his attention, and what better way of doing so than with pictures? After all, one image is worth a thousand words.
It goes without saying that your document must have a great appearance. Take your time to make everything readable and nice. Also, don’t forget that this article only presented a skeleton structure of a GDD for you; you will have to adapt it to your own game!



View full post on Activetuts+
Oct 20, 2011
Posted on Oct 20, 2011 in Hints and Tips | 10 comments
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
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
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?
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.
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:
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.
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.
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:
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.
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.
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.
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.
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.
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:
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.
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:
- a green highlight appears for a couple of seconds behind the task in the list to point to where it has been added, and
- 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.

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.
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+
Apr 21, 2011
Posted on Apr 21, 2011 in Hints and Tips | 2 comments
After many months of learning how to program from the ground up, you’re ready to put it all to use: we’re going to build a simple drawing application. We will focus on Object-Oriented Programming techniques, specifically the use of interfaces. By setting up a few rules for our programming, we will make expanding the feature-set and debugging the project much easier.
Final Result Preview
You’ll see that our little drawing app will be rather simplistic. Rest assured, though, that the internal logic just might make your brain explode. Don’t worry; we’ll take it one step at a time, as we always do. Here’s a peak at what we’re working towards in this tutorial:
While the result is simple, the underlying code is complex, and one of the things you’ll hopefully learn along the way is that Object-Oriented Programming can keep you organized and keep your project maintainable.
Step 1: Create the Project
First things first: we need a home for our project. Start by creating a main folder for the entire project. Use the approach that works best for you. It could be as simple as creating a folder on your computer, using the OS, or using Flash Builder to create a new project for you.
It doesn’t matter where this folder is created, so long as you can get to it when we need to save or open files.
I’ll be calling this app “Drawr,” so I’ll be naming my folder accordingly. The name is of little consequence to the rest of the tutorial, so if you’re feeling imaginative come up with your own name.
Step 2: Create the Flash File
Open up Flash CS3 or higher, and choose File > New and then select the ActionScript 3.0 option. This will be our Flash file for the project.
Save it to your project folder as “Drawr.fla” (or whatever name you feel is better).
Step 3: Create a Classes Folder and the Source Path
We will organize our class files into packages, but for further organization, let’s create a source path.
Create a folder in your project folder named “classes“. All of our classes (and package folders) will go in here.
In your Flash document, choose File > Publish Settings (on the Mac, Option-Shift-F12; on Windows Alt-Shift-F12). Click on the “Flash” tab, and then the “Settings…” button next to “Script: ActionScript 3.0″. Make sure the “Source path” tab is selected, and click on the “+” button. In the new entry, type “./classes“.
If you’d like to know more about this procedure, please refer to the “Source Paths” step of this OOP tutorial.
Step 4: Create the Document Class
We will, of course, be embracing class files in this tutorial, so no code in the FLA! Create a document class as our main point of entry into the application’s logic.
In the text editor of your choice, create a new file, and save it as “Drawr.as” in the classes folder. At this point, I recommend you follow my file- and class-naming instructions. It’s easy to get confused if your names differ, or if you copy code from the tutorial that makes use of different class names than what you’re using. I obviously can’t police that, but consider it a friendly and helpful suggestion.
Since this file is the document class, we have a few more sub-tasks to do. First, pop in some boilerplate code (if you used Flash Builder, almost all of this will be present already):
package {
import flash.display.Sprite;
public class Drawr extends Sprite {
public function Drawr() {
trace("Drawr has started.");
}
}
}
Now make sure that this document class is hooked up back in the Flash file. With nothing selected, open the Properties panel and enter “Drawr” in the “Class” field.
To make sure our files are playing nicely so far, choose Control > Test Movie to run the movie. You should see the trace in the Output panel:
Step 5: Create a UI
If you like, you can just use the starter FLA in the download package for the visual assets (in the “drawr-start” folder). Or you can create your own UI. Here’s what we need:
-
Three “tool” buttons, a la Flash or Photoshop’s tool buttons. Smallish in size, with some kind of icon to indicate the tool that will be activated when the button is selected. The three tools needed are:
- Rectangle button

- Oval button

- Brush button

For example, they might be arranged in Flash like so:
You can grab these straight out the FLA, or even by downloading the above images, which are PNG-24 images with an alpha channel.
-
A “canvas” area, which needs to primarily be an area of artwork on top of which we’ll draw. Even if you make the area transparent, make sure the area has pixels filled it; we’ll be use the MOUSE_DOWN event as a key ingredient to our drawing logic, and that event doesn’t fire for an InteractiveObject if the mouse isn’t over a pixel occupied by that InteractiveObject‘s pixels. Also, as a UI element, it’s helpful to have some kind of area defined visually to know where the drawing can happen.
All of these items should be MovieClips. Name these clips as so:
- Rectangle Button: rectangle_mc
- Oval Button: oval_mc
- Brush Button: brush_mc
- Canvas: canvas_mc
We’re going to need a number of classes to control even this minimal UI. As hinted at earlier, we will follow best practices and place our classes in packages. We’ll create the packages as we need them. In your classes folder, create a new folder called toolbar. We’ll keep toolbar-related classes here (obviously).
We’ll start with the Toolbar class. It’s responsibility will be to handle the UI side of things with the tools. Create a file called Toolbar.as in the toolbar package.
Put the following code in it:
package toolbar {
import flash.events.*;
import flash.display.*;
public class Toolbar extends EventDispatcher {
private var _target:Sprite;
public function Toolbar(target:Sprite) {
_target = target;
trace("Toolbar: " + _target);
}
}
}
Before we flesh this out, we need another class, the ToolbarButton. We’ll do that in the next step. For now, though, you may notice that I’m choosing to compose a Sprite rather than extending one. This is my personal preference, as I find it more flexible in the long run. You may feel differently, but please see this previous tutorial in the OOP series for a lengthy discussion on composition. Regardless, I encourage you to follow my lead on this, as trying to accomplish the same thing but with inheritance instead of composition will undoubtedly cause problems that will be difficult to resolve by comparing your code to mine.
Let’s make a quick test of the Toolbar class. First, in your FLA, select the three tool bar buttons and press F8 to group them into a Symbol. Name the symbol something like “Toolbar”, but more importantly name the resulting instance “toolbar_mc“
Back in Drawr.as, let’s add code to instantiate a Toolbar. Added lines are highlighted below:
package {
import flash.display.Sprite;
import toolbar.Toolbar;
public class Drawr extends Sprite {
private var _toolbar:Toolbar;
public function Drawr() {
_toolbar = new Toolbar(toolbar_mc);
}
}
}
And go ahead and test the movie; you should see a trace in the Output panel.
This class will be very simple, handling duties for a single button in the toolbar. Most importantly, it will carry with it a tool identifier so that a click on the button will ultimately result in the correct drawing behavior.
In the toolbar package, create a file named ToolbarButton.as. Place the following code in it:
package toolbar {
import flash.display.Sprite;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
public class ToolbarButton extends EventDispatcher {
private var _target:Sprite;
private var _toolType:String;
public function ToolbarButton(target:Sprite, toolType:String) {
_target = target;
_toolType = toolType;
_target.addEventListener(MouseEvent.ROLL_OVER, onOver);
_target.addEventListener(MouseEvent.ROLL_OUT, onOut);
_target.addEventListener(MouseEvent.CLICK, onClick);
}
private function onOver(e:MouseEvent):void {
// Perform roll over effect.
}
private function onOut(e:MouseEvent):void {
// Perform roll out effect.
}
private function onClick(e:MouseEvent):void {
dispatchEvent(e);
}
public function get toolType():String {
return _toolType;
}
}
}
All in all, pretty straight-forward. Take a Sprite and add some mouse interaction events to it. Also take a tool type String, and store it in a property while providing read-only access to it through a getter.
I’m not fussing over actual rollover and rollout effects for this tutorial. Feel free to put your own code in the appropriate methods.
We can now create the tool buttons from the Toolbar class. But we need a toolType to pass in. We could just make up string values, but it would be smarter to create some enumerated static constants (see my Quick Tip on static members). We can accomplish this by creating a very simple class.
Make a new class file called ToolType.as in the toolbar package. It just needs a few static constants. Type in the following:
package toolbar {
public class ToolType {
public static const RECTANGLE:String = "rectangle";
public static const OVAL:String = "oval";
public static const BRUSH:String = "brush";
}
}
We don’t even need a constructor; the sole purpose of this class is to carry with it the various string values that we’ll use to identify the various tool types.
Why not just put these constants on, say, the Toolbar class? I’m taking a page from Adobe’s book on this one. This class shares a similar responsibility to classes like StageScaleMode or BlendMode (both in the flash.display package). They just declare public static constants that have String values of the valid values for the Stage.scaleMode and DisplayObject.blendMode properties, respectively.
One reason to consider this approach rather than putting the constants on the Toolbar class (or the Stage or DisplayObject classes) is that there’s a good chance we’ll want to access these values without actually caring about the Toolbar class. This lets us use the “type” class without worrying about a class with greater functionality. This simulates an enumerated type, which ActionScript does not have, and lets the class simply focus on enumeration of valid values. This enumeration can be easily used in multiple places, then.
Now we have some supporting cast members, and we can let Toolbar take center stage. We’ll fill it out to create ToolbarButton objects, passing tool type values and hooking up events. Open Toolbar.as and make the changes highlighted below (including the removal of the trace() line that was there before):
package toolbar {
import flash.display.*;
import flash.events.*;
public class Toolbar extends EventDispatcher {
private var _target:Sprite;
public function Toolbar(target:Sprite) {
_target = target;
var rect:ToolbarButton = new ToolbarButton(_target.getChildByName("rectangle_mc") as Sprite, ToolType.RECTANGLE);
var oval:ToolbarButton = new ToolbarButton(_target.getChildByName("oval_mc") as Sprite, ToolType.OVAL);
var brush:ToolbarButton = new ToolbarButton(_target.getChildByName("brush_mc") as Sprite, ToolType.BRUSH);
rect.addEventListener(MouseEvent.CLICK, onToolClick);
oval.addEventListener(MouseEvent.CLICK, onToolClick);
brush.addEventListener(MouseEvent.CLICK, onToolClick);
}
private function onToolClick(e:MouseEvent):void {
trace("Tool click: " + e.target.toolType);
}
}
}
Still nothing too elaborate, but let’s recap. First, we create three buttons. There’s a pattern to how they get instantiated, so understanding one means you understand them all. If you recall, the ToolbarButton class takes two arguments to its constructor. The first is a Sprite, so we get the button symbol instances and pass them in. Note that we need to cast the result of getChildByName() as a Sprite because the result is a DisplayObject but we need to pass in a Sprite. The second argument is a String denoting the tool type, so here we use our ToolType enumeration class. So now we have three buttons, each associated with a Sprite and given a type.
Then we add CLICK events to each of the buttons. The handler for this simply (for now) traces out some information.
If you test your movie now, you should be able to click on the buttons and receive the traces.
Step 10: Dispatching Back to the Document Class
So far so good, but we can’t stop here. That click event ultimately needs to get back to the Drawr class, so that it can in turn do something with that information. For this, we’ll create a custom Event subclass to indicate a tool selection. It’s a common practice to put a project’s event classes into a single events package, and we’ll do the same. Create a folder called events in your classes folder.
Then create a new text file and save it as ToolbarEvent.as.
The code will be as follows:
package events {
import flash.events.Event;
public class ToolbarEvent extends Event {
public static const SELECT:String = "select";
private var _toolType = toolType;
public function ToolbarEvent(type:String, toolType:String, bubbles:Boolean=false, cancelable:Boolean=false) {
_toolType = toolType;
super(type, bubbles, cancelable);
}
public function toString():String {
return formatToString("ToolbarEvent", "type", "toolType");
}
public function clone():Event {
return new ToolbarEvent(type, toolType, bubbles, cancelable);
}
public function get toolType():String {
return _toolType;
}
}
}
If you worked through the previous tutorial where we built an image viewer, subclassing Event to create a custom event shouldn’t be anything new. Our main purpose for doing this is to create an event with a toolType property. It’s also handy to store the event type name in a static constant here, as well.
With this event class created, move back to Toolbar.as and import the ToolbarEvent class:
package toolbar {
import events.ToolbarEvent;
And modify the onToolClick method to remove the trace and dispatch a ToolbarEvent:
private function onToolClick(e:MouseEvent):void {
dispatchEvent(new ToolbarEvent(ToolbarEvent.SELECT, e.target.toolType));
}
The final task in this step is to listen to this event from the Drawr class. In that class, import the ToolbarEvent class and add an event listener to the Toolbar object:
package {
import events.ToolbarEvent;
import flash.display.Sprite;
import toolbar.Toolbar;
public class Drawr extends Sprite {
private var _toolbar:Toolbar;
public function Drawr() {
_toolbar = new Toolbar(toolbar_mc);
_toolbar.addEventListener(ToolbarEvent.SELECT, onToolbarSelect);
}
private function onToolbarSelect(e:ToolbarEvent):void {
trace("Toolbar select: " + e.toolType);
}
}
}
This will only slightly modify the behavior for right now; but if you’re still getting the trace when you test the movie, then you’re successfully dispatching from the Toolbar object to the document class. We’ll come back to this in just a bit.
Step 11: Create A Canvas Class
We’ll move on to the other key piece of the UI, the area where we will draw the artwork. Create another package (folder) called canvas in the classes folder.
Next, create a new ActionScript file and save it as Canvas.as in the newly-created “canvas” folder.
Enter the following code:
package canvas {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class Canvas {
private var _target:Sprite;
public function Canvas(target:Sprite) {
_target = target;
_target.addEventListener(MouseEvent.MOUSE_DOWN, onCanvasDown);
}
private function onCanvasDown(me:MouseEvent):void {
trace("onCanvasDown");
_target.stage.addEventListener(MouseEvent.MOUSE_MOVE, onCanvasMove);
_target.stage.addEventListener(MouseEvent.MOUSE_UP, onCanvasUp);
}
private function onCanvasMove(me:MouseEvent):void {
var newX:Number = _target.mouseX;
var newY:Number = _target.mouseY;
trace("onCanvasMove: " + newX + ", " + newY);
}
private function onCanvasUp(me:MouseEvent):void {
trace("onCanvasUp");
_target.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onCanvasMove);
_target.stage.removeEventListener(MouseEvent.MOUSE_UP, onCanvasUp);
}
}
}
We’ll be working in this class quite a bit over the course of the tutorial, but for now, the idea is to get some key functionality going. The drawing logic will take place on the canvas, but only after the user clicks the mouse down on the canvas. So the first thing we set up is a MOUSE_DOWN listener on the canvas target (notice that we’re using composition again, not inheritance. This object will have a Sprite).
In that MOUSE_DOWN listener, we add two more events: MOUSE_MOVE and MOUSE_UP. We don’t want these events to fire at any old time, otherwise we might be drawing just because the mouse moved, whether or not a click on the canvas occurred. So we add these events after the MOUSE_DOWN occurred.
In the MOUSE_MOVE listener, for now we’re just getting the position of the mouse relative to the canvas Sprite, and tracing it out. We’ll be doing a lot more here shortly.
Finally, in the MOUSE_UP handler, the important thing to do, considering that our drawing is done at this point, is to remove those MOUSE_MOVE and MOUSE_UP listeners, leaving just the MOUSE_DOWN listener, which can start the process over again.
This is good stuff, but there’s nothing to test yet. We need to create a Canvas object first. That’s next.
Step 12: Create the Canvas Object
Hop back to the Drawr class, and add the highlighted lines in the following code:
package {
import canvas.Canvas;
import events.ToolbarEvent;
import flash.display.Sprite;
import toolbar.Toolbar;
public class Drawr extends Sprite {
private var _canvas:Canvas;
private var _toolbar:Toolbar;
public function Drawr() {
_canvas = new Canvas(canvas_mc);
_toolbar = new Toolbar(toolbar_mc);
_toolbar.addEventListener(ToolbarEvent.SELECT, onToolbarSelect);
}
private function onToolbarSelect(e:ToolbarEvent):void {
trace("Toolbar select: " + e.toolType);
}
}
}
We’re just importing the class, creating a property, and instantiating a Canvas object into that property; should be pretty straight-forward so far.
Go ahead and test the movie. Once running, click and drag in the canvas area. You should get a whole bunch-o-traces.
We have our basic Canvas, now how do we draw into it? Let’s think about the general mechanics of drawing, say, a rectangle.
Let’s divide the phases of drawing a rectangle into three distinct phases. First, there is the start phase. It’s not until this phase happens that we actually begin drawing (you could say that there is a phase before the start phase, called the not doin’ nuthin’ phase). The second phase is the drawing phase; here, we’re moving the mouse around to draw temporary rectangles as we settle on the rectangle we actually want. Finally, we have the commit phase. This is where we finally choose the rectangle that we want.
The perceptive among you will have noticed that these three phases align nicely with the three events that we’ve set up in the Canvas class: the MOUSE_DOWN event coincides with the start phase, and in that event handler we need to perform any set up we need to start drawing. The drawing phase is matched to the MOUSE_MOVE event, where we move the mouse around and try to get the size of our rectangle right. And the MOUSE_UP event corresponds to the commit phase; once the mouse button goes up, we’re done drawing and we have our rectangle.
In rather general terms, then, here’s what we need to do in each of those phases/events.
- start: As one corner of the rectangle is always anchored to the mouse position at this phase, we need to capture the mouse position in the
MOUSE_DOWN event and cache it in a variable for later use.
- drawing: The opposing corner of the rectangle follows the mouse around during this phase. We need to continually update the drawn rectangle based on the continually updating location. It’s important to note that that means we’re actually drawing shapes in this phase. We’ll be using ActionScript’s drawing API to accomplish this.
- commit: There’s actually not too much to do here, other than clean up our event handlers (as already mentioned in a few steps ago in regards to the
Canvas class). The shape is already drawn from the drawing phase, we just need to stop drawing and leave the shape be. However, you may note that Flash’s drawing tools have a “lightweight” outline drawn during the drawing phase, which then get properly rendered with fills and strokes once committed. So, it’s conceivable that you might want to perform a simple drawing routine in the drawing phase and draw it “for real” in the commit phase. We won’t be doing that, but I thought I’d mention the possibility.
Now, think about an oval tool. What kinds of drawing phases would we have with drawing ovals? If you said “exactly the same kind,” then you’re some kind of wizard, because that’s correct. The above three steps could just as easily apply to drawing ovals, or for that matter, lines, or most any geometric shape like stars or regular polygons. The only real difference will be the logic for the drawing of the shape, during the drawing phase.
Step 14: Can We Just Make A Big if Statement?
…in the MOUSE_MOVE handler and draw different shapes accordingly? Sure, we could. But that’s not a terribly object-oriented approach to the problem at hand.
What if we had different objects for each tool? A RectangleTool class, an OvalTool class, etc? Then we can encapsulate the logic of drawing a specific tool into a single class, and keep Canvas related logic separated. The Canvas object can retain a property of the “current tool object” and defer the drawing logic to that object. The current object can get updated whenever it’s appropriate — say, when you click on one tool or another. This strategy sounds appealing (at least, it does to me, and I’m hoping that, by now, it does to you as well).
But this creates a different problem. If there is a single “current tool object” property in the Canvas object, how can we possibly put various different datatypes into it; that is, how do to we type the property so that it can receive both the RectangleTool and the OvalTool objects as values? Not to mention other tools that may eventually get built?
The answer is interfaces, and despite my dramatic build up, that shouldn’t be surprising given the topic of this tutorial. If we can define an interface that more generically declares methods that can be called by the Canvas class, then we can use the interface as the datatype for the “current tool object” in Canvas, and make sure each actual tool object implements the interface.
Sound good? Of course it does (if it doesn’t, try re-reading this step. If it still doesn’t make sense after that, then try taking a leap of faith and forge ahead with the tutorial; it will probably make more sense as we build it out bit-by-bit).
Step 15: Creating the Interface
Create another package in the project, this time called tools. This will be conceptually different than classes in the toolbar package: toolbar classes are UI elements; tools classes will involve logic surrounding drawing things on the canvas.
Create a new text file and save it to the tools folder as ITool.as.
This will be our interface file, and so it won’t be too lengthy:
package tools {
import flash.display.DisplayObject;
public interface ITool {
function mouseDown(x:Number, y:Number, fillColor:uint):void;
function mouseMove(x:Number, y:Number):void;
function mouseUp(x:Number, y:Number):void;
function get art():DisplayObject;
}
}
We will utilize those three phases in the first three methods: mouseDown, mouseMove, and mouseUp. Each will expect the mouse’s x and y position. The mouseDown method will also get passed the fill color to use.
There is an extra method in here that we haven’t really discussed yet, but I’m adding it in here to avoid having to add it in later. We’ll get to it momentarily, but a quick description of it is that the tool actually creates the artwork, and the Canvas will retrieve that artwork as a “layer” for it to display.
Let’s put this interface to work. Create a new class called RectangleTool in the tools package (that is, create a “Rectangle.as” file in the “tools” folder).
We can stub in a basic class. Because we’ll be implementing ITool, we can make sure we get the required methods in place, even if they’re empty.
package tools {
import flash.display.*;
public class RectangleTool implements ITool {
public function RectangleTool() {
}
public function mouseDown(x:Number, y:Number, fillColor:uint):void {
trace("mouseDown: " + x + ", " + y + ", " + fillColor.toString(16));
}
public function mouseMove(x:Number, y:Number):void {
trace("mouseMove: " + x + ", " + y);
}
public function mouseUp(x:Number, y:Number):void{
trace("mouseUp: " + x + ", " + y);
}
public function get art():DisplayObject {
return new Shape();
}
}
}
While we’re not really doing anything in this class, we’ve at least fulfilled the contract of ITool and created the methods required. We’ll get to a more practical implementation in a moment, but our next task will be to put this RectangleTool to use.
Because the Canvas receives the mouse events, it’s the object that needs to tell the RectangleTool about those three phases. And because the Drawr object is the one that’s receiving events from the Toolbar object when a tool is selected, we can use the Drawr class to tell the Canvas which tool to use.
For this to happen, the Canvas needs a public property (or a private property with a public setter and getter) that holds a reference to the RectangleTool. It then needs set by the Drawr when a tool is selected.
In Canvas.as, add the following highlighted lines. Note that I’ve also removed the three traces that were in this file previously.
package canvas {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import tools.ITool;
public class Canvas {
private var _target:Sprite;
private var _currentTool:ITool
public function Canvas(target:Sprite) {
_target = target;
_target.addEventListener(MouseEvent.MOUSE_DOWN, onCanvasDown);
}
private function onCanvasDown(me:MouseEvent):void {
if (!_currentTool) return;
_target.stage.addEventListener(MouseEvent.MOUSE_MOVE, onCanvasMove);
_target.stage.addEventListener(MouseEvent.MOUSE_UP, onCanvasUp);
_currentTool.mouseDown(_target.mouseX, _target.mouseY, 0xFF0000);
}
private function onCanvasMove(me:MouseEvent):void {
var newX:Number = _target.mouseX;
var newY:Number = _target.mouseY;
_currentTool.mouseMove(newX, newY);
}
private function onCanvasUp(me:MouseEvent):void {
_target.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onCanvasMove);
_target.stage.removeEventListener(MouseEvent.MOUSE_UP, onCanvasUp);
_currentTool.mouseUp(_target.mouseX, _target.mouseY);
}
public function get currentTool():ITool {
return _currentTool;
}
public function set currentTool(value:ITool):void {
_currentTool = value;
}
}
}
All of these changes center around adding a new _currentTool property. The import, property declaration, and setter and getter shouldn’t require any explanation. The other lines involve using the _currentTool property. And what’s going on here shouldn’t be a big surprise; we’re just calling the three “phase” methods at the appropriate times according to user interaction. As a side note, we’re also checking — on line 20 — for the existence of a _currentTool object before proceeding with all of this. If it doesn’t exist, don’t add any event listeners or call any methods on the _currentTool property, because we’d get errors if we did.
But we can’t test just yet; we need that _currentTool property to be set before we see anything new. So, in Drawr.as, add this bit of code to the onToolbarSelect method:
private function onToolbarSelect(e:ToolbarEvent):void {
trace("Toolbar select: " + e.toolType);
_canvas.currentTool = new RectangleTool();
}
And you’ll want to import not just the RectangleTool class, but pretty much anything in the tools package.
import tools.*;
Now go ahead and test the movie. Click on the rectangle tool button (or any of the tools, to be fair), and then “draw” in the canvas area. You won’t see any rectangles show up, but you’ll see the traces from the RectangleTool class show up.
To recap what’s happening, we’re supplying the Canvas object with an ITool object. It happens to be the RectangleTool right now. So when the mouse events occur, and Canvas is responding to them, it also asks the ITool object to do its thing, by calling methods on them. This will get more fleshed out as we go along, so if it’s not making sense right now, try to follow the sequence of events through the lines of code in the various classes. If it is making sense, but just seems like too much work for too little result, just hang in there. The grand scheme has yet to be revealed.
Step 18: Drawing a Rectangle
Open up RectangleTool.as again. Remove the traces, and replace them with the following code:
package tools {
import flash.display.*;
import flash.geom.Point;
public class RectangleTool implements ITool {
private var _art:Shape;
private var _fillColor:uint;
public function RectangleTool() {
}
public function mouseDown(x:Number, y:Number, fillColor:uint):void {
_art = new Shape();
_art.x = x;
_art.y = y;
_fillColor = fillColor;
}
public function mouseMove(x:Number, y:Number):void {
_art.graphics.clear();
_art.graphics.beginFill(_fillColor, 1);
_art.graphics.drawRect(0, 0, x-_art.x, y-_art.y);
}
public function mouseUp(x:Number, y:Number):void{
}
public function get art():DisplayObject {
return _art;
}
}
}
And there is one more task to do before we’ll actually see something. We need to get the art object out of the RectangleTool and into the Canvas. In Canvas.as, add one line of code to the onCanvasDown method:
private function onCanvasDown(me:MouseEvent):void {
if (!_currentTool) return;
_target.stage.addEventListener(MouseEvent.MOUSE_MOVE, onCanvasMove);
_target.stage.addEventListener(MouseEvent.MOUSE_UP, onCanvasUp);
_currentTool.mouseDown(_target.mouseX, _target.mouseY, 0xFF0000);
_target.addChild(_currentTool.art);
}
In our app’s current condition, once we set the Canvas‘ _currentTool to a RectangleTool object, this is the sequence of events:
- Nothing happens until a
MOUSE_DOWN on the Canvas.
- At this point, we tell the
RectangleTool to execute its mouseDown method.
- The
RectangleTool then creates a Shape object, sets its position, and also stores the fillColor for later use.
- The
Canvas object is still executing the MOUSE_DOWN handler; it then requests the art object from the RectangleTool
object and adds it to its display list.
- We’re done for now, until a
MOUSE_MOVE event happens.
- In the
MOUSE_MOVE handler, the Canvas forwards along the current mouse coordinates to the RectangleTool.
- The
RectangleTool then uses this new location, along with the original location of the mouse at MOUSE_DOWN (stored in
_art.x and _art.y), to draw the rectangle.
- The
MOUSE_UP event eventually fires, at which point we stop drawing and leave the drawn rectangle as is.
- If you then click again, the
MOUSE_DOWN event fires again, repeating Steps 2-8, resulting in another rectangle.
And we can draw rectangles!
We still haven’t seen the advantage of the ITool interface yet, but we’re getting there soon.
Step 19: Drawing an Oval
Let’s take it to the next level and introduce a second drawing tool: the Oval.
In the tools package, create a new class called OvalTool and add the following code:
package tools {
import flash.display.*;
import flash.geom.Point;
public class OvalTool implements ITool {
private var _art:Shape;
private var _fillColor:uint;
public function OvalTool() {
}
public function mouseDown(x:Number, y:Number, fillColor:uint):void {
_art = new Shape();
_art.x = x;
_art.y = y;
_fillColor = fillColor;
}
public function mouseMove(x:Number, y:Number):void {
_art.graphics.clear();
_art.graphics.beginFill(_fillColor, 1);
_art.graphics.drawEllipse(0, 0, x-_art.x, y-_art.y);
}
public function mouseUp(x:Number, y:Number):void{
}
public function get art():DisplayObject {
return _art;
}
}
}
You may notice that this class bears a strong resemblance to the RectangleTool class. The logic is near identical; aside from having to rename the class and constructor to OvalTool, the only difference is in mouseMove, where, instead of calling _art.graphics.drawRect, we call _art.graphics.drawEllipse.
If you’d like to test it out right now, you can hop over to the Drawr class and in the onToolbarSelect method, set the _canvas.currentTool to a new OvalTool() instead of a new RectangleTool(). You could alternatively wait until you get through the next step, because we’ll be focusing on properly setting the currentTool next.
Of course, what we have is far from ideal. We have three tool buttons, we need three tools. Well, we have two tools now, so it’s time to work out how to select those tools appropriately.
Drawr‘s responsibility will be to translate between the tool selection event and the actual ITool we need. Open up Drawr.as and locate the onToolbarSelect method. Remove the code currently there and replace it with this:
private function onToolbarSelect(e:ToolbarEvent):void {
switch (e.toolType) {
case ToolType.RECTANGLE:
_canvas.currentTool = new RectangleTool();
break;
case ToolType.OVAL:
_canvas.currentTool = new OvalTool();
break;
default:
_canvas.currentTool = null;
}
}
We also need to import the ToolType class. Add the following import line towards the top of the file, with the rest of the imports:
import toolbar.ToolType;
And now for the exciting test. Go ahead and run the movie. Click the Rectangle tool, and draw. You should get a rectangle. Then click the Oval tool, and draw again. It should be an oval. Well done!
There is one more tool to create (at least, for the purposes of this tutorial). This one will be quite different. If you happened to think that the RectangleTool and OvalTool classes were so similar that perhaps we were going about this all wrong, then our next tool class will be a big enough departure to convince you that separate classes for each tool are the way to go.
However, even though the underlying logic will be radically different, we still have the same three-phase approach to the task of drawing. Drawing a brush stroke still doesn’t start until MOUSE_DOWN, and then gets updates with each MOUSE_MOVE, and terminates with MOUSE_UP. It’s just what we actually do in those three phases will be different.
This is perfect for our interface. We have an interface that defines those phases, but implementations that does unique things with the phases.
With that in mind, create a BrushTool.as file in the tools folder, and add the following code:
package tools {
import flash.display.*;
import flash.geom.*;
public class BrushTool implements ITool {
private var _bitmap:Bitmap;
private var _bmd:BitmapData;
private var _brushStroke:Shape;
public function BrushTool() {
_bmd = new BitmapData(500, 500, true, 0x00000000);
_bitmap = new Bitmap(_bmd);
}
public function mouseDown(x:Number, y:Number, fillColor:uint):void {
_brushStroke = new Shape();
var gradBox:Matrix = new Matrix();
gradBox.createGradientBox(20, 20, 0, 0, 0);
_brushStroke.graphics.beginGradientFill(GradientType.RADIAL, [fillColor, fillColor], [1, 0], [127,255], gradBox)
_brushStroke.graphics.drawCircle(10, 10, 10);
var m:Matrix = new Matrix();
m.translate(x-10, y-10)
_bmd.draw(_brushStroke, m);
}
public function mouseMove(x:Number, y:Number):void {
var m:Matrix = new Matrix();
m.translate(x-10, y-10)
_bmd.draw(_brushStroke, m);
}
public function mouseUp(x:Number, y:Number):void {
}
public function get art():DisplayObject {
return _bitmap;
}
}
}
As you can see, that code is quite different. I won’t spend a lot of time explaining it, as dealing with BitmapData isn’t the focus of this tutorial (although I am planning an introduction to BitmapData in the near future, so if you find this intriguing, stay tuned). The general premise, however, is that we have a Bitmap object as our art object. Rather than drawing with the drawing API like we did with the geometric rectangles and ovals, we’ll work with pixels for the brush.
The bitmap logic involves cloning the pixels of a “brush tip” (called _brushStroke) into the BitmapData object. The _brushStroke is just a circle with a gradient fill, that is solid in the center and transitions to completely transparent at the edges, like a feathered brush in Photoshop. By copying this art over and over into the bitmap’s pixels, we get the impression of a continuous line.
The illusion isn’t as nice as Photoshop’s is, of course; if you move the mouse fast you’ll see the individual brush strokes. This can be addressed with more logic and math, but to keep things from getting out of control, we’ll stick with this more rudimentary implementation.
Now, to make this work, we need to expand the scope of the onToolbarSelect method in Drawr. Add the highlighted lines:
private function onToolbarSelect(e:ToolbarEvent):void {
switch (e.toolType) {
case ToolType.RECTANGLE:
_canvas.currentTool = new RectangleTool();
break;
case ToolType.OVAL:
_canvas.currentTool = new OvalTool();
break;
case ToolType.BRUSH:
_canvas.currentTool = new BrushTool();
break;
default:
_canvas.currentTool = null;
}
}
Test it out; you should have a brush tool not unlike the brush tool you know from Photoshop.
Step 22: Choosing a Fill Color
So far, we’ve made a point of specifying a fill color, but have hard-coded it to that bold red. Allowing the user to change the colour is relatively simple, and before we close down for the day we’ll make it happen.
In your FLA, open up the components panel by choosing the Window > Components menu item (or by pressing Command/Control-F7).
Locate the ColorPicker component, and drag it out on to the stage, underneath the toolbar (location isn’t too important so long as it’s not on top of the canvas area).
Give the ColorPicker an instance name of fillColorPicker.
Open up the Canvas class and add a _fillColor property and matching public set/get functions.
private var _fillColor:uint;
[firstline="48"]
public function set fillColor(color:uint):void {
_fillColor = color;
}
public function get fillColor():uint {
return _fillColor;
}
Change the hard-coded 0xFF0000 to use the _fillColor property instead:
_currentTool.mouseDown(_target.mouseX, _target.mouseY, _fillColor);
And finally, add the following code to the Drawr class:
package {
import canvas.Canvas;
import events.ToolbarEvent;
import flash.display.Sprite;
import flash.events.Event;
import toolbar.Toolbar;
import toolbar.ToolType;
import tools.*;
public class Drawr extends Sprite {
private var _canvas:Canvas;
private var _toolbar:Toolbar;
public function Drawr() {
_canvas = new Canvas(canvas_mc);
_toolbar = new Toolbar(toolbar_mc);
_toolbar.addEventListener(ToolbarEvent.SELECT, onToolbarSelect);
fillColorPicker.addEventListener(Event.CHANGE, onFillColorChange);
}
private function onToolbarSelect(e:ToolbarEvent):void {
switch (e.toolType) {
case ToolType.RECTANGLE:
_canvas.currentTool = new RectangleTool();
break;
case ToolType.OVAL:
_canvas.currentTool = new OvalTool();
break;
case ToolType.BRUSH:
_canvas.currentTool = new BrushTool();
break;
default:
_canvas.currentTool = null;
}
}
private function onFillColorChange(e:Event):void {
_canvas.fillColor = fillColorPicker.selectedColor;
}
}
}
If you test the movie now, you should be able to change the fill color of the current tool by using the component.
Step 23: Reviewing the System
In retrospect, the system probably seems pretty sleek. Consider what it would take to add a new tool. Of course, there are the the UI considerations: you’ll need a new button, you’ll need to update Toolbar to accommodate it, and you’ll need to add a new enumeration to ToolType.
In terms of implementing the tool, though, you have one clear-cut task: implement ITool. If you did it faithfully, you should be good to go. Yes, you’ll need to update onToolbarSelect to create the new tool at the right time. The the arguably trickier logic of actually drawing will get encapsulated into its own class. You don’t need to worry about hooking up mouse events; the “phase” methods get called automatically. You just need to take the given information and draw with it.
Compare that to how it might go down without the interface; if we had implemented the big if statement we discussed above. Well, obviously, that big if statement will get bigger, and probably harder to maintain. It’s likely you’ll try to share variables or forget that a variable set earlier needs to remain set at the value before you change it for the new tool. There’s any number of things that could happen to create a mess at this point. This particular technique of separating the raw interaction logic from the individual drawing logic should help protect against introducing errors alongside new features.
It’s not necessarily any less work or fewer lines of code to use interfaces versus not, but the focus of the work is sharper, meaning you can execute the work more confidently in less time. We also have clearly defined responsibilities for each object, making bugs easier to locate.
Step 24: That Last Step is a Doozy
Not only do we have the advantages outlined in the previous step, but you have now been furtively introduced to Design Patterns. Now, that’s a terrible thing to bring up in the last step of a tutorial, because it’s a subject that’s amazingly (and rewardingly) deep. To give a nickel tour of design patterns, they are solutions to common problems in programming, specifically using Object-Oriented techniques. They are typically regarded as “the next thing” to master once you become comfortable with OOP on more general level.
For example, a common problem is the need to use different algorithms. The Strategy pattern is a generic approach to a solution. In our drawing application, we need different drawing algorithms based on the selected tool. The Strategy pattern tells us that we can treat each individual algorithm as its own class, and all algorithm classes should implement the same interface — just as we did with the three tools’ classes and the ITool interface. The “Context” class (the consumer or client of the algorithms) then uses one algorithm class or another to actually complete its own task.
The beauty of the Strategy pattern, though, is the ease with which the algorithm can be swapped out with a different one, as illustrated with the selection of tools in our drawing app.
The applications of this particular pattern are endless, and that’s just one pattern. There are plenty of other design patterns that are just as useful. This subject is, naturally, worth several tutorials, and explaining it all in a few paragraphs is really an injustice. I just wanted to mention it, because I rather intentionally designed the drawing app around not only the use of interfaces, but the Strategy pattern. I hope the topic is intriguing enough to warrant further exploration on your own. I just wanted to plant a seed.
Conclusion
And that wraps up our discussion on interfaces! They are one of the more obtuse concepts in Object-Oriented Programming, and nobody will fault you for not mastering them right away. But I hope that, through this more practical application, you’ve come to grips with the value of interfaces, even if just a little bit. Thanks for sticking it out and reading this tutorial.



View full post on Activetuts+