2013/10/03(木) [n年前の日記]
#3 [unity] Unityのアレコレをメモ
ここ数日勉強したアレコレをメモ。まあ、メソッド名やクラス名でググれば、ちゃんとした解説記事がたくさん読めますけど。
ちなみに C# で書いてました。
以下は、"Enemy"タグを持ったオブジェクトと衝突した際の処理の例。
ちなみに C# で書いてました。
◎ 初期化と毎フレーム呼ばれるメソッド。 :
- void Start() { } は、初期化時に呼ばれる。
- void Updat() { } は、毎フレーム呼ばれる。ただし、どんな時間間隔で呼ばれるかは不明。
◎ 時間の取得。 :
- Time.deltaTime で、前回のフレームから今回のフレームまでの秒数(float。整数ではなく実数)が得られる。60FPS程度で回ってるなら、たぶん 0.016〜前後が返ってくるのかしら? 実測してないから分からんですが。
- float spd = Time.deltaTime * 1秒間で動いてほしい量、てな書き方をすれば、今回のフレームで動かすべきおおよその量が得られる。
- ゲーム起動時から現在までの時間(これも float による秒数)は、Time.time で取得できる。
- 処理が重くなったらあえて処理落ちさせる、といった作りにしたければ、Time.deltaTime は無視して作ったほうがいいのでしょうかね…? でも、一定の時間間隔で Update() が呼ばれてるのか分からんし…。
◎ 入力関係。 :
キーボードやジョイパッドの入力は、
- Input.GetAxisRaw("Horizontal")
- Input.GetAxisRaw("Vertical")
- Input.GetButtonDown("Jump")
- GetAxis〜() や GetButton〜() を使えば、キーボードにもジョイパッドにも反応してくれる。
- GetAxisRaw() は、-1 / 0 / +1 の値を返してくる。
- "Horizontal" は左右。"Vertical" は上下。
- GetButtonDown() は押した瞬間だけ true になる。
- "Jump" の他に、"Fire1"、"Fire2"、"Fire3" も指定出来る。
- どの種類がどのキーと割り当てられているかは、Edit → Project Settings → Input で確認できる。Inspector 上に "Horizontal"、"Vertical"、その他色々が2つあるけど、キーボード用とジョイパッド用で2つ設定が用意されてるらしい?
- ただし、ジョイパッドは、各ボタンがどこに割り当てられるかが製品によってバラバラ。ボタン割り当てを変更可能な仕様を入れないとマズイかもしれず。
◎ シーンの切り替え。 :
- Sceneの切り替えは、Application.LoadLevel(シーン番号); を使う。
- シーン番号は、Build Settings → Scenes In Build で登録(?)した際に割り当てられる。D&Dで並びを変えられる。
◎ transformで動かすか、rigidbodyで動かすか。 :
アタリ判定をするオブジェクトは、transform.position += new Vector3(x, y, z) よりも、rigidbody を指定して動かしたほうがいい、という話を見かけた。transform で動かすと瞬間移動してるような状態になるけれど、rigidbody なら連続して移動している感じの処理にすることもできる、とかなんとか。
rigidbody.velocity = new Vector3(x, y, z) で速度を設定して、Is Kinematic のチェックを外しておけば、その速度で自動で動いてくれる。
速度の単位は、1秒間にどれだけ動くか。
rigidbody.velocity = new Vector3(x, y, z) で速度を設定して、Is Kinematic のチェックを外しておけば、その速度で自動で動いてくれる。
速度の単位は、1秒間にどれだけ動くか。
◎ 画面外判定と補正。 :
画面外にプレイヤーキャラが飛び出さないようにする処理は以下のように書いてみたけど、これで正解なのか自信無し。
// 画面外判定と補正 npos = Camera.main.WorldToViewportPoint(transform.position); Vector3 o = transform.position; if (npos.x < 0.05f) { Vector3 left = Camera.main.ViewportToWorldPoint(new Vector3(0.05f, npos.y, npos.z)); transform.position = new Vector3(left.x, o.y, o.z); } if (npos.x > 0.95f) { Vector3 right = Camera.main.ViewportToWorldPoint(new Vector3(0.95f, npos.y, npos.z)); transform.position = new Vector3(right.x, o.y, o.z); } npos = Camera.main.WorldToViewportPoint(transform.position); o = transform.position; if (npos.y < 0.1f) { Vector3 bottom = Camera.main.ViewportToWorldPoint(new Vector3(npos.x, 0.1f, npos.z)); transform.position = new Vector3(o.x, o.y, bottom.z); } if (npos.y > 0.9f) { Vector3 top = Camera.main.ViewportToWorldPoint(new Vector3(npos.x, 0.9f, npos.z)); transform.position = new Vector3(o.x, o.y, top.z); }
- Camera.main.WorldToViewportPoint(transform.position) は、ワールド座標をメインカメラから見た座標系に変換してくれる…のでしょうかね? よく分からない…。
- ViewportToWorldPoint() は、WorldToViewportPoint() の逆をしてくれるのかな? たぶん。
- 左下が(0,0)、右上が(1,1)。
◎ オブジェクトの消去。 :
自分自身を消滅させたかったら、Destroy(this.gameObject); を呼ぶ。
◎ アタリ判定とタグ。 :
- Inspector 上で、○○○ Collider 等の Is Trigger にチェックを入れておけば、何かしらと衝突した際に OnTriggerEnter() その他が呼ばれる。
- OnTriggerEnter() は、衝突した際に1回だけ呼ばれる。
- 衝突中にずっと呼ばれるメソッドや、衝突しなくなったら呼ばれるメソッドもあるらしい。
- 何と衝突したかは、タグを使って判断することができる。
- タグ(Tag)は、Inspector の上のほうでオブジェクトごとに設定可能。タグの追加がしたければ、Add Tag を選ぶ。Inspector 内の表示がタグ一覧になり、Element 0 の右横が空欄になってるはずなので、そこをクリックして任意のタグ名を入力。同じ手順でタグを増やせる。
以下は、"Enemy"タグを持ったオブジェクトと衝突した際の処理の例。
void OnTriggerEnter(Collider other) { if (other.gameObject.tag == "Enemy") { Player.score += 10; Enemy obj = other.GetComponent(typeof(Enemy)) as Enemy; obj.DeadStart(); Destroy(this.gameObject); } }
- スコアを10点増やして、
- 衝突してきた相手に「死んどいてね」とメッセージを送って(死亡処理開始のメソッドを呼んでる)、
- 自分を消滅させる、
◎ 特定のタグを持っているオブジェクトを検索してポインタを取得。 :
以下の例は、"BgmManager" というタグを持っている GameObject を検索してポインタ(?)を取得する例。BgmManagerクラスには、StartFadeout() というメソッドを追加済み。
// BGMフェードアウト開始 GameObject bgm = GameObject.FindGameObjectWithTag("BgmManager"); BgmManager mbgm = bgm.GetComponent<BgmManager>(); mbgm.StartFadeout();
- GameObject.FindGameObjectWithTag("タグ名") で、そのタグ名が割り当てられたオブジェクトを取得できる。
- ただし、取得できたオブジェクトは GameObject なので、そのオブジェクトに割り当てたクラスに変換(キャスト?)しないと…。
- hoge.GetComponent<変換したいクラス名>(); で変換できるらしい。
◎ テキスト表示。 :
OnGUI() というメソッドを書いておくと、簡易GUIが作れるらしい。
以下の例は、黒い半透明の箱を描画してその上に文字列を描画する処理。
以下の例は、黒い半透明の箱を描画してその上に文字列を描画する処理。
void OnGUI() { string str = "move: Arrow key or WASD\n\nPush SPACE or Button to start"; int w = 320; int h = Screen.height; int x = (Screen.width - w) / 2; int y = h / 2 - 48; GUI.Box(new Rect(x, y, w, 96), str); }
- GUI.Box(new Rect(x, y, w, h), "表示したい文字列"); で描画できる。Rect() が、箱の位置とサイズを指定。
- マウスクリック可能なボタンを作ったりもできるらしい。
- 指定文字列中で、改行文字を使うこともできるみたい。
◎ 画面サイズの取得。 :
Screen.width、Screnn.height で、画面横幅、画面縦幅が得られる。
◎ サウンド再生。 :
- 効果音を鳴らしたい時は、鳴らすオブジェクトに AudioSource を追加しておく。オブジェクトを選択しておいた状態で、Unity上部のメニューから、Component → Audio → Audio Source。もしくは、Inspector の一番下の「Add Component」から、なのかな。
- Audio Source てのは、スピーカ相当らしい。音を出してくれるブツ、という扱い。
- スピーカから流れてきた音を聞く、「耳」に相当するブツも必要。それが、Audio Listener。
- 初期状態では、メインカメラにあらかじめ Audio Listener がついているので、各オブジェクトに Audio Source をつけてそこから音を出してやれば、耳がついているも同然のメインカメラが音を拾ってくれて、それがPCのスピーカから流れてきますよ、という状態らしい。
- スピーカから流す波形データは、AudioClip なるクラスで扱う。
using UnityEngine; using System.Collections; public class ExplosionSe : MonoBehaviour { public AudioClip se1; public AudioClip se2; float chktime; // Use this for initialization void Start() { AudioClip se = (Random.value < 0.5) ? se1 : se2; audio.PlayOneShot(se); chktime = Time.time + se.length + 1.0f; } // Update is called once per frame void Update () { if (Time.time > chktime) Destroy(this.gameObject); } }このソースを、Audio Source をつけたオブジェクトに割り当てる → se1 と se2 は Inspector 上で「None」(未割り当て?)と表示されてるので、Assets から波形ファイルをD&Dして設定する。
- 効果音を鳴らしたいときは、audioSource.PlayOneShot(audioClip)を使うのかな。たぶん。名前からしてワンショット系の鳴らし方をしてくれる…のではないかと。
- audioClip.length で、その波形の長さ(秒数?)が取得できるらしい。
- 鳴らしたオブジェクトが消滅すると、音も消えてしまう。…スピーカ相当が消滅するから音も消えるのは当たり前か。
◎ 乱数。 :
- Random.value で、0.0〜1.0の値が取得できる。
- Random.Range(最小値、最大値) で、最小値〜最大値の間の乱数を取得できる。
- Random.Range() は、int と float のどちらを指定するかで、動作が変わってくる。int の場合は最大値を含まない乱数が、floatの場合は最大値を含む乱数が出てくる、という話を見かけた。
[ ツッコむ ]
以上です。