【Unity】構造体の配列(NativeArray)と参照渡し
今回は構造体を配列(NativeArray)にした時の、そのアクセスについてです。
ECSとJobSystemは構造体の配列を使う
最近よく紹介されているECSやC# Job Systemといった機能では、構造体をNativeArrayに乗せて一括制御するアプローチが見られます。
というのもECSやJobSystemはDODの考えでメモリ内にデータが散らばるのを嫌がるので、殆どStructで実装されています。
それ自体は大した問題では無いのですが、基本的に構造体の配列は参照渡し出来ないので少しコードが冗長になる印象があります。
出来れば構造体でも参照渡しで直接値を書き換えたい所です。
今回はそれを色々とやってみます。
配列からrefやoutで参照を貰う事は出来ない
C#で参照渡しといえばrefやoutです。
構造体などの基本的にコピーを生成する受け渡しであっても、refを指定しておければ参照を渡して中身を書き換えることが出来ます。
ただ残念なことに、通常の構造体なら問題なくとも配列に対してとなると上手くはいきません。配列(インデクサー)は残念ながらoutやrefを使えないのです。
そうだ、unsafeを使おう
最終手段です。unsafeを使います。ポインタを使用してNativeArrayの各要素に直接語りかける訳です。
GetUnsafeReadOnlyPtrを使用してNativeArrayのポインタを取得、あとは要素をズラせば中身が取れます。
ただ、何かの処理を行う場所でもunsafeを要求するのは余り良くないかもしれません。
なおNativeArrayにfixedは必要ありません。
またNativeArrayは連続していますがComponentDataArray等のECSがInjectする要素は連続してるとは限らないので、要素をずらした時に正しく取れない点に注意です。
ArrayElementAsRefで要素のrefを取得する
Incremental Compilerを導入すると、C#7.2が使えるようになり要素のrefが使えるようになります。ソレに合わせてArrayElementAsRefというAPIが追加されるので、コレを使って要素をrefで取得してメソッドに受け渡す的な事も出来るようになります。
UnsafeUtilityExって、もう少し良い名前は無かったのか感あるので、今後変わる気もします。
関連
Incremental Compilerの効果についてのまとめです。
要するにC# 7.2がつかえるようになる他、コンパイル時間短縮も期待出来ます。
但し、現在は記事で紹介されているような、manifest.jsonを書き換えなくともpackagemanagerから導入出来ます。
Unsafeの設定方法について