Unityな日々(Unity Geek)

Unityで可視化アプリを開発するための試行錯誤の覚書

スクリプトのテンプレートを追加する

スクリプトを新規作成する際に、独自のテンプレートを使いたいことがあるとおもう。

その場合は、Unityのインスールフォルダ/Editor/Data/Resources/ScriptTemplates/の下にある、

  • 80-Javascript-NewBehaviourScript.js.txt
  • 81-C# Script-NewBehaviourScript.cs.txt
  • 82-Boo Script-NewBehaviourScript.boo.txt
  • 83-Shader-NewShader.shader.txt
  • 84-Compute Shader-NewComputeShader.compute.txt

を修正するか、あるいは、新規にテンプレートファイルを追加する。

僕の場合、主に使うC#用テンプレートにヘッダコメントとNamespaceをデフォルトで入れたテンプレートを作っている。

// Title
// First Version 2015/mm/dd by A.Y.@XOOMS
// Last Update   2015/mm/dd by A.Y.@XOOMS
//
using UnityEngine;
using System.Collections;
using Xooms;

namespace Xooms{
    public class #SCRIPTNAME# : MonoBehaviour {

        // Initialization
        void Start () {
    
        }
    
        //
        void Update () {
    
        }
    }
}

これを、オリジナルのC#テンプレートに上書きしてもよいが、オリジナルのテンプレートは残したい場合は、別名で保存する。

ファイル名は、'番号+表示名-スクリプト種類.拡張子.txt'となり、'-'ハイフンより前の、番号+表示名は自由に設定できる。番号は数字のほかアルファベットでもいいようだ。要は番号部分のテキストの小さい順番に、メニューに並ぶ。

たとえば81A-C#XOOMS Script-NewXoomsScript.cs.txtという別の名前で保存すると、正規のC#テンプレートの次に、オリジナルテンプレートが表示される。

f:id:yasuda0404:20150309164902p:plain

Materialを比較する

あるオブジェクトにアサインされている特定のマテリアルを別のマテリアルに置き換えたかったので、次のようなコードを書いた。

[SerializeField]protected Renderer rend; //Target Renderer
[SerializeField]protected Material matFrom; //Change from this material
[SerializeField]protected Material matTo;   //Change to this material

<途中省略>

void Change()
{
    Material[] mats = rend.sharedMaterials;
    Debug.Log("ChangeMaterial: mats.Length= "+mats.Length);
    for(int i=0;i<mats.Length;i++) {
        Debug.Log(i+" Spec Int "+mats[i].GetFloat("_SpecInt"));
        if(mats[i] == matFrom) {
            Debug.Log("ChangeMaterial:Material("+i+" changed");
            mats[i]= matTo;     //Replace the material
        }
    }
    rend.materials = mats;  //Reassign Materials
}

ところがこれは機能しない。マテリアルはRunTimeでインスタンス化されるが、インスペクタでアサインしたマテリアルはインスタンスではない。このため、mats[i] == matFromという比較が真にならない。

そこで、マテリアルの名前で比較しようと思い、比較分の箇所を

if((mats[i].name == matFrom.name)...

と書いたが、これもうまくいかない。マテリアルがインスタンス化されると名前も変わるからだ。

結局、

if(mats[i].name == (matFrom.name+" (Instance)")) {

と、元の名前の後に" (Instance)"を加えれば、一応うまくいった。

しかし、もっとスマートな比較方法がないものだろうか…。

Canvas UI(uGUI)のイベント処理

CanvasUI(uGUI)システムでは、ユーザの操作をEventで授受する。たとえばButton要素の場合、インスペクタのButtonスクリプト・ブロックの一番下に、OnClick()という項目がある。ここにOnClick()イベントを受け取る関数と渡す引数を設定する。

f:id:yasuda0404:20150307145538p:plain

タブの"+"をクリックし、左下の枠にイベントを渡すGameObjectを設定し、右上の枠にイベントを送る関数をドロップダウンリストから設定する。左下は関数に渡す引数で、

  • なし
  • float
  • int
  • string
  • bool
  • Object

のいずれか。最後の"Object"はUnityのほとんどのクラス(たとえばGameObject, Component, Monobehaviourなど)のベースクラスなので、実質的にはほとんどのクラスを引数に指定できる。たとえばTransformや、GameObjectそのものも渡すことができる。

ユーザー定義関数を呼び出すサンプル

たとえば、ボタン要素のクリック時のアクションとして、

1) UIControllerのButtonClick()メソッドに、"CustomButton"というstringを渡す場合:

f:id:yasuda0404:20150307142006p:plain

2) ButtonClick2()に、カメラのTransformコンポーネントを渡す場合:

