Unity3Dでの配列に関しての検索が多かったので記事を書きました。

具体的にどのような場面で使用するかといえばやはり配列とそのソートでしょうか
ゲーム中でアイテムの登録やアイテムの整理やらのデータの並べ替えなどが問題になることが多いです。

どんなことに使用するの?ということで いちおう例をあげておきます。

現在作成中のDota系ゲームではミニオンのジェネレート地点から敵のベースまでの移動経路に配置された
waypointデータをソートするのに配列ソートを使用しています。
まず最初にwaypointにwaypoint本体の値(Transform)と敵のベースまでの距離をclass作成して
距離をキーとしてwaypointの並べ替えを行なっています。
Inspectorで一個づつ近い順に登録してももちろん有効ですけど データが変わるたびにその労力はいやでしょ?w

なのであらかじめ
WaypointMasterというスクリプトを親につけて複数のwaypointをその子供にして 

■WaypointMasterの冒頭

class Destination{


var distance:float;
var trans:Transform;

}

function Start(){
for( var trans:Transform in transform){
distination = new Destination();

destination.distance = Vector3.Distance(trans.transform.position,DestinationPoint);
destination.trans = trans;

DistinationArray.Push(new DestinationResult(distination));
}
         ・
         ・
         ・

}


これをdistanceをキーにしてソートするなどというように使用しています。 
まあ細かいところはそのうち解説いたしますので 今回は配列のお話を。。


■Unity3Dで扱える配列

http://robotduck.wordpress.com/2009/11/04/88/   //配列に関する記事
この記事を読めばほとんどわかってしまう内容なのですが、リンク先の記事を眺めてから読んでみてください。

Unity3Dであつかえる配列には以下のようなものがあります

■ビルトイン配列
■Javaスクリプトタイプの配列
■ハッシュテーブル
■ArrayLists(辞書型配列)
■Generic配列
■2次元配列 など



■ビルトイン配列
ビルトイン配列(builtin_Array)は大きさが決まっていない配列で高速に処理できるものです。
var values : int[]];
var values : float[];
var values : String[];
var values : GameObject[];


などのようにほとんどの型がこの指定で配列化できます。ただしこのまま使用するとエラーが出ると思います。
なぜならばデータに大きさがないため初期化のプロセスが必要だからです。
これはAwake()またはStart() のfunctionで


var values:int[];

