left,top より setPos の方が高速

Posted 2013.06.26 in 吉里吉里

レイヤーの縦横位置を変更するには


layer.left = 100;
layer.top = 100;

とする方法と


layer.setPos(100, 100);

とする方法があるが

setPos の方がはるかに高速である!

2つの方法の違い

この2つの方法はまったく同じ意味に見えるが…
実は2つの方法には大きな違いがある。

left, top の方が関数を呼び出していない分、より高速なのではないかと思うかもしれないが、
left, top はプロパティなので、実質的には関数を2回呼び出していることと同じだ。
よってむしろ setPos の方が関数呼び出し1回で済む点において高速である。

しかしそんなことは些細な違いでしかない。

それよりもずっと大きな、決定的な違いがある。
それは

無効領域の発生タイミング

にまつわる動作の違いである。
ちなみに無効領域とは、画面上において再描画が行われる領域のことである。

動作の確認

動作の違いを確認してみよう。


class TestWindow extends Window
{
  function TestWindow()
  {
    super.Window();
    
    // プライマリレイヤー作成
    var w = 200;
    var h = 200;
    add(new Layer(this, null));
    primaryLayer.setImageSize(w, h);
    primaryLayer.setSizeToImageSize();
    setInnerSize(w, h);
    primaryLayer.fillRect(0, 0, w, h, 0); // 黒
  }
  
  function onKeyDown(key, shift)
  {
    // Enterキーが押されたらレイヤーを作成する
    if(key == VK_RETURN)
    {
      // レイヤーを作成
      var w = 100;
      var h = 100;
      var layer = new Layer(this, primaryLayer);
      add(layer);
      layer.setImageSize(w, h);
      layer.setSizeToImageSize();
      layer.fillRect(0, 0, w, h, 0xFFAAAAAA); // 灰
      
      // レイヤーを移動
      layer.visible = true;
      layer.left = 100;
      layer.top = 100;
    }
  }
}

var win = new TestWindow();
win.visible = true;

これを実行したらまずウィンドウを選択して Shift+F11キー を押し
更新矩形を表示するモードにする。
そして Enterキー を押すと次のようになる。

KiriKiri_setPos1

黄色い枠で示されているのが無効領域となり、再描画が行われた領域である。
細かく区切られているように見えるのは、キャッシュ効率を上げるための描画分割による作用だ。

レイヤーが移動する時、無効領域は2つ発生する。
『レイヤーが移動する前の領域』 と
『レイヤーが移動した後の領域』 だ。
画面の左上の領域が 『レイヤーが移動する前の領域』
画面の右下の領域が 『レイヤーが移動した後の領域』 である。

注目して欲しいのは、なんの関係もない右上の領域が再描画されている点だ。
では、これを setPos に置き換えて実行してみよう。


      // レイヤーを移動
      layer.visible = true;
      layer.setPos(100, 100);

KiriKiri_setPos2

右上の領域が無駄に再描画されなくなった!

何が起きているのか

この動作の違いは、先に述べたように 『無効領域の発生タイミング』 に起因している。

無効領域は、レイヤーに対して
操作を行った直後に発生する。

left, top プロパティで位置を変更する方法の場合
left = 100; とした時点で無効領域が発生し
top = 100; とした時点で無効領域が再度発生するという動作になる。
そう、これによって右上に無駄な無効領域が発生し、無駄な再描画が行われてしまったのだ。

setPos の場合、leftとtopを両方変更してから無効領域が発生する。
よって、無駄な無効領域が発生せず、無駄な再描画も行われない。
最初に「setPos の方がはるかに高速」と言ったのはこのことである。

まとめ

このようなことからレイヤーの縦横位置を同時に変更する時は
left, top プロパティよりも setPos 関数を使うべきだと言えるだろう。


Leave a Reply

*