About this book

Starling makes it very easy for an ActionScript developer to create cross-platform, multiplayer games. Starling utilizes GPU to render all the content for excellent performance on a wide range of devices. Multiplayer games have become a very lucrative market, pulling in more and more developers who try to raise the bar for user experience. With the ever-increasing popularity of iOS and Android, the demand for cross-platform games has increased exponentially.

Starling Game Development Essentials takes you step-by-step through the development of a complicated Isometric game. You will learn to create a level editor, AI logic for enemies, and integrate particle effects. Furthermore, you will learn to develop multi-player games that can support multiple players on the same device and would integrate Flox services for efficient user tracking and analytics. Finally, you will understand how to deploy your game to the Web, App Store, and Google Play.

This project-based book starts with the game idea, and an introduction to Game States and Game Loop. You also learn about the working of Isometric projection logic.

You get to explore RenderTexture for dynamically creating game levels and later on easily upgrade to the exceptional QuadBatch for deploying on devices. You will then move on to use Starling Particle extension for explosion effects. Finally, you will develop a simple AI Manager to help the enemy make decisions and use Pathfinder to facilitate grid-based path finding.

Starling Game Development Essentials, with the help of FlagDefense game source code, is an invaluable asset to anyone who wants to create a Starling cross-platform game.

Publication date:
December 2013
Publisher
Packt
Pages
116
ISBN
9781783983544

 

Chapter 1. Our Capture the Flag Game

Welcome to Starling deep dive, where we will focus on creating an interesting game using the excellent Starling framework. We will learn about the major aspects of a typical game including game states and game loops, which will eventually help us to create our own Starling-based game engine. We will be proceeding on the assumption that you already know the concepts of ActionScript 3 programming and have a basic knowledge of the Starling framework. If you are good in ActionScript 3 but have never tried Starling, this is the opportunity to get started. Starling opens up the possibility of deploying your ActionScript-based games onto the touch-based devices including Android and iOS with excellent performance.

In this chapter, we will cover the following topics:

  • Learn about the components that make up a game engine

  • Learn about the tile-based design approach

  • Get introduced to the tools of trade—applications which help in development

  • Explain and understand the game idea which we will be implementing

  • Implement an array-based level data onto a top-down game scene

 

Understanding a game


So what really is a game? It seems to be a difficult question, as we can imagine a million kinds of answers depending on whom you would ask. But particularly for a developer, a game can be explained as a very simple and straightforward logic block. When stripped of all its glory, a game program essentially becomes what we programmers call a loop. You may find it hard at this point to even consider to imagine that the ultra-realistic 3D racing game that you had just played is indeed just a glorified programming loop.

This loop is known as the game loop and it helps in executing the game logic, which is separated into logical blocks known as states or game states.

Introducing the game loop and game states

Once the game is started, the program will enter the game loop and remains in the loop until we exit the game. During this time, the game loop gets executed at a predetermined time, every second. Sometimes this maybe called the FPS (frames per second). In typical cases, we try to maintain a stable FPS throughout the game for the perfect gameplay experience. In every frame, the logic will execute a set of instructions as per the current state of the game. The state of a game is defined by game states. This may sound a bit confusing if you have not tried developing games yet; please read ahead for more clarification.

Game state

Let us try to understand a game state in layman's terms. A typical game starts off in an introduction (init) state, moves onto a menu state of some kind, and then to an actual gameplay state. When you get defeated, the game moves onto a game over state, and then moves towards the menu state where the process can be restarted. The traditional way of handling multiple states is with a series of if statements, switches, and loops. The program begins in the introduction state and loops until a key is pressed or a certain time has elapsed. Then, the menu state starts displaying a set of buttons and loops until a selection is made. Later, the game begins where we loop through the game logic until we reach a level up or till a game is over. In every frame through the game loop, the program checks to see if it should switch to the next state or simply draw the next frame from the current state.

Game loop