f:id:yasuda0404:20150307141924p:plain

等というように設定する。

なお、UI要素から呼び出すユーザ定義関数はpublic voidのみ、渡せる引数の個数は0か1であることに注意。

ちなみに受け側の関数は次のようになる。

public void ButtonClick(string name)
    {
        Debug.Log("Button "+name+" clicked.");
    }

    public void ButtonClick2(Transform cameraTransform)
    {
        Debug.Log("Camera Position "+cameraTransform.position);
    }
その他のイベント

OnClick()以外のイベントを生成・処理したい場合は、EventTriggerを使う。

イベントを生成したいUI要素を選択し、Component-Event-EventTriggerを選択。

f:id:yasuda0404:20150307144247p:plain

UI要素にEventTriggerコンポーネントが追加される。Add New Event Typeをクリックして該当するイベントタイプを選択、後はOnClick()と同様に、イベント受信先のGameObject、イベントを受け取る関数、引数を設定する。

f:id:yasuda0404:20150307144540p:plain

EventTriggerを使えば自由にEventを生成できる。たとえば、UIImage要素はデフォルトではイベントを持っていないが、EventTriggerを使ってOnClickPointer Enterイベントを追加することができる。

参考:

qiita.com

C#のプロパティを理解する

プロパティの使用 (C# プログラミング ガイド)

C#にかぎらずオブジェクト指向言語のクラス内の変数を外部から読み出したり、変数に値を設定する場合は、get/setメソッドを使うのが基本。しかし、変数ごとにいちいちget/setメソッドを設定するのは煩雑になってしまう。

そこでC#では「プロパティ」というしくみがつくられた。プロパティは、クラスの外から見ればget/setメソッドのように見え、クラス内部から見れば普通の変数として扱える。

次のサンプルコードでは、int Monthにgetアクセサとsetアクセサが設定されている。getアクセサはクラス外から値を読むときに実行され、setアクセサは値を設定するときに実行される。 setは、プロパティと同じ方のvalueという暗黙のパラメータを介して値を設定する。

public class Date
{
    private int month = 7;  // Backing store

    public int Month
    {
        get
        {
            return month;
        }
        set
        {
            if ((value > 0) && (value < 13))
            {
                month = value;
            }
        }
    }
}

プロパティを使うメリットは、メソッドを増やさずにメソッドと同等のことができること。たとえば、値が読まれた時にデバッグ出力したり、イベントを発行する、値が設定される際に範囲チェックを行なう(上の例)、などだ。

Inputの種類

Unityにはさまざまな入力APIが準備されている。
Unity - Scripting API: Input


Static関数としては次がある。Down/Up=Yesは、たとえばGetKeyに対して、GetKeyDown/GetKeyUpというメソッドもあるということ。

入力機器 メソッド 引数 戻り値 Down/Up
キー GetKey(string) キー名 bool Yes
マウスボタン GetMouseButton(int) 0:左,1:右,2:中 bool Yes
ボタン GetButton(string) 仮想ボタン名(*1) bool Yes
アクシス(スムージングあり) GetAxis(string)(*2) 仮想アクシス名(*3) float -1~+1 No
アクシス(スムージングなし) GetAxisRaw(string)(*2) 仮想アクシス名(*3) float -1~+1 No
タッチ GetTouch(int).phase 0-Input.touchCount:指番号 タッチフェーズ No(*3)


(*1)バーチャルボタンは、Project Settings-Inputで設定する。デフォルトでは、'Fire1','Fire2','Fire3','Jump','Submit','Cancel'が設定されている。

(*2)スティックは、ジョイスティック以外に、マウスの動き、キーにもアサインできる。
GetAxisRaw()の場合のキーボード入力は、-1,0,+1のいずれかになる。

(*3)GetTouch()は、

Input.GetTouch(i).phase == TouchPhase.Began

のように、.phaseプロパティと、TouchPhaseクラスとのセットで使う。

軸周りの回転の方向

回転は一見単純な操作だが、すぐ忘れるので備忘録代わりに書いておく。


プリミティブをの円柱(Cylinder)を新規作成した場合、

transform.right :グローバルX方向&ローカルX方向=半径方向1
transform.up :グローバルY方向&ローカルY方向=円柱の軸方向
transform.forwad: グローバルZ方向&ローカルZ方向=半径方向2

となる。
f:id:yasuda0404:20141017191018p:plain


この円柱を

transform.Rotate(new Vector3(90.0f, 0.0f, 0.0f))

と、X軸周りに90度回転させる。(円柱の軸は水平方向に向く)
このとき、

transform.right :グローバルX方向&ローカル半径方向1
transform.up :グローバルZ方向&ローカル軸方向
transform.forwad: グローバル-Y方向&ローカル半径方向2

となる。
f:id:yasuda0404:20141017191251p:plain

つまり、ある軸まわりの回転は、その軸を手前から向こうに向かう方向から見たとき、反時計回りの回転となる。ねじ回しでいうと、ねじを外す方向。

当然のことだが、ローカル座標は物体にくっついて方向を変える。円柱の場合、軸方向は常にローカルY軸となる。


この円柱を軸方向に動かしたい時、どうするか。

obj.transform.Translate(10*obj.transform.up);

と書いてしまいそうだが、これではだめ。Translate()はデフォルト(=Translateの第二引数が`Space.Self`の状態)ではグローバル座標で方向を指定するからだ。
下の画像は、青い球の中心に生成した円柱を、青い球の半径分、円柱の軸方向に動かそうとしたもの。しかし、軸方向ではなく円柱の半径方向に動いてしまっている。これは、グローバル座標で(0.0, 0.0, 1.0)であるtransform.upを、円柱のローカル座標で動かしているため、矛盾が生じてしまったのだ。つまり、円柱の軸は水平を向いているが、円柱ローカルのZは下を向いているので、下方に移動してしまう。
f:id:yasuda0404:20141017194946p:plain


円柱の軸方向に動かすには、Translateの第二引数に'Space.World'を指定し、

obj.transform.Translate(10*obj.transform.up, Space.World);

とすればよい。これで、グローバルで見ているtransform.upを、正しくグローバル座標で移動できる。
f:id:yasuda0404:20141017194956p:plain



ランダムに与えた緯度・経度の示す地球表面上の地点に、垂直に円柱を立てるには次のようにすればよい。

void Update () {
  if(count < 20) {
    cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
    cylinder.transform.position = Vector3.zero;
    Debug.Log (cylinder.transform.up);	//(0.0, 1.0, 0.0)
    cylinder.transform.localScale = new Vector3(cylinderRadius, cylinderHeight, cylinderRadius);
    lat =  Random.Range(-80.0f,80.0f);	//latitude
    lng = Random.Range(-180.0f,180.0f);	//longitude

    cylinder.transform.Rotate(new Vector3(-90.0f, 0.0f, 0.0f), Space.Self);	//rotate 90 around X to equator
    Debug.Log (cylinder.transform.up);	//(0.0, 0.0, 1.0)
    cylinder.transform.Rotate(new Vector3(0.0f, 0.0f, -lng), Space.Self);	//rotate in longitude direction
    cylinder.transform.Rotate(new Vector3(lat, 0.0f, 0.0f), Space.Self);

    cylinder.transform.Translate((sphereRadius+cylinderHeight)*cylinder.transform.up, Space.World);
  };
  count++;
}

f:id:yasuda0404:20141017201230p:plain

Unityで使える広義の配列

参考:http://wiki.unity3d.com/index.php?title=Which_Kind_Of_Array_Or_Collection_Should_I_Use%3F

Unityの広義の配列―コレクション―はいくつか種類がある。それぞれ宣言や代入、値の取出しの記述が異なる。また、自由度が高い反面、使わないほうがよいものもある。



1)ビルトイン配列(Built-in Array)

