1st term 5th week - dsuz/csharp GitHub Wiki

Unity 上で C# を使いプログラミングをする上で、C# 上に組み上げられた Unity の仕組みについて学んでいく必要がある。これらを正しく理解していないと、「Unity の C# は普通の C# とは違う」などと誤った理解をしたり、C# の仕組みを勉強してもそれを Unity 上でのゲームプログラミングに生かせなくなってしまう。今回は C# と Unity をつなぐ仕組みについて学ぶ。

準備

  1. 新しく Unity のプロジェクトを作る
    • プロジェクト名は "CSharp 1" のように「どの授業に対応するプロジェクトなのか」を明確に区別できる名前にすること
    • プロジェクト名に "#" を含めることはバグを引き起こすかもしれないので勧めません
  2. CSharp1-5.unitypackage をダウンロードしてプロジェクトにインポートする
  3. Assets/1-5/CSharp/CSOnUnity シーンを開いて実行し、Console にデータが出力されることを確認すること

Unity 上の C# スクリプト コンポーネント

Unity を使って C# プログラミングをする時に、以下のようなことを書くことがある。

  • transform.position
  • name
  • GetComponent
  • OnCollisionEnter(2D)

これらがどこから来ているのか、何を見ればどんなものが使えるかわかるのか説明していく。

MonoBehaviour

Unity で C# スクリプト アセットを新しく作ると、中身は以下のようになっている。

ちなみにこのテンプレートはここで説明されているスクリプト テンプレートを書き変えてカスタマイズできる。最初に生成されるスクリプトに対して「コメントはいらない」「余計なものを削りたい」「これは追加しておいて欲しい」「文字コードを UTF-8 に変えたい」場合などに使える。ただし、別バージョンの Unity をインストールするとテンプレートはデフォルトになっているので、カスタマイズした場合は保存しておいた方がよい。

テンプレートによって作られたプログラムを見ると、クラス名(コンポーネント名、アセット名)の後ろに " : MonoBehaviour" と書かれている。これは「MonoBehaviour クラスの中身をすべて引き継いで(継承して)NewBehaviourScript を作る」という意味である。これは後に扱う「継承」でも詳しく説明する。

新しいクラスを MonoBehaviour から引き継いで作ることによりコンポーネントが作れるのだが、Unity でプログラミングする時は、この MonoBehaviour の中にあるものを使ってプログラミングしている。

これまでは「そういうもの」と理解し、暗記していたであろうことについて理論を説明していく。

this キーワード

Assets/1-5/CSharp/CSOnUnity シーンを開いて実行すると、Console にデータが出力される。これらは、CSOnUnity スクリプトから出力されている。

例えば、name と書くことで GameObject の名前を取得しているが、これは MonoBehaviour の中で定義されたメンバー変数である。

クラスのメンバーを指し示すことができる "this" キーワードを利用して、this. と Visual Studio から入力すると、利用できる変数とメソッドを一覧することができて、name もそこに見つかる。

使えるものの一覧は MonoBehaviour のスクリプト リファレンス から一覧できる。「継承メンバー」以下の「変数」と「Public 関数」の箇所に書いてあるものが、this. から一覧を見る事ができるメンバーである。

なお、this はどうしても必要な時以外は省略可能である。このため、多くの場合、this.transform.position などと書かれずに transform.position と表記されている。これは「このスクリプトが追加されている GameObject の座標」を表す。ここで、transform は「Transform クラスの変数」であり、「Transform クラスは position という座標を表すプロパティを持つ」ので、transform.position は座標を表している。大文字で始まるものはクラスを表し、小文字で始まるものは変数を表していることに注意しなければならない。

GetComponent() も MonoBehaviour クラスのメソッドである。this.GetComponent() は、「このスクリプトが追加された GameObject から、指定したコンポーネントを取得する」という意味である。つまり、GameObject への参照さえあれば、他の GameObject に追加されたコンポーネントを取得し、操作することもできる

なお、座標を取得あるいはセットしたい時に、GetComponent() で Transform コンポーネントを取得してもよいが、Transform コンポーネントは非常に頻繁に呼び出されるため this.transform でアクセス可能にしているのだろう。

参考資料

  • 『独習 C#』7.3.5 this キーワード

Unity メッセージ

Unity メッセージの例は、Start(), Update(), OnCollisionEnter(2D)() などのメソッドである。これらのメソッドは、Unity(のシステム)から決められたタイミングで呼び出される

例えば、Visual Studio を使ってメソッドを定義できる場所に "On" と入力するとインテリセンスの機能により使うことができるメッセージが一覧で表示される。(メッセージの中には On で始まらないものもある)

MonoBehaviour のスクリプト リファレンス の「メッセージ」の項に使えるメッセージの一覧がある。

メッセージは、「コールバック関数」と呼ばれることもある。つまり、Unity によって「折り返し」呼び出される関数、という意味である。

Unity でよく使われるもの

Unity でよく使われるメソッド・変数(プロパティ)・メッセージについては よく使われるもの一覧 (Unity) に一覧してある。これらの内、MonoBehaviour のリファレンスに含まれるものがどれかを確認しておくと、意外と少ないことがわかるでしょう。

null

Assets/1-5/null/null シーンを開いて実行し、Console にエラーが出力されることを確認して下さい。これを踏まえて "null" について説明します。このエラーは、シーン内の "Script" オブジェクトに Sprite Renderer コンポーネントを追加すれば出力されなくなります。

null の最初の説明として、「何もない」と説明されることが多い。

int, float, bool, Vector2, Vector3 などの構造体 (struct) はそれぞれ既定値がある。しかし、クラスの既定値は null である。

コンポーネントはクラスであるが、コンポーネントの変数を宣言した段階では、その変数の中身は null である。これがどのような状態かというと、「どのコンポーネントも指していない状態」である。

コンポーネントの変数が null である時、つまりどのコンポーネントも指していない時にメンバーを呼ぶと、エラーになる。(正確には「例外が投げられる」という)

つまり、何かコンポーネントのメソッドを呼ぼうとしたり、値を取得あるいはセットしようとした時に、コンピュータにとって「どれに対しての命令かわからない」場合は不正な操作とみなされる。

自分の書いたプログラムでエラーが起きた場合は、闇雲に直そうとせず、何が起きているのか、よく観察し、何が悪いのか(原因)を理解して修正するよう努めなければならない。

参考資料

  • 『独習 C#』2.5.2 null 値

break と continue(ループの制御)

Assets/1-5/break/break シーンを実行すると、BreakExample コンポーネントを実行することができる。これは break 命令のサンプルとなっている。

break 命令を実行する (break; と書く)と、ループを強制的に中断して抜けることができる。

continue 命令を実行する(continue; と書く)と、今回のループをそこで中止し、次のループを始めることができる。

break 命令の方が圧倒的に使用頻度が高いです。continue は使用頻度はそれほど高くなく、やや難しい処理で使われます。

参考資料

  • 『独習 C#』4.3 ループの制御
⚠️ **GitHub.com Fallback** ⚠️