【Unity/C#】参照のnullチェックは忘れずにやっておこう!【初心者向け】
「nullチェックは呼吸するように行え」
とは誰の言葉だったか……いえ、すみません今私が勝手に作った言葉です。
Unityでは他のオブジェクトにアタッチされたスクリプトの処理を呼び出したいことが多々あります。
例えば、シーン全体を管理させるスクリプトからBGMの再生/停止するスクリプトにあるBGM再生のメソッドを呼ぶといったケースです。この時気を付けたいのが、他のスクリプトが参照をセットしているかどうか確認する点です。
ここで、シーン全体を管理させるスクリプトのStart()でBGMを再生しようとしているとします。また、BGMの再生/停止するスクリプトでもStart()で『AudioSource』に対してGetComponentしているとします。
この状態だと、先にシーン全体を管理させるスクリプトでStart()が呼ばれた場合、BGMの再生/停止するスクリプトではまだ参照がセットされていない可能性があります。
このままBGM再生の処理が呼ばれたら『AudioSource』への参照がnullなのでエラーが出力されます。このままではコンポーネントにアクセスできていないので、BGMを再生することができないんですよね。
スクリプトの実行順をセットする……のでも良いですがお手軽なのはBGMの再生を行う直前に参照をチェックして、nullだったらそこでGetComponentすることです。
慣れてくると「このタイミングはnullにはならない」「ここはほぼnullで来るはず」なんて予想がつきますが、最初は難しいのでちゃんとnullをチェックして処理を分岐することを考えましょう。
Nullをチェックするサンプル
例えば以下のようなメソッドを用意します。
「bgmAudio」はフィールドとして作成しておきます。再生したいBGMがセットされているAudioSourceだと思ってください。
BGMを再生する直前で「CheckAudioReference()」を呼んでおけばGetComponentする前の「bgmAudio」にアクセスする危険が減ります。
各々のスクリプトのStart()で参照をセットすることはよくありますが、他のスクリプトとのやりとりがある場合は参照をセットするタイミングや参照の確認を行うタイミングに気を配る必要があります。
どちらかが先行して呼ばれるとエラーになる可能性があるのなら、このようにnullをチェックしてnullの場合の処理を入れておくのが鉄板です。
そもそもnullって?
「初心者向け」とタイトルに入れておきながらいきなり具体的なケースの解説をしてしまいました。すみません。
そもそもnullってなんなのか、から共有させてください。
null(ヌル、ナル)は無効な値を表すものです。例えばGameObject型の変数を用意したときに、参照するオブジェクトを指定していない場合はnullになります。変数には値型、参照型があって、値型は値として直接持っていて、参照型では値が置かれている場所を示しています。この参照型が指し示す先がセットされていないということは、値がどうなっているか分からないので無効な値としてnullが返されます。
昔の2chで「ぬるぽ」「ガッ」の流れがありましたが、この「ぬるぽ」はNullPointerExceptionのことで、無効なポインタの例外を意味します。このときに出てくるのもnullですね。
Unityでよく見るNullReference
UnityではNullReferenceExceptionという形で参照されていないオブジェクトにアクセスしようとしていることを教えてくれます。
この点はマニュアルにも記載されているので、こちらもご覧ください。
ぬるぽのような略称は聞いたことがなく、私は「あ、nullが出た」と言ってしまっています。もし「うちの会社ではこう呼んでいるよ!」みたいなのがあったら教えてください。
このNullReferenceExceptionは結構よく見るエラーで、原因の特定もしやすい部類だと思います。初心者の頃によく見たのは、GameObject.Find(“名前”)でゲームオブジェクトを検索したときでした。対象の名前が存在していない場合はnullが返って来るので、そのままGetComponentをしようとしてエラーが出てきました。
今でもスクリプトの処理順を読み違えて遭遇することはありますが、対処については慣れているので割とすぐ解決できるようになったと思います。
このエラーはコンパイル時には検知できなくて、実行したときに気づくものなので、たくさんスクリプトを編集した後にゲームを実行すると出て来ることが多いです。たくさんスクリプトを編集しているということは、それだけ処理の実装漏れも生まれやすいんですよね。
インスペクターウィンドウでよくあるnull
C#のコードを書いている時だけではなく、実はGUI側の操作忘れでも参照のnullが発生することがあります。それは、publicなフィールドに対するオブジェクトの参照をセットするのを忘れた時。例えばスクリプトの中でpublicなフィールドとして主人公オブジェクトへの参照を保持するフィールドを作っていたとします。
スクリプトがコンパイルされると、インスペクターウィンドウでこのフィールドにオブジェクトをセットできるようになりますが、これを忘れてゲームを実行しちゃうことって結構あるんですよね。
恥ずかしながら私はこれをやってしまうことが多くて、コードを書いたらすぐにゲームを実行したくなっちゃうんです。コンソールに「NullReference」のエラーがたくさん出力されるのを見て「またやってしまった……」と自己嫌悪に陥るのですが、結構ありがちじゃないですかね?(私だけ?)
気がはやるとこうしたこともあるので、ゲーム実行前の人力nullチェックは大切です。
このnullチェックをコードの中に入れるか? というのは人によって方針が分かれるかもしれませんが、私は自分だけで作っているゲームの場合、インスペクターウィンドウからオブジェクトをセットする場合はコードの中にnullチェックを入れません。ゲームを実行するときにはインスペクターウィンドウでオブジェクトがセットされているのが正しい状態ですからね。
テストすればすぐにコンソールに「NullReference」のエラーを出して教えてもらえるので、私のミスを拾うためにコードの中に処理を入れるのはやりたくないなぁと考えています。(ここまでするならインスペクターウィンドウからオブジェクトをセットする意味がないですからね)
まとめ
Unityでコーディングする場合はnullチェックをするようにしましょう。特にGameObjectの操作、コンポーネントの操作ではnullが発生しやすいので、nullだった場合の処理も入れておくと安心です。
スクリプトを編集した後にインスペクターウィンドウから参照をセットする点も忘れやすいので、慌てずインスペクターウィンドウを確認するようにしましょう。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【ゲーム開発】プログラミングは使い回しが肝!再利用性を意識しよう 2020.08.14
-
次の記事
【Unity】ゲーム開発ではたまには高校数学も思い出すと便利です 2020.08.16
コメントを書く