もっとも基本的な配列で、もっとも高速。ただし宣言時に要素数を指定する必要がある。が、宣言後にリサイズは可能。(System.Array.Resize(ref myArray, size))で行う。)

C#での宣言、代入、リサイズは次のように行う。ただし、多次元のビルトイン配列はリサイズできない。

TheType myArray = new TheType[lengthOfArray];  // declaration
int[] myNumbers = new int[10];                 // declaration example using ints
GameObject[] enemies = new GameObject[16];       // declaration example using GameObjects
int howBig = myArray.Length;               // get the length of the array
myArray[i] = newValue;                     // set a value at position i
TheType thisValue = myArray[i];            // get a value from position i
System.Array.Resize(ref myArray, size);    //resize array
 
string[] weapons = new string[] { "Sword", "Knife", "Gun" };
float[] alphas = new float[] { 1.0f }; 


2)Javascript配列(Javascript Array)

標準的な.netクラスにはない、Unity独自の配列。ただし名前通り、javascriptスクリプトでのみつかえ、C#型では使えない。

このため、サイズ変更可能、要素の型を宣言する必要がないなど柔軟性が高いが、反面、性能的にはもっとも遅い。

Javascript Arrayは基本的にはArrayListにラッパーをかけたものとみなせ、同様のことはObjectリストで実現できる。しかも速い。Javascript Arrayは「過去の遺産」と考えた方がよさそう。