In its very basic form, the game loop is a state machine which switches between the different game states based on a game logic. Here is a simple illustration of the basic game loop with very basic game states: Initialization, Game loop, and Shutdown (exit). The following diagram shows the basic game loop:

The game loop receives user interactions and inputs, executes the game logic, updates the game world, and finally renders the scene onto our screen. The loop gets repeated based on the FPS. We need to break down our own game into different game states and implement the game engine using an efficient game loop, which logically executes through these states based on the user interaction or logic results. Do not think that this is a complicated process, as we will be breaking down our game idea into manageable game states and implementing it into a loop using an efficient technique that is already provided to us by Flash.

Flash's inherent game loop

Flash already has a loop implemented which is working perfectly for us. All we need is to tap into this rendering loop. Flash has an FPS setting, based on which the Flash Player tries to render each frame one after the other. We can use this for our game loop as we have the Event.ENTER_FRAME event, which gets dispatched on every frame. We can easily write our core game logic as a listener to this event, and it will get executed for every frame which serves the purpose of the game loop. In addition to this, Starling has a new EnterFrameEvent, which also brings in more efficiency as well as functionality. With this event, we get access to the elapsed time between each individual EnterFrame events. This time difference is crucial in implementing time-based animations and delivering the same performance when the FPS cannot remain the same over the duration of execution.

Flash Player tries to render frame after frame while trying to maintain a stable FPS. The following diagram—the famous Flash Player elastic runtime diagram—explains how Flash Player executes the code and does the rendering for every frame. Each frame loop consists of two phases, divided into the following three parts:

  • Events

  • The EnterFrame event

  • Rendering

The first phase includes two parts (events and the EnterFrame event), both of which potentially results in your code being called. In the first part of the first phase, runtime events arrive and are dispatched. The runtime never speeds up the frame rate due to lack of activity. If events occur during other parts of the execution cycle, the runtime queues up those events and dispatches them in the next frame. The second part of the first phase is the EnterFrame event. This event is distinct from the others because it is always dispatched once per frame.

The following diagram shows Flash Player Elastic Racetrack:

Once all the events are dispatched, the rendering phase of the frame loop begins. At that point, the runtime calculates the state of all visible elements on the screen and draws them to the screen. Then, the process repeats itself, like a runner going around a racetrack.

Capture the Flag

It's time to talk about a game idea that we will be trying to implement in this book. We will be creating an isometric game based on tile-based logic where the objective is to capture the enemy's flag while defending our own. The game will be turn based, where each turn is determined by the dice throws. The game involves enemies with AI (Artificial Intelligence), who will try to avoid obstacles and find paths to reach their destination. It also involves the creation of levels externally, which will adhere to a specific format suitable to be used in the game. We will include the ability for two players to play against each other by sharing the gaming device.

The game idea

The game is played out between two teams in an open terrain which will vary depending on the level loaded. The two teams are color coded among which one will be controlled by the player, while the other will be controlled by the computer. Later we will try to make both teams player controlled when we implement the same device multiplayer. The terrain is divided into square grids, which can be occupied by the soldiers of either team. Each team has their base to the extremes of the playing field away from each other. Each team base will have three soldiers and a colored flag, which they should defend. The objective is to capture the opponent team's flag and bring it to your base while keeping your flag intact. The team which has both the flags at their base wins the game.

The following screenshot shows the finished Capture the Flag game level:

Rules of the game

The gameplay is controlled by throwing a dice. Each team gets a turn/chance to throw the dice after the other team has completed its move, and hence it is a turn-based game. For a turn-based game, only one player can make a move at any particular time; when it is his/her turn, other players need to wait for their turn. A famous example would be the classic chess game.

Dice values and their corresponding results in our game are as follows:

  • If the dice value is 1, the player can add a soldier on a grid next to their base

  • If the dice value is 6, the player can add a bomb on a grid next to their base

  • For any dice values, the player can move his/her soldiers as many grids as the value

Player can move multiple soldiers if he/she has more than one soldier on the grid. The total number of moves made by all the soldiers should be equal to the dice value. A soldier can only be moved once per dice throw.

