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

ちなみに

火曜日の空は僕を押しつぶした。

Unity 4.5 の New Hierarchy Window sorting について

TL;DR

Unity 4.5 でヒエラルキービューのソーティングアルゴリズムが変わった。 ソーティングアルゴリズムを自分で作成することもできるようになり、柔軟に並び替えが出来るようになった。 エディタ上の見た目だけの問題かと思っていたら思わぬ問題に遭遇した。

  1. Transform の GetChild メソッドで取得できるオブジェクトは標準のソーティングアルゴリズムに従う。よって、自前のソーティングアルゴリズムで並び替えていてもスクリプトからは標準アルゴリズムで並んでいることを前提に操作しなくてはいけない。
  2. 同じプレハブから生成した GameObject のソート順が実行する度にランダムに変わる問題がある。

1 と 2 のコンボで見た目上問題ないのにスクリプトから取れるオブジェクトが違って死ぬみたいなことに遭遇した。Prefab から作った GameObject は Prefab の参照を切って使うしか回避策がない。

2 についてはどう考えてもバグなので Bug Report を送った。


Unity 4.5 transform sorting bug with prefab.

まえがき

Unity 4.5 が出てうちのチームでも 4.5 を使い出した。基本的には快適に使えている。

ところで、今回の リリースノート のなかに以下のような文言がある。

New Hierarchy Window sorting - sorting of elements is now based on transform order instead of name.

これまでの Unity はヒエラルキービューでのソート順は 数値アルファベット順 (AlphaNumeric) に固定されており、任意の順番には並び替えることが出来なかった。

そのため、並び順を保証するために GameObject の名前に _1_ のようなプレフィクスを付けて任意の順番を作っていた。

それが 4.5 になって任意の順番に並び替えることができるようになった。任意順を標準の Transform Sort として、自作のソーティングアルゴリズムを実装して追加することも出来るようになっている。これによってより柔軟な開発が出来るようになった。(かのように見えた)

一見素敵なことのように見えるこの仕様ですが、2つの問題にぶつかった。

1つ目の問題

BaseHierarchySort を継承したエディタ拡張を作ることで任意の順番でヒエラルキービューをソート出来るようなった。 リファレンス にも、これまでと同様の数値アルファベット順でのソートの例が載っている。

例えばこのサンプルの AlphaNumericSort を Editor ディレクトリに置くと以下のようなソート順を選べるメニューが表示されて、そこから並び順を選ぶことができるようになる。

すでに開発が進んでいてもとのソート順を前提に作っていたので、これはべんりと即採用してチーム全員で使うようにした。

ところが、どうも内部的なインデックスは標準のソート順にそっているということが分かった

たとえば、子供の GameObject が AlphaNumericSort で 1、2、3、4、5 と並んでいて、でも TransformSort だと 5、4、3、2、1 と並んでいるとする。

for (var i = 0; i < this.transform.childCount; i++)
{
    var child = this.transform.GetChild(i);
    Debug.Log(child.name);
}

この時、上記スクリプトの結果は以下のようになる。

5
4
3
2
1

ぜんぜん 数値アルファベット順 じゃない。

これは NGUI を使っていて、UIGrid などで均等配置しようとしたときに露呈する。思っている順番と全く違う順番で整列されるのだ。これは UIGrid が内部的に Transform. GetChild を読んでいて、引数に与えたインデックスの位置には Transform Sort 順で並んでいる GameObject がいるからである。

2つ目の問題

もう一つ問題が起きた。連番で並べている GameObject が実行する度にランダムに並び順(Transform Sortでの)が変わったのだ。

最初は UIGrid が並び替えているのかと思ったけど、どうもそうではないらしい、ランダムで並び替わるから、UIGrid は律儀にそれに合わせて整列していただけだった。1の影響でいくらエディタの見た目上で 数値アルファベット順 に並び替えていたとしても内部的に並び順が変わるので影響を受けていた。

調べてみると Prefab から作った同じオブジェクトの場合だけ起きていることが分かった。まっさらなプロジェクトを作って実験してみると、上に張った動画のような挙動になることが分かった。

f:id:Sixeight:20140530213925p:plain

これが実行すると

f:id:Sixeight:20140530213937p:plain

こうなる。

どう考えてもバグっぽいので、Bug Report を送ったので反応待ちというところ。

いまのところの回避策

Prefab から作成した GameObject は Break Prefab Instance して参照を切ると回避できる。 でもこれだと同じ構造の GameObejct を Prefab を使って一気に編集するというメリットが得られないしなるだけ早く直ってほしい。

f:id:Sixeight:20140530214158p:plain