3)アレイリスト(ArrayList

Javascript Array以上に柔軟性がある(たとえば要素数を変更できるなど)が、性能上は遅い(*)。またArrayList自体には型はなく、任意の型を要素として持つことができる。型の混在も可能。

ただし、Generic Listの登場によりArrayListの存在意義はなくなったといわれる。旧式のコードとの互換性上のものと考えた方がよさそう。

(*)性能面のハンデの多くは宣言時に要素数を宣言しないため、という報告もある。つまり、ArrayListでも要素数を固定すれば、速度は改善するらしい。

ArrayList myArrayList = new ArrayList();    // declaration
myArrayList.Add(anItem);                    // add an item to the end of the array
myArrayList[i] = newValue;                  // change the value stored at position i
TheType thisItem = (TheType) myArray[i];    // retrieve an item from position i
myArray.RemoveAt(i);                        // remove an item from position i
var howBig = myArray.Count;                 // get the number of items in the ArrayList


4)ハッシュテーブル(Hashtable)

'key-value'方式で要素を参照する配列。
key, valueともにどんな型でもよい(untype)。型の混在も可能。(keyは通常はString型であることがおおいが。)このため、Hashtableから要素を取り出す際は、ユーザがCastしてやる必要がある。
ただし、ArrayListよりもGeneric Listが良いのと同じように、近年は、HashtableよりDictionaryを使う方が良い。

Hashtable myHashtable = new Hashtable();                 // declaration
myHashtable[anyKey] = newValue;                          // insert or change the value for the given key
ValueType thisValue = (ValueType)myHashtable[theKey];    // retrieve a value for the given key
int howBig = myHashtable.Count;                          // get the number of items in the Hashtable
myHashtable.Remove(theKey);                              // remove the key & value pair from the Hashtable, for the given key.

