Cross platform

It's time to let you explore the web code base on your own and figure out the rest of the code. With the help of the Adobe AIR technology, we are able to use the same ActionScript code base to target desktops, Android, iOS, and Blackberry along with the Web. This is what we call cross-platform development, and Starling helps us with its optimized architecture and touch-based interactivity.

Moving on, let us open up the FlagDefenseDevice project, which is actually a Flash builder ActionScript mobile project. The code base remains almost the same with some very subtle but important changes, which we will discuss later on. We have an additional dependency, the RectanglePacking algorithm by Ville Koskela, which is used for the creation of dynamic texture atlases.

Note

More information on this can be found at http://villekoskela.org/2012/08/12/rectangle-packing/.

We have the com.Adobe package, which helps us save the dynamically created atlas for future use. We no longer need a preloader class as the entry point. Let us explore the FlagDefenseDevice document class. The first important change which you may actually miss is the SWF directive, which sets the width and height to 100%.

 [SWF(backgroundColor = "#004400", frameRate = "30", width "100%", height = "100%")]

This enables us to make the game fit any screen on which it is displayed. The com.csharks.juwalbose.utils package now has a different ResourceManager class and a new class called DynamicTextureAtlasCreator, which is a slightly altered version from the following link:

Tip

DynamicTextureAtlasCreator can be found on GitHub at https://github.com/juwalbose/DynamicAtlasCeatorAirDemo.

Another major difference is that the art assets are no longer embedded and they are dynamically loaded at runtime. This is a very important step, which can save you some significant memory usage as embedding takes up a lot of our precious and available memory. An important thing to notice is that we are using two texture atlases based on the 2048 x 1536 iPad retina screen size. These can be found in the media folder inside the bin-debug folder.

Supporting multiple screens

Supporting multiple screens is kind of the holy grail in cross-platform development. There are multiple approaches which we can follow, but all have their own flaws and there is no single solution at this point. Let me briefly explain the different possible approaches in order of increasing complexity.

The easiest one is to just provide one single art asset designed for one-screen size, say, 800 x 480, which has the most prevalent aspect ratio and stretch to fit the current screen. The main flaw is that the art will be distorted depending on the aspect ratio of the screen. Also, the quality of the art will be poor in high-resolution as well as low-resolution screens.

We can alternately provide multiple sets of art to be used for multiple sets of screen sizes as it is done in Android with LDPI, MDPI, HDPI, XDPI, and XHDPI. This will certainly address the quality loss to a certain extent, but the aspect ratio distortion will persist if we allow the canvas to stretch to fit the screen.

Yet another alternative, which is preferred by many game developers as well as the Starling creator, is to use letterboxing . Letterboxing tries to fit the canvas to the screen without changing the aspect ratio. This makes the game display empty areas on its borders that fall outside the strict aspect.

Note

Rolf Ruiz has an excellent Starling Viewport class which can help with letterboxing. More information on this is available at https://github.com/alesys/StarlingViewPort.

The most efficient method is to create needed textures from an asset dynamically at runtime based on the current screen size. This can be achieved by using Flash vector assets along with Emibap's exceptional Dynamic Texture Atlas and Bitmap Font Generator available at https://github.com/emibap/Dynamic-Texture-Atlas-Generator.

The only problem with this approach is that this breaks the way we normally create games, which involves spritesheets and raster atlases. An artist may be more comfortable creating a spritesheet, or rather a development pipeline in place will facilitate the same. Ideally, game development is spritesheet-based and handling more platforms, such as HTML5 will demand the same. So, it is advised to have a spritesheet-based development pipeline to support as many platforms as possible.

So, I have created a solution, which creates textures dynamically based on the current screen size, but is still raster atlas-based. Enter the DynamicTextureAtlasCreator class, which works in tandem with ResourceManager and the Rectangle packing algorithm by Ville Koskela to create atlases dynamically at runtime.

Note

Check out the DeviceManager class, which tries to detect if it is an iOS or an Android device.

Dynamic Texture Atlas Creator

This class uses a 2048 iPad retina-based texture atlas to create textures for the current screen size by scaling the images with respect to the aspect ratio. The created images are then packed into a new atlas and saved in the ApplicationStorageDirectory folder for use for any subsequent runs. The crux of it is the following function, which scales the images:

private static function scaleBitmapData(ARG_object : BitmapData, ratio : Number):BitmapData {
  var bmpd : BitmapData = new BitmapData(Math.round(ARG_object.width * ratio), 
  Math.round(ARG_object.height * ratio), true, 0x000000);
  var scaleMatrix:Matrix = new Matrix();
  scaleMatrix.scale(ratio, ratio);
  var colorTransform:ColorTransform = new ColorTransform();
// draw the object to the BitmapData, applying the matrix to scale
  bmpd.draw( ARG_object, scaleMatrix ,colorTransform,null,null,true);
  ARG_object.dispose();
  ARG_object = null;
  return bmpd;
}

The ResourceManager class initiates the creation of the dynamic atlas by calling the following:

DynamicAtlasCreator.createFrom(XhdpiPng.bitmapData,data,scaleRatio,assets,atlasName);

It passes the 2048-based texture details along with the scale ratio to which we need to scale down, an instance to the asset manager, and the name in which we would be saving the new atlas. ScaleRatio needs to be calculated based on the current screen.

Finding the ScaleRatio value

The good thing about developing a tile-based game is that it becomes much easier to scale the game scene up or down as it is just a matter of increasing or decreasing the tile width. In our game too, we just need to find a new tile width, based on which we can re-align our game without affecting the logic and create a new atlas based on the new tile width. The FlagDefenseDevice class calls up an onResize method when a Starling root is created. OnResize calls up the rescaleAndRedraw method of the SceneManager class, passing in the current stage width and height as parameters.

Have a look at the following rescaleAndRedraw code from the SceneManager class:

public function rescaleAndRedraw(newWidth:Number,newHeight:Number)
:void{
  if(ResourceManager.assets){
    ResourceManager.assets.purge();
  }
  var visibileTiles:Point = new Point(13,20);
  var newDimensionX:uint = 
  1 + Math.round(newWidth / visibileTiles.x);
  var newDimensionY:uint = 
  1 + Math.round(newHeight / visibileTiles.y);

  if(newDimensionX > 2 * newDimensionY){
    newDimensionX = 2 * newDimensionY;
  }else{
    newDimensionY = newDimensionX / 2;
    newDimensionX = 2 * newDimensionY;
  }
  var scaleRatio:Number = Math.round(newDimensionY / 8) / 10;
  ResourceManager.initialise(scaleRatio);
    addEventListener(Event.ENTER_FRAME,waitForReload);
}
private function waitForReload(e:Event):void{
  if(ResourceManager.initialised){
  removeEventListener(Event.ENTER_FRAME,waitForReload);
  launchMenu();
  }
}

We need to show 13 tiles horizontally and 20 tiles vertically to complete the display of our effective game area. Here, we essentially divide the screen width and height with these values to find the best size for our new tile width. This is a misnomer as we are actually using the newDimensionY height value as the tile width. The scaleRatio value is calculated by dividing the new tile width by the original tile width, which is 80. ResourceManager is called to initialize and thereby create a new texture atlas and we wait for the process to be completed. The menu gets launched once the textures are in place.

Positioning items properly

Now, as the screen size can be of any value, we need to find a way to properly position items. The safest way is to position them based on the screen size and the item size itself.

helpBtn.x = stage.stageWidth / 2 – helpBtn.width / 2;

This code places the button in the middle of any screen horizontally. For absolute placement we need to use the scaleRatio value.

soundBtn.y = (20 * ResourceManager.scaleRatio);

This will place it at 20 pixels for iPad retina and 10 pixels for iPad nonretina.

Now, in order to middle align our active game area on any screen size, we need to do some calculations. This is done within the MainLevel class' init method.

sr=ResourceManager.scaleRatio;
var newDimensionY:uint = sr * 80;
var newDimensionX:uint = 2 * newDimensionY;
viewPort = RectangleUtil.fit(
  new Rectangle(0, 0, 2*newDimensionY*visibileTiles.x, newDimensionY*visibileTiles.y),
  new Rectangle(0, 0, stage.stageWidth, stage.stageHeight),ScaleMode.SHOW_ALL);
screenOffset.x = 2 * newDimensionY * screenOffset.x / (2 * tileWidth);
screenOffset.y = newDimensionY * screenOffset.y / tileWidth;
screenOffset.x += viewPort.x;
screenOffset.y += viewPort.y;
tileWidth = newDimensionY;

This finds the rectangle fitting value to centralize the active area and adds it to the screenoffset value which makes all the drawing to get offset, thereby centralizing the game scene.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.44.143