Edited at
UnityDay 14

Unity初心者がハマる11の「罠」~考察編

More than 5 years have passed since last update.

Unity Gemsというウェブサイトがあって、初心者のためにより有用な情報を集積しようという目的で運営されている。

Unity Answersの常連が集まって、過去の投稿の中から選別されているだけあって、本当に優良なサイトで、私自身の技術翻訳ブログでもしばらくの間、トピックとして取り扱ってきた。

ちょうどシリーズが一つ終わったところなので考察を少ししてみたい:



Unity初心者がハマる11の「罠」~の考察


学習ステップ

目次: Unity初心者がハマる11の「罠」~目次


  1. 別スクリプトの変数やメソッドへの参照

  2. OnTriggerやOnCollisionの判定条件

  3. Inputの正しい用法

  4. 未来事象の正しい文法

  5. ListやDictionariesで増減するオブジェクトコレクションを管理

  6. Rigidbodyの正しい移動方法

  7. Character Controllerの正しい使い方

  8. クォータニオンの修正方法

  9. C#とJavascriptを正しく連動させる


Unity初心者がハマる11の「罠」 ※上記1~9の中から抜粋。


1. 簡単なタイマー機能にyieldやcoroutineを使用しないこと


タイマーを作成するだけなら以下のコードで良い:

float timer;

int waitingTime;

void Update(){
timer += Time.deltaTime;
if(timer > waitingTime){
//Action
timer = 0;
}
}



2. staticを変数に用いないこと


「staticを変数に用いないこと」がUnityで陥りやすい「罠」。ついつい変数を保有するスクリプトの参照方法が分からない場合に、簡単に参照出来る方法としてやってしまいがちだ。正確に理解していないかぎりやってはいけない典型パターンだ。staticな変数はグローバル変数の扱いであり使用すべき状況はかぎられていて、かつ上級者向けにシナリオといえる。複雑なゲームのプログラミングにおいて一度も使うことがなかったとしても全く困らないことが殆どだ。



3. CharacerControllerを格闘やゲームでの移動ではない目的で使用しないこと


物理(Physics)エンジンを使用したい場合はCharacter Controllerを使用しないこと。このケースではカスタムのスクリプトを作成する必要がある。



4. FixedUpdateの中でInputを使用しないこと


大体において、問題はInputを通して物理エンジンを作用させるときに問題が起きる。PhysicsはFixedUpdateに配置するものなので、そこにInputも配置すれば良いだろう、とおもって。そこが大きな勘違いなのである。



誤った使用例

using UnityEngine;

public class Test:MonoBehaviour{
void FixedUpdate(){
if(Input.GetKeyDown(KeyCode.Space)){
//Action
}
}
}



5. Array, HashtableやArrayリストを間違った使用方法で使わないこと


Array、ArrayList、HashTableを用いないこと。.NETのジェネリックコレクションか組み込みされた配列を使用すべきである。古いコレクションでは多くのコードを記述しないと必要なオブジェクト型を得ることが出来ない一方で、ジェネリックコレクションはその問題を解決し、さらに必要であれば異なったオブジェクト型にも対応することも可能である



6. Quaternionのx,y,z値を更新しないこと


クォータニオンのx、y、z、wパラメータは、インスペクタで表示されるオブジェクトの回転の値と関係がない。x、y、z、wは角度で格納はされている(角度のサイン値、コサイン値で格納)。クォータニオンのx、y、z、wは、本当に何をやっているのか理解していないかぎり、修正すべきではない。もし何かの回転を角度で修正したい場合は.eulerAnglesを使用して修正すべきである。



7. KinematicでないRigidbodyでオブジェクトを移動しないこと


物理エンジンを使用する場合、KinematicでないRigidbodyを移動する場合はAddForceなどを使用すること。



8. CollisionやTriggerの発生条件を勘違いしないこと



  1. OnCollision、OnTriggerメソッドをふくむスクリプトの対象となるゲームオブジェクトにRigidbodyコンポーネントをアタッチすること

  2. 衝突するオブジェクトのどちらかのRigidbodyはスリープになっていないことが必要



9. Java, Javascript一般のプログラミング手法をUnityに持ち込まないこと

※gamesonytabletブログでは未投稿


UnityのJavascriptはJavascriptではない。多くの人はUnity Scriptと呼び区別する。UnityのJavascriptは、JavascriptというよりAction Scriptに近い.NET言語といえる。Javascriptのいくつかの機能はあるものの、大部分の機能がない。プロトタイプの継承よりも伝統的な継承が使われ、コンパイルの後に関数を加えることは出来ない、など違いはその他にも多くある。

どんな状況であっても本当のJavascriptのチュートリアルを学習したり、本当のJavascript本を読んでUnityに適用することはやるべきでない。ただ混乱するだけだ。



10. waitやyield後のcoroutineの終了条件を勘違いしないこと

※gamesonytabletブログでは未投稿


誤ったコルーチンの記述

void Update() {

if(health < 0) {
StartCoroutine(Die());
Destroy(gameObject); //あるいはenabled = false;
}
}

IEnumerator Die() {
animation.Play("wobble");
yield return new WaitForSeconds(3);
//次の行はコールされることがない
animation.Play("die");
}



11. C#スクリプトからJavascriptの相互参照を軽く考えすぎないこと


プロジェクトを記述する言語を一つ選ぶこと。もしサードパーティのコンポーネントの場合に完全に独立したものを使用する場合、一番最初にコンパイルされる特別なフォルダにこれらのスクリプトを置く、すなわちStandard Assetsフォルダ、Pro Standard Assetsフォルダ、 またはPluginsフォルダに置いて、かつ参照する側のスクリプトをこれらのフォルダには置かないようにすれば、どの言語で記述されていようとも問題ない。



上記で特に勉強になったところ


学習ステップ


1.「別スクリプトの変数やメソッドへの参照」


2.「OnTriggerやOnCollisionの判定条件」


4.「未来事象の正しい文法」

プログラミングではデザインパターンを学ぶことが学習の早道とされることが多いが、#1は経験からしか学ぶことが難しい変数やメソッドの使用について整理がなされている。

一方、#2、#4は「こういう風なやり方があることを知らなかった」という観点で推奨したい。

あらためてUnityマニュアルを読み返したが、確かにTriggerやCollisionの条件について詳細に書いてあるのだが、最初から全部を読むことはないだろうからハマるまで気付きにくいポイントだ。

「何秒後にこういうことをしたい」といったように、1フレームを超えた処理でコルーチンを使用しないといけないところで自分の理解が止まっていて、パターンによって簡単な記述方法があることを改めて認識できた。

さて、人によって気になる箇所が違うのではないかとおもう。他の人もどういうところが勉強になったかTwitterなどで共有してお互いの参考にしようぜ!!