5) ジェネリック・リスト(Generic List)

Generic Listは、Listとも呼ばれる。要素数可変、要素の追加・削除ができる点ではJavascript, ArrayListと同等の柔軟性がある。違いは、定義時に型を指定する点。宣言した型の要素しか保持できないため

  • 要素の値を取出す際、型キャストが不要。
  • ArrayListより速い

という利点がある。
つまり、特定の型のみ扱うことがわかっている場合は、ArrayListよりGeneric Listを使う方が良い。

using System.Collections.Generic;

List<Type> myList = new List<Type>();                 // declaration
List<int> someNumbers = new List<int>();              // a real-world example of declaring a List of 'ints'
List<GameObject> enemies = new List<GameObject>();    // a real-world example of declaring a List of 'GameObjects'
myList.Add(theItem);                                  // add an item to the end of the List
myList[i] = newItem;                                  // change the value in the List at position i
Type thisItem = List[i];                              // retrieve the item at position i
myList.RemoveAt(i);                                   // remove the item from position i


6) ジェネリック・ディクショナリー(Generic Dictionary)

HashtableのGneric List版。宣言時にkey, valueの型を指定する。このため、Gneric Listと同じ利点が得られる。

using System.Collections.Generic;

// declaration:
Dictionary<KeyType,ValueType> myDictionary = new Dictionary<KeyType,ValueType>();
 
// and a real-world declaration example (where 'Person' is a custom class):
Dictionary<string,Person> myContacts = new Dictionary<string,Person>();
 
myDictionary[anyKey] = newValue;                 // insert or change the value for the given key
ValueType thisValue = myDictionary[theKey];      // retrieve a value for the given key
int howBig = myDictionary.Count;                 // get the number of items in the Hashtable
myDictionary.Remove(theKey);                     // remove the key & value pair from the Hashtable, for the given key.


7) 2次元配列(2D Array)

以上はすべて1次元の配列について述べてきた。Unityでは2次元以上の配列を使うこともできる。以下は2次元配列についてのべるが、3次元、4次元…といった多次元配列を扱うこともできる。

「一般の」2次元配列の宣言では、外側・内側の2要素の要素数を指定する。

// declaration:
string[,] myArray = new string[16,4];            // a 16 x 4 array of strings
 
// and a real-world declaration example (where 'Tile' is a user-created custom class):
Tile[,] map = new Tile[32,32];                   // create an array to hold a map of 32x32 tiles
 
myArray[x,y] = newValue;                         // set the value at a given location in the array
ValueType thisValue = myArray[x,y];              // retrieve a value from a given location in the array
int width = myArray.GetLength(0);                // get the length of 1st dimension of the array 
int length = myArray.GetLength(1);               // get the length of 2nd dimension of the array


一方「ジャグ(jagged)」2次元配列では、(内側の)要素の数がそろっていなくても良い。

var myJaggedArray = [ [1, 2, 3], [4, 5], [6, 7, 8, 9, 10] ]; // a jagged int array

myArray[x][y] = newValue;
ValueType thisValue = myArray[x][y]; 

ちなみに、「ビルトイン配列(たとえば、GameObject[])を要素にもつジェネリック・リスト」を作るには次のように書く。

GameObject[] go1;
GameObject[] go2;
GameObject[] go3;
List<GameObject[]> gos = new List<GameObject[]>{go1,go2,go3};

以上、Unityで扱われる広義の配列について述べた。利用指針は次のようになるだろう。

・大きさがわかっているケースは、ビルトイン配列を使う。メモリ効率も速度ももっともよい。
ArrayListのかわりにGneric Listを、Hashtableの代わりにGeneric Dictionaryを使う。
Javascript Arrayは使わない。

要するに、型のキャストを避けるべき。
開発時はArrayListやHashtableを使ってもよいが、リリース時はGnericに変換するとよいだろう。

インスペクタで、カスタムクラスの中にある変数にアクセスする

