読者です 読者をやめる 読者になる 読者になる

なんて事言っても始まらないし少しは建設的に行こうよ俺


id:keim_at_Si:20070913の続き。


昨日書いたネガティブ要素の解決について。

基本はベクター描画

とりあえず、ActionScriptが必ずしもベクター描画である必要が無いという事は、
2年も前に先人様方がいろいろ検証してくれました。
当時と比べるとAS3仕様も変わったので若干の変更は必要だけど、大筋この方法で解決。
ARCANACRAでは、描画回数の多い弾をcopyPixels(BitmapData)、
回転描画を多用したい敵をdraw(Shape)で使い分けています。

Flashスプライトの木構造の使用が必須

Spriteを一個だけ作って、そいつのaddEventListner(Event.ENTER_FRAME)の
コールバック内で1フレーム内のすべての処理を行う。
描画は、上述SpriteにaddChild(Bitmap)をして、このBitmap上に
コールバック中にfillRect/copyPixels/draw等で書き込めばOK。

FPS管理がFlash任せ

これはちょっと微妙。
まず、上述メインのコールバック内でフレーム数をカウントする。
で、それとは別にTimerを使って1秒毎にコールバック。
このTimerのコールバックの時に、メインコールバックでカウントしたフレーム数を検証。
stage.fpsで設定した値より小さかったら、不足フレーム数を次の1秒内で余計に動作させる。
これで一応、1秒毎にフレーム数を訂正することが出来るんだけど、
id:keim_at_Si:20070515#p2の通り、Timerのコールバックは結構不正確なので、
この方法による音楽との同期とかは無理。
ただし、別スレッドとかで処理が走って一時的に遅くなるような場合には有効っぽい。
以下、イメージ図。

//--------------------------------------------------
// メイン
//--------------------------------------------------
class Main extends Sprite
{
    private var timer:Timer = new Timer(1000, 0);
    private var frameCounter:int = 0;
    private var overFrames:int = 0;

    public function Main()
    {
        timer.addEventListener(TimerEvent.TIMER, _onTimer);
        stage.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
        timer.reset();
        timer.start();
    }

    private function _onEnterFrame(e:Event) : void
    {
        ++frameCounter;
        _run();               // とりあえず一回は処理。
        if (overFrames > 0) {
            --overFrames;
            _run();           // フレームオーバー分をもう一回処理。
        }
        _draw();
    }

    private function _onTimer(e:TimerEvent) : void
    {
        var diff:int = stage.fps - frameCounter;
        overFrames += (diff < 0) ? 0 : diff;
        frameCounter = 0;
    }

    private function _run() : void
    {
        // ここで1フレ処理
    }

    private function _draw() : void
    {
        // ここで描画関係
    }
}

もっとも、この書き方だと処理落ち発生時、急に2倍速になるし、
2倍以上の処理落ちには対応できない。でもま、こんなもんで。

これらの理由で遅い、安定しない

Spriteでベタに書くよりはかなり速くなる。でも近年のPCとしてはやっぱり遅いのかも。
でも、ベーマガ世代には十分過ぎる速さだよね。