おもちゃラボ

Unityで遊びを作ってます

Unityで使える!C#の便利な機能7選

Unityでは基本的にC#を使ってプログラムを書くと思います。そんなときに知っておくと「チョットだけ便利」「チョットだけ楽できそう」なC#の文法をまとめました。現在Unityで使える最新のC#のバージョンはC#6になっています。使えるものはじゃんじゃん利用していきましょう!

null許容型

int型やfloat型などの値型には、通常nullを代入することはできません。でも、null許容型を使うことでnull値を代入できるようになります。

null許容型を宣言するには通常の値型の最後に「?」をつけます(なんでハテナやねんと思わなくもない)

int? a;
float? b;

みたいな感じです。

値型にnullが入れられると、どんな良いことがあるのでしょうか?例えばメソッドの中で何か処理をしてから、処理結果をint型で返したいとしましょう。処理が失敗した場合は-1を返します。

int hoge()
{
	// なんか処理

	if( success ){
		return result;
	} else {
		return -1;
	}
}

この場合、処理結果(result)が-1だった場合、メソッドの呼び出し元は返り値が処理結果なのかエラーか判別できません。そこでnull許容型の登場です。

int? hoge()
{
	// なんか処理

	if( success ){
		return result;
	} else {
		return null;
	}
}

void Start()
{
	int? result = hoge();
	if( result != null ){
	}
}

null許容型を使うことで、上のように返り値がnullだった場合のみエラーとして扱うことができるようになります。

数値を戻り値に使う場合は、たまに役に立つので覚えておくと、ちょっとだけプログラムが綺麗になるかもしれません!?

enum型

使っていますか?enum型。CやC++でゴリゴリプログラムを書いていた人にはお馴染みだと思いますが・・・。もちろんC#でもenum型を使うことができます。

    public enum PlayerState{
        WAIT,
        RUN,
        DAMAGE,
        DEAD,
    };
    public PlayerState type;
    
    void Start()
    {
    	this.type = PlayerState.WAIT;
    }

enum型はクラスや構造体と同じように型を作るための仕組みです。ただし、クラスのようにメソッドや変数を定義するのではなく、関連のある定数値を複数作るのに使用します。

例えば、上のC#プログラムのように、プレイヤのステート管理や、ゲームのステート管理をするのによく使われます。

定数値と書きましたが、enum型ではその中で宣言した順番に自動的に数値が割り振られます。上の例ではWAIT=0、RUN=1、DAMAGE=2、DEAD=3となります。

なので、次のようにenum型の最後にSTATE_NUMと宣言しておくと、自動的に「STATE_NUM=4」となって、ステートの数を宣言することができます(C言語では多様されていましたが、今でも使うのかなぁ・・・)

    public enum EnemyState{
        WAIT,
        ATTACK,
        DEAD,
        STATE_NUM,
    };

さらに、さらに!enum型の変数をpublicで宣言すると、Unityのインスペクタからドロップダウンで値を選べるようになる特典付き!これは結構便利です。

f:id:nn_hokuson:20170825184124p:plain:w300

テキストファイル読み込み

Unityでテキストファイルを読み込むのは非常に簡単です。と書くと、どうせ「usingとStringStreamを使うんでしょ〜〜〜」と言われそうです。

その方法は「確かな力が身につくC#超入門」で解説しているのでそちらを参考にしていただくとして・・・(笑)

UnityではTextAssetを使うとStringStreamを使うまでもなく、ファイルの内容を読み込むことができます。

 public TextAsset file;
 
 void Start()
 {
 	string data = file.text;
 } 

はい、これだけです!なんと簡単な!TextAsset型の変数をpublic変数で宣言し、Unity側でインスペクタからテキストファイルをセットすればあとはdata変数の中にファイルの全行が格納されます。

f:id:nn_hokuson:20170825163112j:plain

あとはSplitメソッドを使って一行一行パースするなり、焼くなり、好きなように調理すればOKです。ちなみにSplitメソッドを使ったパースは次のような感じになります。

 public TextAsset file;
 
 void Start()
 {
	string[] lines = data.text.Split ('\n');
	foreach (string line in lines)
	{
	    Debug.Log (line);
	}
 } 

拡張メソッド

拡張メソッドとは、すでにあるクラスにメソッドを追加することができる機能です。まさに、拡張するためのメソッド、略して拡張メソッドですね。

なんか、難しそうな割に使う機会がなさそうな機能ですが、unityでは意外と役に立つやつなんですよ。例えば、Unityでは次のようにオブジェクトの持つpositionの値を1つだけ変える、ということができません。

gameObject.transform.position.x = 3; // エラー

xの値だけを変えたい時は次のように書かなくちゃいけないんですが、何はともあれ不恰好ですよね・・・