わかりにくいタイトルだが、具体的な例で説明する。

下のように、メインであるクラス(下の例では、Physics)のPublic変数にカスタム・クラス(SubData)
を指定しているとする。、

using UnityEngine;
using System.Collections;

public class SubData {
	public int data1;
	public int data2;
	private int data3;
}

public class Physics : MonoBehaviour {
	public SubData data;
	// 途中省略
}

この場合、インスペクターから、SubDataクラスは見えない。つまり、data1, data2も見えない。
f:id:yasuda0404:20130913160031p:plain



インスペクタからSubDataの中にある変数を見えるようにするには、Runtime Attributeの、[System.Serializable]を指定する。

[System.Serializable]
public class SubData {
	public int data1;
	public int data2;
	private int data3;
}

こうすれば、インスペクタから、SubDataのPublic変数が見えるようになる。SubDataクラスのPrivate変数には当然アクセスはできない。

f:id:yasuda0404:20130913160413p:plain

コンポーネントが存在するかどうかを見る

GameObjectに対し、あるコンポーネントを持っているかを調べ、なければ足す(あるいは、処理を変える)場合の手順

例えば、あるGameObjectに対し、rigidbodyコンポーネントがなければ新たに加え、rigidbodyコンポーネントを返す例。

if(rigidbody == null){
	return transform.gameObject.AddComponent("Rigidbody") as Rigidbody;
}else{
	return rigidbody;
}

'rigidbody == null'は、rigidbodyコンポーネントがない場合に真となる。

Componentを足すだけなら、

GameObject.AddComponent("コンポーネント名")

でよいが、Componentを加えると同時に、そのコンポーネントを変数として取得する場合、
変数 = GameObject.AddComponent(”コンポーネント名”) as コンポーネント
のように一行で行える。
AddCompnent()の引数はComponent型のため、コンポーネントの型に応じたキャスト(上の例ではRigidbody)が必要。


カスタムクラス・コンポーネントの場合は、次のように書ける。

if(ball.GetComponent<Ball>()){
	//if Ball does not exist
	ballRB = ball.GetComponent<Ball>().getRB();
}else{
	ballRB = ball.rigidbody;
}

一行目は、

if(ball.GetComponent<Ball>() != null){

としてもよい。

                  • -

追記:2013/9/13

特定のコンポーネントなければ加える別な方法として、Runtime Attributeの[Require Component(typeOf(コンポーネント名))]
を使う手もある。エディター上で見えるので、必ず組にして使う必要があるコンポーネントならこの方法がわかりやすい。

using UnityEngine;
using System.Collections;
[RequireComponent (typeof (Rigidbody))]
public class Test : MonoBehaviour {
.........

とすれば、Scriptをアタッチした時点で、アタッチしたゲームオブジェクトがRigidbodyコンポーネントを持っていなければ自動的に加えられる。

timeScaleでアニメーション速度を変更する

Time.timeScaleでFixedUpdate()の時間間隔を調整できる。

Time.timeScale=1.0 で、デフォルトの速度(時間間隔)
Time.timeScale=0.5で、速度を半分(時間間隔を2倍)にする
Time.timeScale=0.0は、速度ゼロ、すなわち、FixedUpdate()を停止する


具体的な事例で見てみる。

子オブジェクトのスクリプト。一定速度で回転する。

using UnityEngine;
using System.Collections;

public class revolution : MonoBehaviour {
	
    // Update is called once per frame
        void FixedUpdate () {
        transform.RotateAround(Vector3.up, 0.02f);
    }
}


親オブジェクト:一定速度で上昇するスクリプト。スペースキーでTime.timeScale=0.0f/1.0fにトグルする。これによって、アニメーションの停止・作動を切り替える。

using UnityEngine;
using System.Collections;

public class move : MonoBehaviour {
	
	// Use this for initialization
	    void Start () {
	}
	
	// Update is called once per frame
	void Update () {
	    if (Input.GetKeyDown ("space")){
            print ("space key was pressed Time.timeScale="+Time.timeScale);
	    Time.timeScale = Mathf.Abs (1.0f-Time.timeScale);
	}

	}
	void FixedUpdate(){
		transform.Translate(0.01f*Vector3.up);
	}
	
}


ここで注意するのは次の2点。

1)timeScale=0.0fで停止するのは、FixedUpdate()のみ。Update()はTime.timeScaleの値に関係なく、動き続ける。
 つまり、上の事例では、親オブジェクトのUpdate()内のInput.GetKeyDownによるキー入力は有効のままである。

2)親オブジェクトでTime.timeScale=0.0fとすると、子オブジェクトを含む全てのFixedUpdate()が停止する。上の例では、親オブジェクトの上昇が止まるだけでなく、子オブジェクトの回転も止まる。
 親子関係にあるオブジェクトだけではなく、シーン内のすべてのオブジェクトでFixedUpdate()は停止する。

