Smart Scale для Starling

1
Начав работать со Starling и нацелившись на мобильные платформы я столкнулся с необходимостью поддержки разных разрешений экрана (размеры и соотношения сторон). Попробовав разные варианты решения данной проблемы я написал для себя 4 типа скейлинга, которые покрывают все запросы.

Для удобства использования определим константы типов:
// Растягивает картинку без учёта соотношения сторон, заполняя весь экран
public static const STRATCH:String = "ScaleMode.Stratch";
// Сохраняет пропорции и центрирует картинку, оставляет полоски
public static const LETTERBOX:String = "ScaleMode.LetterBox";
// Сохраняет пропорции и увеличивает картинку пока она влезает в экран, оставляет полоски
public static const ZOOM:String = "ScaleMode.Zoom";
// Подстраивает размер картинки под размер экрана, "резиновый" дизайн
public static const SMART:String = "ScaleMode.Smart";

STRATCH и LETTERBOX не меняют scaleFactor по умолчанию, ZOOM и SMART могут динамически менять scaleFactor. Это надо помнить, чтобы перегрузить ресурсы при необходимости.

Теперь код самого скейлинга. Для некоторых расчётов нам потребуется базовый размер, на который мы ориентируемся при разработке. Некий эталон, который мы принимаем за scaleFactor=1. Эти размеры никогда не меняются и могут быть заданы в виде констант. Например если мы на 1 принимаем размер iPhone3GS, то width=480 и height=320.
public function setScaleMode(value:String, width:int = 480, height:int = 320):void {
        if (value != STRATCH && value != LETTERBOX && value != ZOOM && value != SMART) {
                if (value != "") {
                        trace("Scale mode '" + value + "' not found.");
                }
                return;
        }
        
        var starling:Starling = Starling.current;
        if (starling == null || !starling.isStarted)
        {
                return;
        }
        
        var stage:Stage = starling.nativeStage;
        
        switch(value) {
                case STRATCH:
                        starling.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
                        break;
                case LETTERBOX:
                        var k:Number = Math.min(int(stage.stageWidth / width), int(stage.stageHeight / height));
                        var w:int = width * k;
                        var h:int = height * k;
                        var x:int = (stage.stageWidth - w) * 0.5;
                        var y:int = (stage.stageHeight - h) * 0.5;
                        starling.viewPort = new Rectangle(x, y, w, h);
                        break;
                case ZOOM:
                        k = Math.min(stage.stageWidth / width, stage.stageHeight / height);
                        w = width * k;
                        h = height * k;
                        x = (stage.stageWidth - w) * 0.5;
                        y = (stage.stageHeight - h) * 0.5;
                        starling.viewPort = new Rectangle(x, y, w, h);
                        break;
                case SMART:
                        if (stage.stageWidth / width > stage.stageHeight / height) {
                                var s:int = stage.stageWidth / width;
                                k = stage.stageWidth / stage.stageHeight;
                                starling.stage.stageWidth = stage.stageHeight * k / s;
                                starling.stage.stageHeight = stage.stageHeight / s;
                        } else {
                                s = stage.stageHeight / height;
                                k = stage.stageHeight / stage.stageWidth;
                                starling.stage.stageWidth = stage.stageWidth / s;
                                starling.stage.stageHeight = stage.stageWidth * k / s;
                        }
                        starling.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
                        break;
        }
}


Чтобы использовать всё это дело надо определиться с эталонными размерами и при каждом ресайзе вызывать приведённую функцию.
public static const WIDTH:int = 480;
public static const HEIGHT:int = 320;
Starling.current.viewPort = new Rectangle(0, 0, WIDTH, HEIGHT);
...
// onResise
setScaleMode(SMART, WIDTH, HEIGHT);
  • +13

Комментарии (3)

0
Спасибо, помог.
единственнеое, что исправил:

было:
var s:int = stage.stageWidth / width;

стало:
var s:Number = stage.stageWidth / width;

А то s = 0 для скалинга в обратную сторону
0
s=0 надо как-то отдельно разруливать, иначе не правильно работать будет на нормальных размерах.
0
Спасибо, мне тоже очень помогло.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.