2012/09/08(土) [n年前の日記]
#3 [as3][flash][starling] Starling使用中のウインドウをリサイズする際の処理でハマる
Windows7 x64 上で Starling を勉強中なのだけど。ウインドウサイズを変更した際に、表示内容もウインドウサイズに合わせて拡大縮小させようとしたものの、何度もサイズを変更してるうちにエラーが出て Flash Player が固まってしまう不具合が出てハマってしまったり。
ウインドウサイズ変更時は、Event.RESIZE でイベント発生させられるのだけど。もしかすると前のリサイズ処理がまだ終わってないうちに、次のイベントが発生して、マズイことになってるのかなと。しかしそれなら、まだ処理中だよ的フラグを用意すれば、そこそこ改善するはずで。しかし、相変わらずエラーが出る。改善できてるように見えない…。
変更したら必ず固まるわけではないのが困る。時々何かの拍子に発生するようで。Starling.current.viewPort = viewport; のあたりがおかしいのかなあ…。よくわからん…。
色々試したけど、どうにかエラーが出ない感じになったかもしれず。とりあえず、Main.as は下のようになった。
ハマってた時のソースから変えた部分をメモ。
以下、よくわかってないけど。
ウインドウサイズ変更時は、Event.RESIZE でイベント発生させられるのだけど。もしかすると前のリサイズ処理がまだ終わってないうちに、次のイベントが発生して、マズイことになってるのかなと。しかしそれなら、まだ処理中だよ的フラグを用意すれば、そこそこ改善するはずで。しかし、相変わらずエラーが出る。改善できてるように見えない…。
変更したら必ず固まるわけではないのが困る。時々何かの拍子に発生するようで。Starling.current.viewPort = viewport; のあたりがおかしいのかなあ…。よくわからん…。
色々試したけど、どうにかエラーが出ない感じになったかもしれず。とりあえず、Main.as は下のようになった。
package com.blawat2015 { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Rectangle; import starling.core.Starling; [SWF(width="480",height="320",frameRate="60",backgroundColor="#000000")] /** * Starling + ウインドウサイズ変更のテスト */ public class Main extends Sprite { private var myStarling:Starling; private var resize_exec:Boolean = false; /** * コンストラクタ */ public function Main():void { // stage が既に存在しているなら即座に、 // stage が存在していないならステージ生成時に、初期化メソッドを呼ぶ。 if (stage) init() else addEventListener(Event.ADDED_TO_STAGE, init); } /** * 初期化処理 * @param e */ private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.quality = StageQuality.BEST; // Starlingのインスタンスを生成 var viewport:Rectangle = new Rectangle(0, 0, _g.STGW, _g.STGH); myStarling = new Starling(MySprite, stage, viewport, null, "auto", "baseline"); myStarling.antiAliasing = 1; // アンチエイリアス設定 myStarling.showStats = true; // 状態表示有効化 myStarling.enableErrorChecking = true; // エラーチェック myStarling.start(); // 描画処理開始 // ウインドウリサイズ時の処理を設定 stage.addEventListener(Event.RESIZE, onResize); } /** * ウインドウリサイズ時に呼ばれる処理 * @param e */ private function onResize(e:Event):void { // 処理中にイベントが再発生するとマズいので、フラグでチェック if (resize_exec) return; resize_exec = true; var v:Rectangle, sw:int, sh:int; myStarling.stop(); // 念のために描画を停止しておく do { sw = stage.stageWidth; sh = stage.stageHeight; v = new Rectangle(0, 0, sw, sh); // 縦横拡大率を求める _g.wdw_scaleX = sw / _g.STGW; _g.wdw_scaleY = sh / _g.STGH; if (_g.wdw_scaleX > _g.wdw_scaleY) { // 横に引き延ばし過ぎ var w:int = int(_g.STGW * _g.wdw_scaleY); if (v.width > w) v.width = w; v.x = int((sw - v.width) / 2) & 0xfff8; _g.wdw_scaleX = _g.wdw_scaleY; } else if (_g.wdw_scaleX < _g.wdw_scaleY) { // 縦に引き延ばし過ぎ var h:int = int(_g.STGH * _g.wdw_scaleX); if (v.height > h) v.height = h; v.y = int((sh - v.height) / 2) & 0xfff8; _g.wdw_scaleY = _g.wdw_scaleX; } // 処理中にウインドウサイズが変更されてたら算出し直し } while (sw != stage.stageWidth || sh != stage.stageHeight); myStarling.viewPort = v; myStarling.stage.stageWidth = _g.STGW; myStarling.stage.stageHeight = _g.STGH; myStarling.start(); // 描画再開 _g.wdw_w = sw; _g.wdw_h = sh; resize_exec = false; } } }ちなみに、main.as とは別に、MySprite.as、_g.as が用意してある。
ハマってた時のソースから変えた部分をメモ。
- new Starling() を呼ぶ際に与えるパラメータを、巷のサンプルでよく見かける記述から少し変えてみた。巷では、new Starling(MySprite, stage, viewport); になってることが多い印象。
- リサイズ時に、Starling.current.viewPort = 〜 ではなくて、既に記憶していた Starling のインスタンス変数を使うようにした。
- 短い時間内に連続してリサイズ処理が呼ばれる場面があるのかと思い、一定時間が経過してからリサイズ処理をするようにしてみたけど改善されず。なので、そういう複雑(?)なことは全部止めて、リサイズイベントが発生したら、すぐにさっさと処理するようにした。
- リサイズ時に、Starling.stop()、start() を呼ぶようにした。しかしコレをしても改善しなかったので関係ないかも。
- viewPort を弄る直前まで、処理途中でウインドウサイズが変更されてる可能性を意識するようにした。もし、途中でウインドウサイズが変わってたら、do - while の部分で処理をし直す。
以下、よくわかってないけど。
- viewPort に与えるのは、実際のウインドウサイズ内で、どこからどこまでを表示範囲にするか、という値。Rectangle の x,y が、領域の左上。width, height が、領域の縦横幅、なのかな?
- Starling.stage.stagWidth, stageHeight に与えるのは、表示範囲を、何x何ドットの領域として扱うか、という値。
- 480x320 のゲーム(?)画面を、1920x1080のウインドウサイズ内に表示しようと思ったら…。
- viewPort には x,y,w,h=(0,0,1920,1080) を与えて、stageWidth,stageHeight には (480,320) を与える。
- これだと縦横比が妙なことになる・横に引き延ばされた見栄えになる。
- 縦横比を合わせて、表示範囲をセンタリングしたいなら、viewPort に、x,y,w,h=(150,0,1620,1080) を与える。
[ ツッコむ ]
以上です。