Mouse入力 Event, OnMouse, Input

Mouse入力(および、タッチセンサー入力)を受け取るには、次の3つの方法がある。

1)Event
キー入力とMouse操作が発生した時に発信されるEventを受け取る。
ただし、Eventは、OnGUIの中のみで受け取れる(ようだ)

using UnityEngine;
using System.Collections;

public class RotateObject : MonoBehaviour {
	void OnGUI(){
		Event e = Event.current;
		if(e.button == 0 && e.isMouse){
			Debug.Log (e.delta);
		}
	}
}

e.buttonは、マウスボタンの種類。

e.button 0:左ボタン、1:右ボタン、2:中ボタン

e.isMouse == true は、マウスイベントであることを示す。


2)OnMouse
MonoBehaviourのメソッドとして用意されている、Mouse関連の関数を使う方法
Scriptのアタッチ先は、GUIElemmentかColliderを持つオブジェクトのみで、オブジェクトとマウスとの関係が重要

OnMouseEnter オブジェクト上に入った時に一度だけ呼ばれる。ボタンの状態は無関係
OnMouseExit オブジェクトから出た時に一度だけ呼ばれる。ボタンの状態は無関係
OnMouseDown オブジェクト上で左ボタンを押した。オブジェクト外で左ボタンを押してからオブジェクト内に入っても呼ばれない
OnMouseDrag マウス左ボタンを押したまま動かした。押したままオブジェクト外にでても有効
OnMouseOver オブジェクト上に入っている状態。OnMouseEnterと違って何度も呼ばれる
OnMouseUp オブジェクト上で左ボタンをアップ。オブジェクト外でアップしても呼ばれる。
OnMouseUpAsButton オブジェクト上で左ボタンをアップ。オブジェクト外でアップした場合は呼ばれない。


3)Input
アタッチされたオブジェクトと関係なくMouseの動作を取得する。通常は、Update()、FixedUpdate()の中で使用する。

GetMouseButton 左ボタンをおした状態。毎回呼ばれる。
GetMouseButtonDown 左ボタンをおした動作。押した際に一度だけ呼ばれる
GetMouseButtonUp 左ボタンを話した動作。一度だけ呼ばれる

*引数はすべて共通で、0:左ボタン、1:右ボタン、2:中ボタン

LineRendererを使う

例えば、空間上に引出線を描画する場合、線に相当するオブジェクトを置くよりも、LineRendererを使ったほうがスマート。

1)Scriptの例
  下の例は、Transformの配列(transforms)に格納した座標間にラインを描画するもの。

using UnityEngine;
using System.Collections;

public class LineTest : MonoBehaviour {
	
	public Transform[] transforms;
	LineRenderer lineRenderer;
	
	// Use this for initialization
	void Awake () {
		lineRenderer = GetComponent<LineRenderer>();
		lineRenderer.SetVertexCount(transforms.Length);
	}
	