function Awake(){

values = new int[10];


として配列を確保してやる必要があります。
初期化と同時に数値を代入したい場合は

var values:int[]=[0,0,0,0,0,0,0,0,0,0]

としてやると配列宣言と初期化を同時にしていることになります。

まだこのブログでは解説していませんがclassを使用する場合


var CLASSArray : CLASS[];

class CLASS{

 var1:int;
var2:float;
var3:String;


function Awake(){

CLASSArray = new CLASS[1]; // 配列の領域確保

CLASSArray[0] = new CLASS(); // 空のクラスを代入

CLASSArray[0].var1 = 5;
CLASSArray[0].var2 = 5.0;
CLASSArray[0].var3 = "test";



クラスを代入のところを私は

for(i=0; i<CLASSArray.length; i++){

CLASSArray[i] = new CLASS();

}

なんて風に書いてるんですけど他の書き方があったらだれかヘルプミーです。



■Javaスクリプトタイプの配列

リファレンスの解説を翻訳(意訳)しました

function Start () {
var arr = new Array ();
  
 arr.Push ("Hello");    // elementの追加
arr.length = 2;      // arrayのリサイズ
 arr[1] = "World";     // セカンドエレメントの追加

  for (var value : String in arr) {  // 配列から値を取り出す
print(value);
}
}



/////////////////////////////////////////////

var values : float[]; // インスペクタで値を登録します

function Start () {

for (var value in values) {  // forループを使用してvaluesからvalueに値をひとつづつコピー
print(value);
}

values = new float[10]; //valuesに10個分の領域を確保

values[1] = 5.0;   //valuesの2番目の値(インデックスは0が初めで2番目が1)
}


/////////////////////////////////////////////

●配列のビルトイン配列への変換方法


function Start () {
var array = new Array (Vector3(0, 0, 0), Vector3(0, 0, 1));
array.Push(Vector3(0, 0, 2));
array.Push(Vector3(0, 0, 3));


var builtinArray : Vector3[] = array.ToBuiltin(Vector3); //配列をビルトイン配列に変換  <.ToBuiltinを使用して変換 型は 左側=右側にあわせる

var newarr = new Array (builtinArray); //ビルトイン配列を配列に変換


print (newarr);
}



■配列型のリファレンス

●Variables
length 配列の長さを返す

●Constructors
Array 配列型の指定

●Functions
Concat    配列の結合
Join      値をひとつだけ結合
Push   配列の最後に値を追加する
Add      同上
Pop      配列の最後の値を取り出す
Shift       配列の最初の値を取り出して返す
RemoveAt インデックス(0,1,2‥)で指定した値を削除する
Unshift   配列先頭にひとつ以上の値を追加?配列の長さを更新する。
Clear    配列の値を0に初期化する
Reverse    配列並びを反転する
Sort      配列を規則にそってソートする(abc順、値が小さい順など)


Q.ビルトイン配列にArrayみたいに値を追加したいときはどうすんの?

話が前後しますがビルトイン配列には通常の配列操作のような機能(function)がついていないようです。
それで一度新しく配列をつくってそちらで操作する方法があるようです。

var builtinArray : MyClass[];

function Start () {
var enemies = new Array(builtinArray);
enemies.push(new MyClass());
}


でここまで覚えた所でビルトイン配列のソートですが↓のリンク
http://answers.unity3d.com/questions/22261/sorting-builtin-arrays.html

例の中ではクラスを使ったものが使いやすかったです。

import System;

class RaycastResult implements IComparable
{
var distance : float;
var collider : Collider;

function RaycastResult(hit : RaycastHit)
{
distance = hit.distance;
collider = hit.collider;
}

function CompareTo(other : System.Object) : int
{
if (!(other instanceof RaycastResult)) return;
var raycastResultOther : RaycastResult = other;
return distance.CompareTo(raycastResultOther);
}
}

var raycastResults : Array = new Array();

function SortDistances()
{
raycastResults = new Array();
var hits : RaycastHit[] = Physics.RaycastAll(transform.position, transform.forward, 100.0);

for(var hit : RaycastHit in hits)
{
raycastResults.push(new RaycastResult(hit));
}
raycastResults.sort();

}

これは一度にPhysics.RaycastAll()を使用してオブジェクト前方に例キャストしてヒットしたものを配列hitsに
格納してしまっています。
それをraycastResultsにpushで登録して ソートするわけですが。
CompareTo()のファンクションの中のdistance.CompareTo(raycastResultOther)が距離distanceをほかの値と比較して
小さい方を返す部分です。 distanceを他の値に変えれば条件が変わります。

■ArrayList


ArrayListクラス
http://msdn.microsoft.com/ja-jp/library/7x4b0a97(v=vs.80).aspx

Javaの配列に操作が似ているけれどJavaとC#両方からつかえる点が異なるようです。
リンク先のメンバの解説を読んでつかってみてください。 なげやりw
 

■ハッシュテーブル

http://msdn.microsoft.com/ja-jp/library/system.collections.hashtable.aspx
http://msdn.microsoft.com/ja-jp/library/system.collections.hashtable_methods.aspx


ハッシュテーブルは連想配列とも呼ぶようで辞書の一種ですね 普通の配列と少し違って
『キー と 値』の 2つでワンセットに格納されます。

import System.Collections.Hashtable; //JavaScriptの場合importでC#の場合はusingでライブラリ仕様宣言します


myhash = {"name":"John", "occupation":"programmer"};

Debug.Log( myhash["name"] ); //displays "John"


ハッシュテーブルのメソッド
Count ハッシュテーブルの長さ


Clear     値をクリアー テーブル長さを0に
Remove     キーと値の削除
ContainsValue  与える値と同じ値がテーブルに入っているか確認
ContainsKey   与えるキーと同じキーががテーブルに入っているか確認
Contains      キーか値の確認でいいのかな?.
Add        キーと値をテーブルに追加


●ハッシュテーブル(辞書)のソート

http://forum.unity3d.com/threads/6335-associative-arrays-hashtables



function SortHashtable (inpHash : Hashtable) {

var iVal; var key; var arrayValues = new Array(); var valuesKeysHash = new Hashtable(); var returnArray = new Array();



for (key in inpHash.Keys) {

arrayValues[arrayValues.length] = inpHash[key];

valuesKeysHash.Add(inpHash[key], key);

}


arrayValues.Sort();


for (iVal in arrayValues)

returnArray[returnArray.length] = valuesKeysHash[iVal];

return returnArray;

}




■Generic配列

かなり様々な操作が行える上に早いので なれれば使いやすい?
C#のひとは断然これをつかうんでしょうね

●参照
http://answers.unity3d.com/questions/166789/iterate-through-generic-list.html

http://msdn.microsoft.com/ja-jp/library/6sh2ey19(v=vs.80).aspx

Listのメソッド
http://msdn.microsoft.com/ja-jp/library/s6hkc2c4(v=vs.80).aspx


■基本仕様例

var myList = new List.<型>();

myList.Add(値);

myList[インデックス] = 値;

myList.RemoveAt(インデックス);




例)

import System.Collections.Generic; // ライブラリのインポート

var phraseList = new List.();

function OnGUI () {

var i : int = 0;
for (str in phraseList) {
if (GUI.Button (Rect (100, 20 * i, 200, 20), str)) {
Debug.Log ("Box #" + i + " is working!");
}
i++;
}

}

function Update () {
if (Input.GetKeyUp ("z")) {
phraseList.Add("Test string 1");
phraseList.Add("Test string 2");
phraseList.Add("Test string 3");

}

}




■2次元配列

2次元の配列ですよ 指定方法はカンマで区切って宣言するだけです。

var myArray = new string[0,1];

var width = myArray.GetUpperBound(0); //2次元配列の次元の上限を返す
var length = myArray.GetUpperBound(1);//2次元配列の次元の下限を返す




調べていたらちょっと特殊な2次元配列の使い方をみつけたのでピックアップ
GameObject型に2次元配列を使用してステージを作るやり方ですかね なんかにつかえそう。

http://answers.unity3d.com/questions/168822/2d-array-of-gameobjects.html


public var spawn = 15;
public var rows = 10;
public var cols = 10;
public var gemObject: GameObject;
public var pieces: GameObject [,];
public var gems: Object [];

function Start () {
//Initializing variables
pieces = new GameObject[rows, cols];

//load's gems from the resources Gem folder to this object array
gems = Resources.LoadAll("Gems", GameObject);

for (i = 0; i < gems.Length; i++)
Debug.Log("gems #" + i + "is: " + gems[i].name);

for (i = 0; i < rows; i++) {
for (j = 0; j < cols; j++){
pieces[i,j] = Instantiate (gems[i], Vector2(i,j), Quaternion.identity);
}
}
}



以上私も全部の機能を使ったわけではないので間違いがあるかも知れませんので ご容赦ください。
で そろそろ本業のビジュアル的な部分や企画的なことなどもやっていこうかなーと 思っています。。。。。。。仕事が入らなければ