The rules of the game play are as follows:

  • Any grid can be occupied by a single soldier only.

  • Soldiers can enter the grid occupied by an opponent soldier, thereby resetting the opponent soldier to their base. If a soldier ends up on a grid with a bomb, both the soldier and the bomb gets reset to base.

  • Soldier entering a grid with a flag picks it up.

  • Collecting the flag doesn't require an exact dice value.

  • Bombs automatically move towards the nearest enemy soldier one step at each turn.

A valid move is executed by the player by dragging from the soldier to a destination grid, if the current dice value permits the same. The user interface of the game will also have a die which can be clicked on to stop the dice roll. This results in a new dice value for which the moves can be executed. For grid-based games, we have a well-established school of game development logic called tile-based design. We will explore the same in the next section.

 

The tile-based approach


Tile-based game design involves breaking the level art into pieces known as tiles, which will then be arranged in a two - dimensional grid to create complicated levels. These tiles will be of equal dimensions, which means that the height and width will be the same for all of the tiles. Care should be taken while designing such tiles, as they need to be joined with other tiles on all four sides without creating a discontinuity in the overall level graphic created by all of the tiles arranged in the grid. Hence, a tile will need to be seamless, and we should be able to stack an infinite number of them adjacent to each other in order to create complicated-level designs.

The major advantages of using such an approach are as follows:

  • We can get rid of huge level sheets

  • Only a limited number of tiles are capable of creating complicated levels

  • Tile-based level and logic can be implemented using standard data structures

  • Collision detection and path finding becomes comparatively easier

  • Scrolling levels are much easier to implement

  • Multiple views can be supported: top-down, side, and isometric

  • Easy serializing and deserializing of level data

The following screenshot shows an example of a top-down tile-based game level:

Now let us see how a simple two-dimensional array can be used to facilitate the implementation of the tile-based design.

An array-based implementation of a level

We have understood that a tile-based level is actually a two-dimensional grid of tiles. This can be logically represented using a 2D array, where the value stored at any index can be the ID of the corresponding tile. For example, say we have 20 different tiles making up a level of 50 x 50 tiles. This means that if an individual tile has dimensions A x B, then our level will be 50 x A wide and 50 x B high. Here, A is called tileWidth whereas B is called tileHeight. In many cases, both of these values will be the same resulting in square tiles. For representing these 20 different tiles, we can give them sequential IDs starting from 1 to 20. So, tile number 12 will have an ID as 12. This means that our 50 x 50 level data can be stored as a two-dimensional array with tile IDs as values.

The following example shows the level data for an 8 x 5 tile grid:

[[5,1,1,1,1,1,1,6],
[4,0,0,0,0,9,0,2],
[4,0,9,0,0,0,0,2],
[4,0,0,0,0,0,0,2],
[8,3,3,3,3,3,3,7]]

This level data can be explained as follows:

  • ID 0: Sand tile, walkable

  • ID 1, 2, 3, and 4: Wall tiles on top, right, bottom, and left respectively

  • ID 5, 6, 7, and 8: Wall corner tile on top - left, top - right, bottom - right, and bottom - left respectively

  • ID 9: Sand tile with a rock formation

Relationship between screen space and level array

Now that we have represented our level data using a 2D array, let us explore how we can formulate a relationship between the graphic in screen space and their corresponding value in the array. Let us consider a case where we have square tiles with the dimension tileWidth x tileWidth. Also, our level array is M x N, that is, M columns and N rows. We can place the first tile at [0][0] on screen at (0,0) as:

var tile:Image = Image.fromBitmap("tile"+levelData[0][0]+".png");
addChild(tile);

Tip

The source uses a better asset management by using a texture atlas, and then an image will be created using the following code:

tile=new Image(texAtlas.getTexture(paddedName(levelData[i][j])));