	// Update is called once per frame
	void Update () {
		for(int i=0; i<transforms.Length;i++){
			lineRenderer.SetPosition(i, transforms[i].position);
		}
	}
}

2)上のScriptのアタッチ先オブジェクトに、LineRendererコンポーネントをアタッチする。ラインの色や太さなどはLineRendererコンポーネントで指定する。
f:id:yasuda0404:20130325174039p:plain
f:id:yasuda0404:20130325174048p:plain

Prefabのインスタンスを生成する

Project内に次のPrefab (BallPrefab)があるとする。
f:id:yasuda0404:20130302160328p:plain

このPrefabをシーン内に生成するには、Instantiate()を使う。
たとえば次のScriptを作り、シーン内のGameObjectにアタッチ。

using UnityEngine;
using System.Collections;

public class MainScript : MonoBehaviour {
	public GameObject ball;
	
	// Use this for initialization
	void Start () {
		for (int i=0 ; i<3 ; ++i) {
      		      Instantiate(ball,new Vector3(Random.Range(-0.5f,0.5f)*10,i*10+10,Random.Range(-0.5f,0.5f)*10),Quaternion.identity);
    	        }
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

Instantiateの引数は、複製したいオブジェクト(Object)、位置(Vector3D)、回転(Quaternion)。
public変数として定義した'ball'に、Project内のPrefabをひもづける。
f:id:yasuda0404:20130302160647p:plain

Instantiate()の戻り値は'Object'のため、戻り値は使用するにはキャストが必要。
RigidBodyにキャスト:

	void Init () {
		Rigidbody[] obj = new Rigidbody[3];
		for (int i=0 ; i<3 ; ++i) {
      		obj[i] = Instantiate(ball,new Vector3(Random.Range(-0.5f,0.5f)*10,i*10+10,Random.Range(-0.5f,0.5f)*10),Quaternion.identity) as Rigidbody;
    	}

GameObjectにキャスト:

	void Init () {
		GameObject[] obj = new GameObject[3];
		for (int i=0 ; i<3 ; ++i) {
      		obj[i] = Instantiate(ball,new Vector3(Random.Range(-0.5f,0.5f)*10,i*10+10,Random.Range(-0.5f,0.5f)*10),Quaternion.identity) as GameObject;
    	}


このシーンを実行すると、Project内のBallPrefabがランダムな位置に生成される。
f:id:yasuda0404:20130302160835p:plain

                                                                      • -

[追記:2015/3/9]

上の手順では、インスタンス化したGameObjectはシーンの最上位階層におかれる。インスタンス化したGameObjectを特定のGameObjectの下(子供)におきたい場合は、

obj[i] = Instantiate(ball,new Vector3(Random.Range(-0.5f,0.5f)*10,i*10+10,Random.Range(-0.5f,0.5f)*10),Quaternion.identity) as GameObject;
obj[i].transform.parent = targetGameObject.transform;
    	}

と、transform.parentをつなぎなおせばいよい。

書式付で数値を文字に変換する

数値を文字に変換するのは、toString()関数だが、同時に書式も指定できる。
たとえば、小数点以下第一位まで表示した文字は、

数値変数.toString("#.0")

とする。

他にも多くの書式設定がある。
カスタム数値書式指定文字列


なお、toString()は、日付時刻の書式付変換でも使う。
bear.mini : [.NET] DateTime.ToString() 書式指定文字列 まとめ - カスタム DateTime 書式指定文字列編

GUIがエラーになる時(クラス名のコンフリクト)

GUIメソッドがない、というエラーで悩まされた。
f:id:yasuda0404:20130112151800p:plain

スクリプトは間違いがないので、システムがおかしくなったかとも疑ったが、理由は簡単だった。
別途、'GUI'という名前のC#クラスを作ったため、コンフリクトを起こしていたのだ。
f:id:yasuda0404:20130112151937p:plain

GUIファイルを削除(リネーム)して、問題解決。

他にもUnityの予約クラス名とのコンフリクトは注意しなければ。