Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Flex Developer Center /

Building a game with Flash Builder using the Cairngorm framework-Part 1: Displaying the board and processing player moves

by Nick Avgerinos

Nick Avgerinos
  • blogs.adobe.com/adobearcade
  • axcella.com/~nicka

Created

21 December 2009

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Flex gaming

Requirements

Prerequisite knowledge

  • Working knowledge of Struts.
  • Basic knowledge of Flex.

User level

Beginning

Required products

  • Flex Builder (Download trial)

Sample files

  • flex_struts_sample.zip (1978 KB)

Note: This article was created basedon Flash Builder 4 beta. Minor changes in the description and code maybe necessary before it can be applied to Flash Builder 4.

Due to the ubiquity of Adobe Flash Player, the Adobe Flash Platform is the most popular global platform for building games. Adobe Flash is also increasingly being used in the enterprise community to develop RIAs. As a result, developers with a wide range of skill sets and expertise are developing for the Flash Platform.

In this article, I'll highlight concepts many RIA developers may already be familiar with (the Flex and Cairngorm frameworks) and describe how they can be used to build a simple four in a row game.

This is the beginning of a three part series. In this first part, you'll learn how to:

  • Import graphics built in Flash CS4 to create the game board
  • Create an MVC framework to represent the game components
  • Handle mouse events to process the player's moves

In Part 2, you'll update the game to add the game logic. You'll extend the game's features to detect when a player has won (or determine that there are no possible winning moves remaining). In Part 3, you'll take the game one step further by adding some simple artificial intelligence (AI) that allows a single user to play the game with the computer.

Building the game board

The sample project you'll build in this article is a simple four-in-a-row style game. The game board is comprised of rows and columns. Players take alternating turns by dropping a chip of their color (in this example, red or black) in a column. The chip lands in the lowest empty position in the column, stacking on top of previously played chips, if applicable. Only one player's chip can be contained in any one cell, and once a move is made the chip cannot be moved. The first player to line up four of their colored chips, aligned in a row, column or diagonal, is the winner.

In this first section, you'll begin by creating a new project. Then you'll import board images from a SWF file and draw the game board on the Stage.

Starting a new project

Follow these steps to begin building the new game project:

  1. Launch Flash Builder 4.
  2. Choose File > New > Project. In the New Project dialog box that appears, name the new project: FourInARow. Set the Application type to Web and choose the Flex 3.4 SDK option. Click Finish.
  3. Download Cairngorm. I used build 2.2.1 for this project. Newer versions should work, but note that they are untested.
  4. Copy the Cairngorm.swc file, which you downloaded with Cairngorm in the previous step to your new project in the libs directory.

Creating the MVC structure

If you're not familiar with the Cairngorm framework, it follows MVC (Model-View-Controller) design patterns common in many RIAs. You can use the same approach to develop games like the one described in this article. The Model keeps track of the game state (whose turn it is and what moves have been made). In part two of this series, the Model is also responsible for determining when the game is over (when a player wins or when there are no more winning moves to be made). The View handles display of the game board, and the Controller processes game events (when a player starts a game or makes a move).

Start building the MVC structure by creating the following empty folders under the new project:

  • src/assets
  • src/control/commands
  • src/control/events
  • src/model
  • src/view

Creating the board model

The game board for a four-in-a-row style game is comprised of a two dimensional grid. The traditional version of the game contains 6 rows and 7 columns. This version is more customizable to make things a little more interesting—you'll create an interface to allow the user to choose the number of rows and columns, as well as choosing the number of chips that must match in a row to win.

The board model tracks the moves that have been played so far on the board. A simple array is used to keep an internal map of where each player's chips are positioned on the board. The index of the array makes it possible to reference each position on the board by starting at the bottom left corner of the game board, then increasing from left to right to fill out the entire row before moving up to the next row.

You can use the following function to locate any position in the game board array by its row and column number. The array index will store the number of the player who has a chip in that position.

index = (row * NUM_COLUMNS) + column

(This formula assumes your rows and columns start at 0.)