LevelData[0][0] will return the stored tile ID value and it is appended to the string to form the correct name of the tile. For example, if levelData[0][0] is 5, then the tile image name will be tile5.png. We create an image from this particular bitmap and add it to the scene. As this tile is situated at the top-left extreme, there is no need to explicitly set the x and y values because by default they will be 0, 0. For any other tile, we will need to set the x and y values for rightly positioning it on the screen.

Let us take the example of levelData[5][4], which means the tile is in the sixth column and fifth row. For placing this tile, we will need to offset the tile by relevant multiples of tileWidth.

var tile:Image = Image.fromBitmap("tile"+levelData[5][4]+".png");
addChild(tile);
tile.x=5*tileWidth;
tile.y=4*tileWidth;

So for any tile at an arbitrary position i, j in the array, the screen position will be x = i * tileWidth and y = j * tileWidth. This is the forward relationship from level array to screen space, but what about the reverse? How will we find the corresponding level array value from any particular point in screen space?

For this, we will need to reverse the preceding formula, that is, i = x / tileWidth and j = y / tileWidth. Care is to be taken to make sure that we only consider the integer value of the calculated values, as the original result will be a float with decimal values. This is because AS3 array indices are always integer values starting at a value of 0.

So let us write down our formulas for any level array at the position [i][j]:

x = offsetX + (i * tileWidth);
y = offsetY + (j * tileWidth);

Here, offsetX and offsetY are the space we need to leave out in the left and top respectively, because in normal cases our level art won't start at (0, 0) screen position, but at an arbitrary (offsetX, offsetY). Reversing the preceding formula, we calculate the level array indices as follows:

i = int ((x - offsetX) / tileWidth);
j = int ((y - offsetY) / tileWidth);

There can be times at which the calculated values may fall out of valid array dimensions and may need to be ignored. Now let us try implementing a simple top-down view array-based level using Starling, based on the knowledge we have acquired so far.

 

Prerequisites for using the shared code


There are certain prerequisites that are necessary for following the programming done in this book. You will need to perform the following setup properly:

  • ActionScript development IDE such as Flash Builder 4.7, FDT, FlashDevelop, or Flash IDE is required. Flash Builder is recommended, but if you are concerned with licensing, then the free FlashDevelop is ideal for the Windows platform.

  • The latest source or compiled SWC of Starling should be added to the class path or should be linked. At the time of writing, the latest Starling version was 1.4.1.

  • Download the art assets and the sample code for this book from the Packt website.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.

 

Creating a top-down game scene


Let us try to implement a sample Starling-based top-down level with provision to detect the tile on which we touch. We will use the source and the tile sheet given in the Chapter 1 folder from the shared source. The code for the TopDownScene class is shared in the following code snippet. You will need to initialize this class from the Starling document class using new Starling(TopDownLevel, stage).

