砂風呂

いろいろなことを書く

Unity初心者が2DShootingGameのチュートリアルを読みました

ゲーム制作編第10回まで読みました。スクリプトを変更しつつ遊んでいたら無限ループに陥ったらしくUnityが落ち、シーンファイルがなぜか初期化されてしまいつらかったです・・・。気になった点をググって調べてみたのでそれをいくつかピックアップしてみます。雑なので綺麗に書く時はQiitaに書こうと思います。また、ここでは様々なサイトを参考にさせていただきました。ありがとうございます。

QuadとPlaneの違い

PlaneはXZ平面、QuadはXY平面の板
Planeは平らな床や平面を表示するのに利用
Quadは画像や動画、シンプルなGUIディスプレイを表示するディスプレイとして利用

LerpとClampとは

Lerpは、区間[a, b]をパラメータ0<=t=<1で線形補間する関数。たとえばa=3,b=7,t=0.4ならLerpの戻り値は4.6
Clampは、valueを入力として、区間[min, max]より外側をカットする関数。たとえばmin=-2,max=2,value=3ならClampの戻り値は2。

配列の初期値をインスペクタでセットする

あるクラスのフィールドに

public GameObject[] spawnObject;

と書くと、インスペクター上で
f:id:seaview_p35:20160606011833p:plain
このようにサイズが可変になり、各要素を指定できるようになる。

wavをシーン画面やゲームオブジェクトにD&DするだけでAudio Sourceコンポーネントが追加される

そのまんまです。

コルーチンでできそうなこと

・Start()でUpdateもどきが作れる。Unityではこういうのが良くあるらしい

IEnumerator Start()
{
  while(true)
  {
    //update like
    yield return null;
  }
}

・A→B→Cとアニメーションしたい時に以下のようなコードが使えたりする。BからCへはcondがtrueであるかぎり進まない。WaitForEndOfFrame()はEmitter.csに書いてあったが、yield return nullでも変わらなさそう(未検証)。WaitForEndOfFrame()はリファレンスによると、スクリーンショットをWWWFormなどを使ってどこかに送信するなどという用途らしく、かなり限定的な使い方らしい。

IEnumerator f()
{
  A();
  yield return new WaitForSecond(1.0f);
  B();
  while(cond)
  {
     yield return new WaitForEndOfFrame();
  }
  C();
  yield return new WaitForSecond(1.0f);
}

Unity3つの座標系

・ワールド座標系・・・3次元。原点は世界の中心。
・スクリーン座標系・・・2次元。カメラの写る範囲を(0, 0)から(640, 480)などで表す。ただしレゾリューションにより異なる点に注意。
・ビューポート座標系・・・2次元。カメラの写る範囲を正規化された座標系で表す。つまり(0, 0)から(1, 1)

衝突検出で注意すべき点

OnCollisionEnter, OnCollisionExit, OnCollisionStay, OnTriggerEnter, OnTriggerExit, OnTriggerStay 関数について。
・どちらかにRigidBodyがアタッチされてないとNG
・RigidbodyのIs KinematicがOffになってないとNG(物理演算が効かない)
・ColliderコンポーネントのIs TriggerがOffのとき→OnCollision〜関数が呼ばれる
・Is TriggerがOnならOnTrigger~であることに注意

まとめ

Transformを直接動かす方法でゲームオブジェクトを行うとそもそも物理演算が行われない。
Rigidbody.velocityに値を設定したり、Is Gravityなどによる物理演算が行われて初めて、OnColliderなんちゃらなどのイベントハンドラが実行される。


解決しなかったこと

・Sceneビューを見ているときに、wave.childcountが0のときに働くリスポーン機能が働かない。
・UnityのGUITextはなぜかSceneビューからは見れない謎
・GameObject (named 'XXXX') references runtime script in scene file. Fixing!
UnassignedReferenceException: The variable projectile of ‘explosion' has not been assigned.
というエラーが以下のコードで出てしまう。言い換えると、抽象クラスで定義された関数内で、抽象クラスで定義された変数を利用した時に以上のエラーが起きてしまう。これをメモする前に実際のコードを変更してしまったのでもしかしたら以下のコードは正しいのかもしれないがよく分からない。調査中。

class Spaceship : MonoBehaviour
{
  [SerializeField] protected GameObject explosion;
  
  protected void Explosion()
  {
    Instantiate (explosion, transform.position, transform.rotation);
  }
}

class Player : Spaceship
{
  void hoge()
  {
    base.explosion();
  }
}