The following chart illustrates how each space on the board is indexed (see Figure 1):

file
Figure 1. Mapping the rows and columns of the game board to an array.

Adding a Board class
Follow these steps to add the code to create the game board model:

  1. Choose File > New ActionScript Class.
  2. Name the new ActionScript class Board under the model folder as shown below, and then click Finish (see Figure 2).
file
Figure 2. Creating the board model.
  •  Open the new class (AS file).
  • Add the following variables to represent the various items you'll track in the game:
public static const EMPTY:int = 0; // An empty position public static const INVALID_MOVE:int = -1; // An invalid move private var rows:uint; // Number of columns on the board private var cols:uint; // Number of rows on the board private var players:uint; // Number of players private var connect:uint; // How many in a row to win private var boardMap:Array; // Array of all the pieces that have been played
  • The only time any of the variables (rows, cols, players, connect) used to define the game settings should change is when a user begins a new game. Each time a new game is started, the Board class uses the values of the variables to recreate the boardMap. If the number of rows or columns changed in the middle of a game, it would invalidate the data in the Model. That is why the variables shown above are set to private. Other components of the game still need to access the variable values, so you'll need to add the following public accessor functions to the Board class.
  • Copy or paste this code:
public function getCols():uint { return cols; } public function getRows():uint { return rows; } public function getPlayers():uint { return players; } public function getConnect():uint { return connect; }

  • Next, you'll add the getMapIndex function. This function accepts a row and column number as the input and returns the position in the boardMap array that points to the location.

  • Copy or paste this code to add the getMapIndex function:

  • // Passed a row and column, returns the index in the boardMap array private function getMapIndex(r:uint, c:uint):uint { return (r * cols) + c; }

    Creating the ModelLocator

    If you've used the Cairngormframework before, this step should be familiar to you. If not, don'tworry. Just follow along. A ModelLocator in the Cairngorm framework isused as a global singleton repository to hold shared or global objects.You can think of the ModelLocator as a central place to store globalvariables and objects. In this game, the ModelLocator is the locationfor all the other components of the game; you'll use it to access thecentral instantiation of the board model. Follow these steps:

    1. Choose File > New ActionScript Class.
    2. Name the new ActionScript class ModelLocator under the model folder. It will implement the com.adobe.cairngorm.model.IModelLocator interface (see Figure 3).

    file
    Figure 3. Creating the ModelLocator class.

  •  Open the ModelLocator class (AS file) at this location: src/model/ModelLocator.as.
  • Type or paste the following code into the class file:

  • package model { import com.adobe.cairngorm.model.IModelLocator; [Bindable] public class ModelLocator implements IModelLocator { public var board:Board = new Board(); // board model public var playerTurn:uint = 1; // Which player's turn is it //********************************************************** // Singleton methods //********************************************************** /** * This returns and instance of the custom ModelLocator. * @return ModelLocator */ public static function getInstance() : ModelLocator { if ( __modelLocator == null ) { __modelLocator = new ModelLocator(new ConstructorBlock); } return __modelLocator; } /** * Default constructor. * @param block Private class required. * Prevents public, direct instantiation of multiple instances */ public function ModelLocator(block:ConstructorBlock) { if ( __modelLocator != null ) { throw new Error( "Only one ModelLocator instance should be instantiated" ); } __modelLocator = this; } // ********************************************************** // Singleton attribute // ********************************************************** private static var __modelLocator:com.adobe.games.fourinarow.model.ModelLocator = null; } } // Declared outside package so it can be used // to prevent direct construction of ModelLocator instances class ConstructorBlock { }

  • Next, you'll edit the FourInARow.mxml file (from the sample files folder) to instantiate the ModelLocator you just created.

  • Add the following code inside the <mx:Application> tag:
  • <mx:Script> <![CDATA[ import com.adobe.games.fourinarow.model.ModelLocator; private var __model:ModelLocator = ModelLocator.getInstance(); ]]> </mx:Script>

    Creating the board view

    While it is possible to create a game just using the board model, its not much fun to play unless you can actually see what is happening at each turn. In this section, you'll create a canvas that will draw the game board.

    To give the board some visual depth, the board itself will be drawn on two separate layers (front and back). A third layer in between those two will hold the chips that are played during the game. This approach simulates the appearance of the chips sitting inside the board. It also makes the animation look more convincing when a chip falls down into place. The following figure shows how the layers line up and how an individual cell on the board looks when a player's chip is held inside (see Figure 4).

    file
    Figure 4. Deconstructing the layer structure of the board view.

    The next task is to start creating the view. Follow these steps:

    1. Choose File > New MXML.
    2. Create a new MXML Component named boardCanvas under the view folder, based on mx.containers.Canvas (see Figure 5).

    file
    Figure 5. Creating a new MXML Component named boardCanvas.

  •  Open the MXML file.
  • Add the following code to create the three layers you'll need to draw the board:

  • <mx:Canvas id="backCanvas" x="0" y="50" width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off" /> <mx:Canvas id="chipCanvas" x="0" y="50" width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off" /> <mx:Canvas id="frontCanvas" x="0" y="50" width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off" />

  • Since the board is drawn dynamically, some programming is needed to draw out the elements. To create a simple board like the one required for a four in a row game, you could import bitmap images or even use the built-in drawing functions. However, for the purposes of this article, I'll demonstrate the process of importing elements from a SWF file. I've found this is a common workflow, because the design team often uses Flash CS4 to create the graphic assets for games.

  • Locate the file named board.swf in the sample files folder. Place a copy of the file in your src/assets directory.

    Note: The board.fla file that was used to create board.swf is also provided in the sample files folder for your reference, but you don't need it to follow along with these instructions.

  • To make a symbol in a Flash CS4 file accessible to your Flash Builder project, use the Library to access the symbol properties for the movie clip and make sure the option to Export for ActionScript is selected. You'll use the Class name you enter in the Symbol Properties dialog box (blackChip) to reference the symbol in Flash CS4 (see Figure 6).

  • file
    Figure 6. In the Symbol Properties dialog box, select the option to Export for ActionScript.

  • Temporarily minimize Flash CS4 and return to Flash Builder. Then follow these steps:

  • Open the boardCanvas.mxml file in Flash Builder.
  • Create an <mx:Script> block at the top of your boardCanvas.mxml file, and then add the following code to pull in the classes from the SWF file:

  • [Embed(source="assets/board.swf", symbol="BoardElementBack")] [Bindable] public var BoardElementBack:Class; [Embed(source="assets/board.swf", symbol="BoardElementFront")] [Bindable] public var BoardElementFront:Class; [Embed(source="assets/board.swf", symbol="redChip")] [Bindable] public var redChip:Class; [Embed(source="assets/board.swf", symbol="blackChip")] [Bindable] public var blackChip:Class;

  • Review the code above and notice that the symbol name in the Embed() function here exactly matches the name of the Class exported in the Flash CS4 file. To use the element in MXML, you'll create a new Image object and set its src value to the Class variable you created previously.

    Each cell in our game board is symmetrical and uses the same width and height.

  • Near the top of the <mx:Script> block, define the width and height values, like this:

  • private static const CELL_WIDTH:int = 80; private static const CELL_HEIGHT:int = 80;

  • Next, you'll add the code to connect to the ModelLocator in order to access the board model.

  • Use the helpful code completion functions available in Flash Builder to ensure that the ModelLocator class gets imported:

  • private var __model:ModelLocator = ModelLocator.getInstance();

    Create the drawBoard() function that handles sizing the Canvas and laying out the game board view. Add the following code:

    public function drawBoard():void { // Clear the board canvas chipCanvas.removeAllChildren(); backCanvas.removeAllChildren(); frontCanvas.removeAllChildren(); // Set the size of our main canvas this.width = 30 + (CELL_WIDTH * __model.board.getCols()); this.height = 80 + (CELL_HEIGHT * __model.board.getRows()); for (var r:int=__model.board.getRows()-1; r >= 0; r--) { // Loop through each row (bottom up to handle overlap) for (var c:int=__model.board.getCols()-1; c >= 0; c--) { // Loop through each col (right to left to handle overlap) // Create Back of cell var b:Image = new Image; b.source = BoardElementBack; // Create Front of cell var f:Image = new Image; f.source = BoardElementFront; b.x = f.x = 15 + (CELL_WIDTH * c); b.y = f.y = 15 + (CELL_HEIGHT * r); backCanvas.addChild(b); frontCanvas.addChild(f); } } }

    Double-check that the mx.controls.Image class is imported at the top of your <mx:Script> block:

    import mx.controls.Image;

    The process for drawing the board involves looping through each column for each row, to create the cell that holds a single player chip. Images for the front and back of the board are created and added to the appropriate Canvas layer. The virtual sides of the board are drawn as part of the front cell. To make sure everything overlaps properly, start by adding the objects to the right side of the board and moving left (to ensure that each cell is always layered on top of the one on its right).

    Setting up the view

    There are only a few things left in order to set up the view and get a graphic to appear on the Stage. In this game, the user gets to choose the number of rows and columns, and these are displayed dynamically. Later in this article series I'll provide the instructions to create the control panel used to set those values, but for now you need a way to set the initial default values. The constructor of the board model is a fine place to set those values for testing purposes.

    1. Open the file Board.as and add the following code to your Board constructor:

    public function Board() { rows = 6; cols = 7; players = 2; connect = 4; }
    1. Save the Board.as file.
    2. Return to your main application file, FourInARow.mxml.
    3. At this point, you can add the boardCanvas MXML object and a call to the drawBoard() function in the creationComplete event of your application. Update your FourInARow.mxml file to match the code example shown below:

    <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="1024" minHeight="768" xmlns:view="view.*" creationComplete="init();"> <mx:Script> <![CDATA[ private function init():void { board_C.drawBoard(); } ]]> </mx:Script> <view:boardCanvas id="board_C" x="25" /> </mx:Application>
    1. Save all your project files an run your game.

    After making these changes, you should see an empty game board displayed (see Figure 7).

    file
    Figure 7. The game board as it appears at this point in the project.

    Continue on to the next section of this article, where you'll add the code to begin allowing each player to take a turn when playing the game.

    Processing a player's move

    In the previous section of this article, you learned how to build the game board and display it on the screen. In this section, you'll add the functionality to process each move in the game when a player takes their turn. In the previous instructions, you created a model and a view. The next part involves creating a controller that handles the processing of game events, such as tracking the data when each player makes a move.

    Creating the PlayerMove Event

    Before you start building the controller, you'll create a CairngormEvent class to represent a player move event. The class will define the data that will be sent when the event occurs (for example, passing which player completed the move and which column they selected). Follow these steps:

    1. Choose File > New Class.
    2. Create a new ActionScript Class and name it PlayerMoveEvent. Save it under the control/events folder. The Superclass it inherits from is: com.adobe.cairngorm.control.CairngormEvent.

      It is common practice to define an EVENT_ID string to reference your event. This is the unique name for each of your Cairngorm events that makes it easy to tell which event was fired, in order to handle processing for it. It's also common to define variables that hold the player number and the column played.

    3. Open the PlayerMoveEvent.as file that exists at this location: control/events/PlayerMoveEvent.as. Update the ActionScript to match the code example shown below: 

    package control.events { import com.adobe.cairngorm.control.CairngormEvent; public class PlayerMoveEvent extends CairngormEvent { public static const EVENT_ID:String = 'playerMove'; public var player:uint; public var column:uint; public function PlayerMoveEvent() { super(EVENT_ID); } } }

    Next, you'll create a function in the view of the boardCanvas that will take as its input the number of the column that a player selects. Players take their turn by clicking on the board (the view), so it makes sense for the PlayerMoveEvent to be dispatched from the view.

    1. Update the code to match the example shown below, and notice how the number of the column, as well as the number of the player that made the move, are passed into the event.
    private function onPlayerSelectColumn(column:uint):void { if (column < __model.board.getCols()) { var event:PlayerMoveEvent = new PlayerMoveEvent(); event.player = __model.playerTurn; event.column = column; event.dispatch(); } }
    1. Make sure that the PlayerMoveEvent class is imported at the top of the script, like this:
    import control.events.PlayerMoveEvent;

    Detecting a player's move

    The game play takes place as follows: Players take their turn by clicking on the game board to indicate the column where they would like to place their chip. The chip will fall to the next available space, closest to the bottom). To reduce confusion, it's best to set up the code to ignore clicks that are too close to the edge of a column. Players must click near the center of the column they choose to place the chip. Follow these steps:

    1. Open the boardCanvas.mxml file.
    2. Review the code example below. Note that MouseEvent.stageX returns the position on the Stage where the click occurred. The function subtracts the x position of the boardCanvas (this.x) to determine where on the board canvas the click occurred. Next, it divides that value by the width of each column (and compensates for a little padding) to return the column number that was clicked. The conditional statement only processes the click if the user clicked near the center of the column (ignoring 15 pixels on either side).
    3. Add the following function to handle processing mouse click events:

    private function onMouseClick(e:MouseEvent):void { // Figure out which column (if any) we've clicked on var pos:int = e.stageX - this.x; var col:int; pos -= 15; // board offset if (pos > 0) { col = pos / 80; if ((15 < pos%CELL_WIDTH) && (pos%CELL_WIDTH < (CELL_WIDTH-15))) { trace(‘[boardCanvas] onMouseClick – col: ‘ + col); onPlayerSelectColumn(col); } } }
    The next step involves adding an event listener that will call the onMouseClick function.
    1. Create the init() function below, still in boardCanvas.mxml:
    private function init():void { addEventListener(MouseEvent.CLICK, onMouseClick); }
    1. Then, add the init() function to the creationComplete event in the <mx:Canvas> tag at the very top of your file, like this:
    <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" creationComplete="init();" >
    1.  Choose Run > Debug (Project Name).
    2. Run the game in debug mode, and click on the columns to test the code. 

    If everything is working as expected, you'll see the Debug console display a message every time you click on a column, to indicate which column was clicked. Spend some time testing the game, by clicking all over the board. As each message appears, verify that the number of the clicked column is correct. Also try clicking outside or on the edge of the columns to see what happens. When you click between two columns, the Debug console should not display a message, because the click is ignored. If your project is not functioning this way, check the code examples provided above or compare your version with the code in the provided sample files to make sure they match.

    Drop a Chip

    To complete this part of the project, there's one more function to add to the boardCanvas.mxml file; this function will display a player's chip on the board. To accomplish this, you first need to find an easy way to determine which color chip (red or black) is to be displayed. Since the player number is an integer (either 1 or 2), the player number can be used as an index for an ArrayCollection that contains the chip images for the players. Follow these steps:

    1. Open the boardCanvas.mxml file.
    2. Add an ArrayCollection variable near the top of the <mx:Script> block, and be sure to import the mx.collections.ArrayCollection class, like this:

    public var playerChips:ArrayCollection = new ArrayCollection();
    1. Add the following code inside the init() function to populate the new ArrayCollection with the player chips:
    // Set the chip colors for each player playerChips.addItem(null); playerChips.addItemAt(redChip, 1); playerChips.addItemAt(blackChip, 2);
    1. Add the dropChip() function that takes the player number, column number and row number as the input and displays the chip on the board:
    public function dropChip(p:uint, c:uint, r:uint):void { var newChip:Image = new Image; newChip.source = playerChips[p]; newChip.x = 15 + 30 + (CELL_WIDTH * c); newChip.y = (CELL_HEIGHT * (__model.board.getRows() - r)) - 30; chipCanvas.addChild(newChip); }
    1. In order to test that everything is working as expected, temporarily add the following lines at the bottom of the init() function in your FourInARow.mxml file, right after the call to board_C.drawBoard(), like this:
    board_C.dropChip(1, 3, 0); board_C.dropChip(2, 4, 0); board_C.dropChip(1, 4, 1);

    The placeholder code above calls the dropChip() function, as if the first three moves of a game have been played, and places three chips on the board.

    1. Run the game, to test it. You should see a board that looks like Figure 8.
    file
    Figure 8. Run the game to test the code and ensure that the chips are placed correctly.

    Important: Don't forget to delete those temporary calls you added in Step 3 before continuing on to the next part of this article.

    Checking for a valid move

    At this stage in the project, you've learned how to place chips on the view of the board, but the view does not contain data about the current state of the game—the status is controlled by the board model. If you click on the board in the view, you trigger an event that tells you which column was selected, but unless you check the board model data (to determine the current game's state) it is impossible to tell how far down the column (which row position) the chip dropped. Follow these steps to pass the data and complete the move (if it is a valid selection; the selected column could also be full).

    1. Create a new function in the Board.as file named playerMove.
    2. Add the following code that takes the value of a player and a column as an argument and determines the lowest empty row position on the board to display the player's chip:

    public function playerMove(player:uint, c:uint):int { for (var r:int=0; r < rows; r++) { var pos:uint = getMapIndex(r, c); if (boardMap[pos] == EMPTY) { // Found empty space // Mark player has placed a chip in this space boardMap[pos] = player; // Return the row that was played return r; } } return INVALID_MOVE; // No valid moves }

    The function above loops through each row on the board, starting with the bottom row, and searches for the first EMPTY position in the boardMap[] array.

    If an empty position is found, the function updates boardMap[] with the player number that made the move and returns the row that was played.

    If the function loops through to the end, it means that all rows in that column already have chips in them and there are no empty spaces. This means that the player made an invalid move by selecting that column, and a INVALID_MOVE (-1) value is returned.

    1. Update the code again. Since it is necessary to begin tracking actual moves in the model, initialize the boardMap[] array setting of each position to EMPTY, like this: 

    public function clearBoard():void { for (var i:int=0; i < (rows * cols); i++) { boardMap[i] = EMPTY; } }

    In the next section of this article series, you'll add the ability to reset the game and you'll call this function to clear the board model.

    1. For now, just initialize a new array and add a call to clearBoard() to the constructor, as shown below:

    public function Board() { rows = 6; cols = 7; players = 2; connect = 4; boardMap = new Array; clearBoard(); }

    Making the view accessible

    The controller must update both the board model and the view every time a player takes their turn. Although you could lookup the Stage object and try and hunt for the view, that's not always the ideal solution; you'd have to keep updating your code if you change where the boardCanvas is displayed. In a previous section, you learned that the ModelLocator is already being used to access to global board model, so it makes sense to also add a pointer to the view here. Follow these steps:

    1. Open the Board.as file located in the model folder.
    2. Update the Board.as code, to match the following code example:

    import view.boardCanvas; public class ModelLocator implements IModelLocator { public var board:Board = new Board(); public var boardView:boardCanvas; public var playerTurn:uint = 0;
    1. Open the FourInARow.mxml file.
    2. Update the init() function, to connect the boardCanvas to the ModelLocator:

    <mx:Script> <![CDATA[ import com.adobe.games.fourinarow.model.ModelLocator; private var __model:ModelLocator = ModelLocator.getInstance(); private function init():void { __model.boardView = board_C; board_C.drawBoard(); } ]]> </mx:Script>

    Creating the game controller

    At this point, the game dispatches a playerMoveEvent every time a player makes a move. The view responds and displays a chip on the board to represent the player's move. The model tracks the moves that have been played, to determine valid moves. In this section, you'll hook up the game controller to connect all of the pieces and create a game that you can begin playing.

    In the Cairngorm framework, a FrontController is used as the central place to process all CairngormEvents. In this game, the FrontController object is called the GameController. The GameController listens for all CairngormEvents that are broadcast. Whenever it receives a broadcast, it launches the designated command class to process it. At the moment, the game only has one event type to process, but as you continue to extend the game and add more functionality, more events and commands will be added. Follow these steps to create the GameController:

    1. Choose File > New Class.
    2. Create a new ActionScript class named GameController. Save it under the control folder. This class will inherit from its Superclass: com.adobe.cairngorm.control.FrontController.
    3. Add the following code to create the registerAllCommands function. This function adds a listener for the PlayerMoveEvent and registers the PlayerCommand class as the responder for those events. Your GameController.as file should look like this:

    package control { import com.adobe.cairngorm.control.FrontController; import control.commands.*; import control.events.*; public class GameController extends FrontController { public function GameController() { super(); registerAllCommands(); } private function registerAllCommands():void { // Register Player Moves addCommand(PlayerMoveEvent.EVENT_ID, PlayerCommand); } } }
    1. Create the PlayerCommand class to handle the actual processing of the event by creating a new ActionScript class under control/commands directory. Name the class: PlayerCommand (see Figure 9).
    file
    Figure 9. Creating the new PlayerCommand class.

    Unlike the previous classes you created that extend a Superclass, the PlayerCommand needs to have the following two Interfaces implemented:

    com.adobe.cairngorm.commands.ICommand mx.rpc.IResponder

    In every ICommand class that you implement, you'll need to add an execute() function. This function is called to respond to the event, and is passed a CairngormEvent object. An ICommand can respond to multiple event types, so inspect the event.type to determine the exact event that was passed. Cast the event for the specific type you are handling so you can access event-specific variables, such as player and column.

    1. Open the PlayerCommands.as file that exists in this location: control/commands/PlayerCommand.as.
    2. Type or paste in the following code:
    package control.commands { import com.adobe.cairngorm.commands.ICommand; import com.adobe.cairngorm.control.CairngormEvent; import control.events.PlayerMoveEvent; import model.Board; import model.ModelLocator; import mx.controls.Alert; import mx.rpc.IResponder; public class PlayerCommand implements ICommand, IResponder { private var __model:ModelLocator = ModelLocator.getInstance(); public function PlayerCommand() { } public function execute(event:CairngormEvent):void { switch (event.type) { case PlayerMoveEvent.EVENT_ID: onPlayerMoveEvent(event as PlayerMoveEvent); break; default: break; } } private function onPlayerMoveEvent(e:PlayerMoveEvent):void { var moveRow:int = __model.board.playerMove(e.player, e.column); if (moveRow == Board.INVALID_MOVE) { Alert.show(‘Sorry, that move is not valid.', 'Invalid Move', Alert.OK); } else { // Tell the view to place a chip __model.boardView.dropChip(e.player, e.column, moveRow); // Player turn over, increment/loop __model.playerTurn++; if (__model.playerTurn > __model.board.getPlayers()) __model.playerTurn = 1; } } public function result(data:Object):void { } public function fault(info:Object):void { } } }

    The onPlayerMoveEvent function controls what happens when a player makes their move. First, it updates the model to verify that the move that was made is valid; it also determines which row was played. If the move is valid, the player, column and row position data is passed to place a chip in the correct location on the board. The dropChip() function is called to update the view. Finally, the playerTurn variable is incremented to allow the next player to take their turn.

    To make everything work, you just need to load the GameController. Follow these steps:

    1. Open the FourInARow.mxml file.
    2. Add the following line of code inside the <mx:Application> tag:

    <control:GameController xmlns:control="control.*" />

    The line above is the last piece necessary to hook up the GameController code into your main application.

    1. Save all of the files and run the game. Test the game by clicking on a column. You should see a chip appear on the board in the correct position.

    As you continue to click, you'll see the chip colors alternate with each player's turn. If you fill up a column with chips and then select it again, an alert box appears to display the message that the move is not valid.

    Where to go from here

    In this article, you've learned how you can leverage familiar concepts from an RIA framework (Model-View-Controller) and use them to build a game.

    The four in a row game is far from complete at this point. Continue following along with part two of this article series (coming soon), where you'll use the files you've developed up to this point and create a working game with an interface. You'll learn how to add a control panel, sound and animation; you'll also incorporate detection logic to indicate when the game is over. In part three of this series, you'll finish this project by adding logic to allow the user to play the game and compete against the computer.

    To learn more about developing with the Cairngorm framework, see the following online resources:

    • Introducing Cairngorm
    • Developing Flex RIAs with the Cairngorm microarchitecture
    • Cairngorm on Adobe Open Source


    This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 Unported License.

    More Like This

    • Rendering game assets in ActionScript using blitting techniques and Flash Builder 4
    • Getting started with Flash Platform game development

    Tutorials & Samples

    Tutorials

    • Flex mobile performance checklist
    • Flex and Maven with Flexmojos – Part 3: Journeyman
    • Migrating Flex 3 applications to Flex 4.5 – Part 4

    Samples

    • Twitter Trends
    • Flex 4.5 reference applications
    • Mobile Trader Flex app on Android Market

    Flex User Forum

    More
    07/25/2011 Flash Player Debug Issues - Safari 5.1 & Chrome 13
    04/22/2012 Loader png - wrong color values in BitmapData
    04/22/2012 HTTPService and crossdomain.xml doesn't work as expected
    04/23/2012 Memory related crashes in Flex application

    Flex Cookbook

    More
    04/06/2012 How to detect screen resize with a SkinnableComponent
    02/29/2012 Embed Stage3D content inside Flex application components
    02/15/2012 Custom WorkFlow Component
    02/09/2012 Using Camera with a MediaContainer instead of VideoDisplay

    Products

    • Acrobat
    • Creative Cloud
    • Creative Suite
    • Digital Marketing Suite
    • Digital Publishing Suite
    • Elements
    • Mobile Apps
    • Photoshop
    • Touch Apps
    • Student and Teacher Editions

    Solutions

    • Digital marketing
    • Digital media
    • Web Experience Management

    Industries

    • Education
    • Financial services
    • Government

    Help

    • Product help centers
    • Orders and returns
    • Downloading and installing
    • My Adobe

    Learning

    • Adobe Developer Connection
    • Adobe TV
    • Training and certification
    • Forums
    • Design Center

    Ways to buy

    • For personal and home office
    • For students, educators, and staff
    • For small and medium businesses
    • For businesses, schools, and government
    • Special offers

    Downloads

    • Adobe Reader
    • Adobe Flash Player
    • Adobe AIR
    • Adobe Shockwave Player

    Company

    • News room
    • Partner programs
    • Corporate social responsibility
    • Career opportunities
    • Investor Relations
    • Events
    • Legal
    • Security
    • Contact Adobe
    Choose your region United States (Change)
    Choose your region Close

    North America

    Europe, Middle East and Africa

    Asia Pacific

    • Canada - English
    • Canada - Français
    • Latinoamérica
    • México
    • United States

    South America

    • Brasil
    • Africa - English
    • Österreich - Deutsch
    • Belgium - English
    • Belgique - Français
    • België - Nederlands
    • България
    • Hrvatska
    • Česká republika
    • Danmark
    • Eastern Europe - English
    • Eesti
    • Suomi
    • France
    • Deutschland
    • Magyarország
    • Ireland
    • Israel - English
    • ישראל - עברית
    • Italia
    • Latvija
    • Lietuva
    • Luxembourg - Deutsch
    • Luxembourg - English
    • Luxembourg - Français
    • الشرق الأوسط وشمال أفريقيا - اللغة العربية
    • Middle East and North Africa - English
    • Moyen-Orient et Afrique du Nord - Français
    • Nederland
    • Norge
    • Polska
    • Portugal
    • România
    • Россия
    • Srbija
    • Slovensko
    • Slovenija
    • España
    • Sverige
    • Schweiz - Deutsch
    • Suisse - Français
    • Svizzera - Italiano
    • Türkiye
    • Україна
    • United Kingdom
    • Australia
    • 中国
    • 中國香港特別行政區
    • Hong Kong S.A.R. of China
    • India - English
    • 日本
    • 한국
    • New Zealand
    • 台灣

    Southeast Asia

    • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

    Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

    Terms of Use | Privacy Policy and Cookies (Updated)

    Ad Choices

    Reviewed by TRUSTe: site privacy statement