Emanuele Feronato, a well known Flash/Html PROgrammer posted in his blog "Managing multiple iOS resolutions with Starling – real world example" (Part1, Part2)
Emanuele's solution (Many people use the same solution) was to check what is the device and load the right texture, use "Magic Numbers" to place the texture on the screen, and we have a working UI...

The problems

  • You can support a limited number of resolutions, Android has many.
  • You need to refactor your code for a new device.
  • It's very hard to maintain code with "Magic Number"
  • You are embedding all the resolutions that you support, may results in a very large app.

DMT to the rescue

  • Much smaller (No embedded Pngs, only one SWC) 
  • Will fit ANY device resolution (Even TV).
  • Easy to maintain and refactor, even redesign.
So I took the Circle Chain UI, and made everything using DMT, the full source code (FlashBuilder project) is on gitHub.

The project uses two classes, the UILayout.as to build the UI relative to the device width and height. And GameWithDMT.as which uses DMT to rasterize the UILayout result, and animate it just like Emanuele did in the original post.

UILayout.as

package
{
 import flash.display.Sprite;
 
 public class UILayout
 {
  public var UIContainer:Sprite;

  private var deviceWidth:Number;
  private var deviceHeight:Number;

  private var gameTitle:Sprite;
  private var mainBG:Sprite;
  private var gridEdition:Sprite;

  public function UILayout(deviceWidth:Number, deviceHeight:Number)
  {
   this.deviceWidth = deviceWidth; 
   this.deviceHeight = deviceHeight;
   
   // This class will build and layout the Vector assets according to the give device width and height
   // The result of the layout will be at the UIContainer Sprite (Flash Sprite with Vectors children, no artifacts)
   UIContainer=new Sprite();
   
   createBackground();
   createGameTitle();
   createGridEdition();
   createButtons();
  }
  
  private function createBackground():void {
   mainBG=new MainBG();
   mainBG.name = "MainBG";
   mainBG.width = deviceWidth;
   mainBG.height = deviceHeight;
   UIContainer.addChild(mainBG);
  }
  
  private function createGameTitle():void {
   gameTitle=new GameTitle();
   gameTitle.name = "gameTitle";
   gameTitle.width = deviceWidth*0.65; // will take 65% of the screen width
   gameTitle.scaleY = gameTitle.scaleX; // keep the same aspect ratio
   gameTitle.x=(deviceWidth-gameTitle.width)/2; // center it
   gameTitle.y=deviceHeight*0.2; // 20% of the screen height
   UIContainer.addChild(gameTitle);
  }
  
  private function createGridEdition():void {
   gridEdition=new GridEdition();
   gridEdition.name = "gridEdition";
   gridEdition.height = gameTitle.height*0.25; // make it 25% of the game title
   gridEdition.scaleX = gridEdition.scaleY; // keep the same aspect ratio
   gridEdition.y=gameTitle.y+gameTitle.height*1.1;
   gridEdition.x=gameTitle.x+gameTitle.width-gridEdition.width; // align to the right of the gameTitle
   UIContainer.addChild(gridEdition);
  }
  
  private function createButtons():void {
   var normalMode:Sprite=new NormalMode();
   normalMode.name = "normalMode";
   normalMode.height = gameTitle.height*0.25; // 25% of the game title height
   normalMode.scaleX = normalMode.scaleY; // keep the same aspect ratio

   UIContainer.addChild(normalMode);
   normalMode.x=(deviceWidth-normalMode.width)/2;
   normalMode.y=deviceHeight*0.5; // 50% of the screen height

   var timeAttackMode:Sprite=new TimeAttackMode();
   timeAttackMode.name = "timeAttackMode";
   timeAttackMode.height = gameTitle.height*0.25; // 25% of the game title height
   timeAttackMode.scaleX = timeAttackMode.scaleY; // keep the same aspect ratio

   UIContainer.addChild(timeAttackMode);
   timeAttackMode.x=(deviceWidth-timeAttackMode.width)/2;
   timeAttackMode.y=deviceHeight*0.65; // 65% of the screen height
  }

  
 }
}

GameWithDMT.as

package {
 
 import com.xtdstudios.DMT.DMTBasic;
 
 import flash.events.Event;
 
 import starling.animation.Tween;
 import starling.core.Starling;
 import starling.display.DisplayObject;
 import starling.display.Sprite;
 
 public class GameWithDMT extends Sprite {
  private var _dmtBasic     : DMTBasic;
  private var starlingUIContainer : Sprite;
  
  public function GameWithDMT() {
   _dmtBasic = new DMTBasic("DMTCircleChain", false); // change to "true" to turn ON caching
   _dmtBasic.addEventListener(Event.COMPLETE, dmtComplete);
   if (_dmtBasic.cacheExist() == true)
    _dmtBasic.process(); // will use the existing cache
   else
    doLayoutUI(); // will be done one time per device  
  }
  
  private function doLayoutUI():void {
   var uiLayout: UILayout = new UILayout(Starling.current.nativeStage.stageWidth, Starling.current.nativeStage.stageHeight);
   uiLayout.UIContainer.name = "UIContainer"; // name it so we can ask DMT for it
   _dmtBasic.addItemToRaster(uiLayout.UIContainer);
   _dmtBasic.process(); // will rasterize the given assets  
  }
  
  protected function dmtComplete(event:Event):void {
   starlingUIContainer = _dmtBasic.getAssetByUniqueAlias("UIContainer") as starling.display.Sprite;
   addChild(starlingUIContainer);

   // animate
   var gameTitle    : DisplayObject = starlingUIContainer.getChildByName("gameTitle");
   var gridEdition   : DisplayObject = starlingUIContainer.getChildByName("gridEdition");
   var normalMode    : DisplayObject = starlingUIContainer.getChildByName("normalMode");
   var timeAttackMode   : DisplayObject = starlingUIContainer.getChildByName("timeAttackMode");
   var gameTitleTween  : Tween=new Tween(gameTitle, 0.7);
   var gridEditionTween : Tween=new Tween(gridEdition, 0.7);
   var normalModeTween  : Tween=new Tween(normalMode, 0.7);
   var timeAttackModeTween : Tween=new Tween(timeAttackMode, 0.7);
   var gameTitleY    : Number;
   var gridEditionX   : Number;
   
   // save final postion
   gameTitleY = gameTitle.y;
   gridEditionX = gridEdition.x;
   
   // starting position/alpha
   gameTitle.y = -100;
   gridEdition.x = starlingUIContainer.width;
   normalMode.alpha = 0;
   timeAttackMode.alpha = 0;
   
   gameTitleTween.moveTo(gameTitle.x, gameTitleY);
   gridEditionTween.moveTo(gridEditionX, gridEdition.y);
   gridEditionTween.delay = 0.7;
   normalModeTween.fadeTo(1);
   normalModeTween.delay = 0.7+0.7;
   timeAttackModeTween.fadeTo(1);
   timeAttackModeTween.delay = 0.7+0.7+0.2;
   Starling.juggler.add(gameTitleTween);
   Starling.juggler.add(gridEditionTween);
   Starling.juggler.add(normalModeTween);
   Starling.juggler.add(timeAttackModeTween);
  }
 }
}
Powered by Blogger.