[ActionScript 3.0] Event.RENDERとinvalidateでタイムラインが進む直前で描画する

[ActionScript 3.0] Event.RENDERとinvalidateでタイムラインが進む直前で描画する

AS3.0で、表示リストをレンダリングする必要のある次の機会に、表示オブジェクトに通知する方法です。

Event.RENDER と invalidate について

どういうことかというと、AS3.0の独自で作ったクラスに、widthプロパティをオーバーライドしたり backgroundColorプロパティを用意して背景に色を塗ったりしたいとき、「幅の値 → 背景色の色」と値を指定していくと 2回レンダリングしてしまうわけで、それを避ける方法として Event.RENDERinvalidateメソッドがあります。

この方法を使うと、Flashが次のタイムラインにレンダリングする直前のタイミングで処理してくれるので、タイムラインが進む前に設定がかぶっても処理は一回で済むのだ。

使い方

使い方は、設定するメソッド(例えば widthプロパティ や backgroundColorプロパティ)に stage.invalidate() を置き、コンストラクタに addEventListener(Event.RENDER, draw) と書いて、drawメソッド内に処理を付け加える。

例えば、縦横100pxの黄色い背景みたいな指定の場合、それぞれのメソッドが高さ、横幅、背景色と3回あるので stage.invalidate() も3回叩かれるが、drawメソッドの処理はタイムラインが進むタイミングのときに一回だけ走る。

以下のソースコードは、指定されたサイズと色の矩形を描画するサンプルです。
drawメソッド内は好きなようにごにょごにょしてくだされ。

package {
    import flash.display.Sprite;
    import flash.events.Event;
    public class Example extends Sprite {
        private var _width:Number = 0;
        private var _height:Number = 0;
        private var _backgroundColor:uint = 0;

        public function Example() {
            addEventListener(Event.RENDER, draw, false, 0, true);
        }

        /**
         * 表示オブジェクトの幅を示します(ピクセル単位)。
         */
        public override function get width():Number {return _width;}

        /**
         * @private
         */
        public function set width(value:Number):void {
            _width = value;

            // 表示リストをレンダリングする必要のある次の機会に、表示オブジェクトに通知する。
            if (stage) stage.invalidate();
        }

        /**
         * 表示オブジェクトの高さを示します(ピクセル単位)。
         */
        public override function get height():Number {return _height;}

        /**
         * @private
         */
        public function set height(value:Number):void {
            _height = value;

            // 表示リストをレンダリングする必要のある次の機会に、表示オブジェクトに通知する。
            if (stage) stage.invalidate();
        }

        /**
         * 背景色を指定します。
         */
        public function get backgroundColor():uint { return _backgroundColor; }

        /**
         * @private
         */
        public function set backgroundColor(color:uint):void {
            _backgroundColor = color;

            // 表示リストをレンダリングする必要のある次の機会に、表示オブジェクトに通知する。
            if (stage) stage.invalidate();
        }

        /**
         * タイムラインが進む直前で描画します。
         * @param event
         */
        private function draw(event:Event):void {
            if (_width == 0 || _height == 0) return;
            graphics.clear();
            graphics.beginFill(_backgroundColor);
            graphics.drawRect(0, 0, _width, _height);
            graphics.endFill();
        }
    }
}

最後に

AS2.0のときはあまり気にしなかったタイムラインのライフサイクルだけど、AS3.0だとそこら辺が有効に制御できます。
ちょいと難しいけど、覚えておくとちょっとだけ幸せになれます。