Vector3 pos = gameObject.transform.position;
pos.x = 3;
gameObject.transform.position = pos;

ということで拡張メソッドの出番です。 拡張メソッドを使ってTransformクラスにメソッドを追加するには次のように書きます。

public static class TransformEx
{
    static Vector3 v;

    public static void SetPosX(this Transform transform, float x) 
    {
        v.Set(x, transform.position.y, transform.position.z);
        transform.position = v;
    }
}

ここでは、拡張メソッドを使ってTransoformクラスにSetPosXというメソッドを追加しています。拡張メソッドを作るには、静的クラスを作成し、その中に追加したいメソッドを書きます。

このとき、第一引数にはthisキーワードに続けて拡張したいクラス名を書きます。ここではTransformクラスを拡張したいので、this Transform transform としています。

作成した拡張メソッドを呼び出す方法は、通常のメソッドと変わりありません。つぎのようにtransformに続けてメソッド名を書くだけです。

void Start()
{
    Debug.Log(transform.position);
    transform.SetPosX (10);
    Debug.Log(transform.position);
}

このように、拡張メソッドを使うと、あたかもTransformクラスに最初からSetPosXメソッドが用意されているかのように、シレッと使うことができるのです。なかなか便利でしょ?

プロパティ

メンバメソッドをカプセル化したい場合、C++では一つ一つアクセサを手書きする必要がありました。この煩雑さを解決する手段としてC#には簡単にアクセサを作成できる「プロパティ」という機能が追加されました。

プロパティの基礎的はお話は「確かな力が身につくC#超入門」で解説していますので、こちらも書籍を参照いただければとおもいます m(_ _)m

プロパティ、とても便利なんですが、C#のバージョンを重ねるごとにプロパティの仕様がコロコロと変わり・・・ここでは自動実装プロパティと初期化ができるようになったC# 6時点での最終形態だけを紹介したいと思います。

この機能を試すにあたってはUnityでメニューバーからEdit -> Project Settings -> Playerを選択し、Other Settingsの「Scripting Runtime Version」を「Experimental(.NET 4.6 Equivalent)」に設定して下さい。

f:id:nn_hokuson:20170825184416p:plain:w350

プロパティを使うと次のような書き方ができます。

public class Player
{
    public int Hp{ get; set; } = 100;
    public string Name {get;} = "hoge";
}

void Start()
{
	  Player player = new Player ();
      Debug.Log (player.Name);

      player.Hp -= 30;
      Debug.Log (player.Hp);
}

ここではPlayerクラスにHpとNameのプロパティを作っています。通常の変数宣言と同様にpublic int Hpと書き、続く{} の中にアクセス権限を記述します。

Hpの場合はset;とget;を指定しています。Nameは書き換えることはないのでget;のみを指定しています。最後に=に続けて値を書くことで、プロパティを初期化できます。

プロパティを使う場合は、通常のメンバ変数(メンバメソッドではなく)を使うように使えます。player.Hp -= 30のように直接プロパティ値を書き換えられることに注目してください!

メンバメソッドだと次のように冗長な書き方になってしまいますね・・・

int hp = palyer.GetHp();
hp -= 30;
player.SetHp(hp);

ということで、最新版のプロパティはかなり便利になっているので積極的に使っていきましょう!

タプル型

タプル型はかなりマイナーです、たぶん(笑)なぜなら、使いどころがいまいちないからだ、と思っていますがどうでしょう。ですが、戻り値を複数返したい場合には、タプルを使うとちょっと便利です(本当にチョットですよ)

 Tuple<string, int>GetStatus()
{
    string name = "hoge";
    int hp = 50;
    return Tuple.Create (name, hp);
}

void Start()
{
    var status = GetStatus ();
    Debug.Log ("Name=" + status.Item1 + ",HP=" + status.Item2);
}


ここではタプル型を使って複数の戻り値をメソッドの呼び出し元に返しています。ListやDictionaryのコレクションを使い慣れている人にはおなじみの書き方ですね。

Tupleに続けて<>の中にまとめたい型名を「,」で区切って書きます。ここではプレイヤの名前とHPを返り値として返したいのでTupleと書いています。

タプルを作るにはTuple.Createメソッドを使います。また、戻り値としてタプル型を受け取るにはvarを使います。タプルから値を取り出したい場合は「変数名.Item1」, 「変数名.Item2」のように書くことで、順番に値を取り出すことができます。

タプルの特徴をまとめると、わざわざ新しく戻り値に使う型を作らなくても、名前のないTuple型を使えば良い、ということになります。そういう意味ではラムダ式と似た構造なのですが、如何せん使いどころが・・・(笑)

まとめ

Unityで使えるC#の便利機能を7つ紹介しました。