package com.csharks.juwalbose
{
  import starling.display.DisplayObjectContainer;
  import starling.display.Image;
  import starling.events.Event;
  import starling.events.Touch;
  import starling.events.TouchEvent;
  import starling.textures.Texture;
  import starling.textures.TextureAtlas;
  public class TopDownLevel extends DisplayObjectContainer
  {
    //Texture Atlas image
    [Embed(source="../../../../assets/assets.png")]
    public static const AssetTex:Class;
    //Texture Atlas XML
    [Embed(source = "../../../../assets/assets.xml", mimeType = "application/octet-stream")]
  private static const AssetXml:Class;
    private var texAtlas:TextureAtlas;
    private var tileWidth:uint=50;
    private var borderX:uint=25;
    private var borderY:uint=50;
    private var touch:Touch;
    //LevelData as 2 dimensional array
    private var levelData:Array=[["14","21","21","21","21","21","21","13","21","21","21","21","21","21","17"],
      ["18","12","7","2","2","8","2","3","2","5","2","2","7","13","20"],
      ["18","3","3","2","2","2","2","2","2","2","2","2","3","2","20"],
      ["18","3","3","2","2","2","9","2","2","2","3","2","3","3","20"],
      ["18","5","2","2","5","2","2","2","4","2","2","2","2","5","20"],
      ["10","2","2","2","2","3","2","2","2","2","2","2","7","2","12"],
      ["18","2","8","2","2","2","2","3","2","5","2","2","2","5","20"],
      ["18","2","2","2","4","2","2","2","2","2","4","2","2","2","20"],
      ["18","11","2","3","2","2","2","3","2","2","2","2","2","10","20"],
      ["15","19","19","19","19","19","19","13","19","19","19","19","19","19","16"]];
  public function TopDownLevel()
  {
    super();
    this.addEventListener(Event.ADDED_TO_STAGE, init);
  }

  private function init(e:Event):void
  {
  this.removeEventListener(Event.ADDED_TO_STAGE, init);
  //Let us create a texture atlas
  var tex:Texture =Texture.fromBitmap(new AssetTex(),false);
  var img:Image;
  texAtlas=new TextureAtlas(tex,XML(new AssetXml()));
  //Loop through 2D array & add images to stage
  for(var i:int=0;i<levelData.length;i++){//i is for rows
  for(var j:int=0;j<levelData[0].length;j++){//j is for columns
  img=new Image(texAtlas.getTexture(paddedName(levelData[i][j])));
  addChild(img);
  //calculate position depending on i & j
  img.x=j*tileWidth+borderX;
  img.y=i*tileWidth+borderY;
  }
  }
  //Listener for touch
  this.addEventListener(TouchEvent.TOUCH, onTouch);
  }

  private function paddedName(id:String):String{
    //function to return '0' padded name
    var offset:uint=10000;
    offset+=int(id);
    var str:String="tiles";
    str+=offset.toString().substr(1,4);
    return str;
  }
  private function detectTile(valueX:int, valueY:int):void{
    //function to detect tile at given position
    var tileX:int=int(valueX-borderX)/tileWidth;
    var tileY:int=int(valueY-borderY)/tileWidth;
    trace(levelData[tileY][tileX]);
  }
  protected function onTouch(event:TouchEvent):void
  {
    for (var i:int = 0; i < event.getTouches(this).length; ++i)
      {
        touch = event.getTouches(this)[i];
        detectTile(touch.globalX,touch.globalY);
      }
    }
  }
}

Here we are using the Starling TextureAtlas class created from embedded assets. The embedded XML and PNG files are created using the TexturePacker application using the Sparrow/Starling export feature. The PaddedName function adds the zero padding to the tile names and the onTouch listener function traces out the tile value in the levelData array based on the touch position. The registration point of an image is at its top-left corner by default. This benefits us for placing them properly in the scene. Try working with this on your own by playing around with the level data. You can change the values in the level data and see the level scene updates accordingly. We have a total of 22 tiles to play with.

Applying the RenderTexture approach

In the preceding code, we have placed each tile as individual images on the scene. This will look fine but it is not necessarily the best approach. This creates a lot of independent entities on the scene, which may become a performance hog for a complicated game where we may need to manipulate each and every tile on every frame. An alternate approach is to use a RenderTexture class.

A RenderTexture class can be considered as a dynamically changeable Starling texture, which can be altered anytime via code. We can use methods to clear it, draw items onto it, or to fill it up completely. For our previous level scene, we can simplify everything by creating a single image based on a RenderTexture class, and then drawing all tiles onto it. This results in the scene having only one entity, thereby minimizing the effort on the Flash Player. Let us take a look at the changes in the code:

rTex=new RenderTexture(stage.stageWidth,stage.stageHeight);
var rTexImage:Image= new Image(rTex);
addChild(rTexImage);
for(var i:int=0;i<levelData.length;i++){
  for(var j:int=0;j<levelData[0].length;j++){
    img=new Image(texAtlas.getTexture(paddedName(levelData[i][j])));
    img.x=j*tileWidth+borderX;
    img.y=i*tileWidth+borderY;
    //draw to texture instead of adding new image
    rTex.draw(img);
  }
}

The detectTile function is also slightly altered to ignore invalid touch points which fall out at the side level area:

private function detectTile(valueX:int, valueY:int):void{
  var tileX:int=int(valueX-borderX)/tileWidth;
  var tileY:int=int(valueY-borderY)/tileWidth;
  if(tileX<0 ||tileY<0 ||tileX>levelData[0].length-1
  ||tileY>levelData.length-1)
  { //outside of tile area
    return;
  }
  trace(levelData[tileY][tileX]);
}

Use RenderTexture wherever possible for efficient resource management as well as performance boost. There is an additional method called RenderTexture.drawBundled, which can further speed things up considerably. We will be using this function a lot for our screen update.

 

Tools of the trade


We have successfully created our level scene based on a level data 2D array. There are different tools which we may need or which may help us to speed up our development. Let me mention a few of these which every game developer should consider having in their tool box:

  • TexturePacker: This is a tool for packing images into texture atlases. It is very handy for resource management, size reduction, and memory optimization. A free version is available. Please note that the latest Flash Professional CC has an inbuilt spritesheet creator.

  • Hiero: This is a free online Java-based application for creating bitmap fonts. Bitmap fonts will help to speed things up for game text which need frequent updating. You may also use standalone tools such as BMFont for Windows or Glyph Designer for OS X.

  • Adobe Scout: This is a wonderful tool for profiling your AS3 applications and games from the stables of Adobe. This is a must have for any AS3 developer. It is a part of the Adobe Gaming SDK. You can get it for free now.

  • Adobe ATF tools: These are a set of texture packing tools from Adobe, which help to minimize the memory consumption on handheld devices. This will be needed for our cross-platform deployment segment. It is a part of Adobe Gaming SDK.

  • DragonBones framework: This is a Flash IDE extension for creating skeleton-based animations. It is a part of Adobe Gaming SDK.

  • FeathersUI latest source or compiled SWC should be added to class path or should be linked. We will be using this excellent framework for all our UI needs.

  • External debuggers such as Arthropod or De MonsterDebugger will facilitate bug spotting and fixing.

 

Summary


In this chapter, we learned about the basic structure of a game and got introduced to the game loop and game states. We learned that the Flash Player facilitates game development by providing its own game loop hook and doing scene updates per frame. I also explained to you the game idea, which we will be trying to develop throughout this book. The idea is a tile-based, isometric, and turn-based game. We understood about the turn-based game and got in-depth understanding of the tile-based approach.

We wrote code to create a level using the tile-based approach where the level data is stored as a 2D array. We also found out the relationship between screen space and array indices. Let us use the tile-based approach we have learned in this chapter to implement the isometric view in the next chapter. We will learn how a normal 2D view relates to the interesting pseudo 3D isometric view.

About the Author

  • Juwal Bose

    Juwal Bose is a game developer, game designer, and technology consultant from the incredibly beautiful state of Kerala in India. He is an active figure in social media and game development SIGs, and he never misses a chance to speak at technical conferences and BarCamps. He conducts technical workshops for engineering students at professional colleges as part of open source initiatives. Juwal is the Director at Csharks Games and Solutions Pvt. Ltd., where he manages research and development, training, and pipeline integration.

    He has been developing games since 2004 using different technologies, such as ActionScript, Objective-C, Java, Unity, LibGDX, Cocos2D, OpenFL, Unity, and Starling. His team has created more than 400 games to date, and many of the job management games are listed at the top of leading portals worldwide. He was involved in the development of more than 20 LibGDX games, primarily for the Android platform.

    Juwal writes game development tutorials for GameDevTuts+ and manages the blog of Csharks. His isometric tutorial for GameDevTuts+ was well received and is considered a thorough guide for developing tile-based isometric games. This is his second book and he aims to keep writing and sharing his 10 years of game development experience through more books. His first book, Starling Game Development Essentials, Packt Publishing, was on another exceptional cross-platform game development framework—Starling.

    Juwal is a voracious reader and likes to travel. His future plans also include writing fiction.

    Browse publications by this author
Book Title
Unlock this full book FREE 10 day trial
Start Free Trial