Unity入門5

Space Shooter②

(スペースシューター)

  • 前回までで【プレイヤー】【カメラ】【ライト】【背景】の用意が出来ました。
  • まずは、プレイヤーを動かせるようにして行きましょう。
  • こっから本番です。

状況確認

  • キーボードでプレイヤーを動かす】というプログラムは、実は今回が初めてですね。
  • ゲーム作りには非常に重要な部分なので、ゆっくり進んで行きます。

プレイヤーを動かす

  • まず、キーボードの動きについて、ちゃんと理解しておきましょう。
  • そもそもキーボードマウスなどは【入力機器(にゅうりょくきき)】と呼ばれる物で、キーを押すと【◯◯キーが押されたで】というデータをパソコン側に送ってくれるだけの物です。
  • その入力機器とは反対に、出力されるだけの物を出力機器と呼びます。パソコンのディスプレイなどのことです。
  • つまりパソコンは、送られてきたデータを受け取り【aキーが押された言うとるし、aってディスプレイに出力(表示)したろ】という処理をしているに過ぎません。

キーボード(入力)

パソコン(入力を受け取り、出力に渡す)

ディスプレイ(出力)

  • ちなみノートパソコンは、この3つを見た目的に合体させてるだけで、中身は同じように分かれています。
  • 今回は十字キーなどでプレイヤーを動かしますので、キーボードから送られてくる「上のキーが押されてるで!」「右のキーが押されてるで!」という情報を受け取り、【上キーならz座標を+にする】などの処理のプログラムを用意すれば良いということになります。
    • ※今作っているゲームは【z座標がタテ】【x座標がヨコ】の構図になっています。

プレイヤーを動かす

ギズモを見ると分かりやすいです。

xプラス

方向

xマイナス

方向

zマイナス

方向

zプラス

方向

  • では、実際にプログラムを作って行きましょう。
  • スクリプトを作る前に、まずはスクリプトを保存する用の【Spricts】フォルダを作りましょう。
  • Assets】を右クリックし、【Create】→【Folder】を選んでください。
  • 新しいフォルダが出来れば、名前をSpricts】に変更しておきましょう。

プレイヤーを動かす

  • では、次はこの【Spricts】フォルダの中にスクリプトを作ります。
  • ​【Spricts】フォルダを右クリックし、【Create】→【C# Script】を選択してください。
  • 名前は【PlayerController】にしておきましょう。
    • ※この先、全てのスクリプトは【Spricts】フォルダに作ります。特に指示がなくてもスクリプトは【Spricts】フォルダの中に作ってください。​

プレイヤーを動かす

  • 早速スクリプトの中身を作って行きましょう。
  • 今こんな感じでしたね。
  • 一応おさらいしておいてください。

プレイヤーを動かす

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour {

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

Using文

Unity専用のメソッドを使える(短く使える)ため必要

クラス設定

名前はスクリプトファイルと同じでないとエラー。

【:MonoBehavior】は継承している親クラス(Unityのスクリプトはでは必ずコレを継承する)

ゲームスタートの時に【1回だけ】

呼び出されるメソッド

1フレーム事に

【何度も】

呼び出されるメソッド

  • 今回はstartメソッドは使いませんので、消しておいてください。
  • まずは、以下のように変数speed(スピード)を作っておきます。

プレイヤーを動かす

public class PlayerController : MonoBehaviour {
    public float speed;

    void Update (){
    }
}
  • 次にUpdateメソッドの中に、以下の変数を追加しましょう。
public class PlayerController : MonoBehaviour {
    public float speed;

    void Update (){
        Vector3 nowP =  GetComponent<Rigidbody>().position;
        float moveH = 0;
	float moveV = 0;
    }
}
  • さて、ここで「メソッドの外で変数の宣言するのと、メソッドの中で宣言するのは何がちゃうんや?」と疑問に思ったかも知れません。くわしくは次へ。
  • 今まで【変数の宣言場所】に関して、あまり詳しく説明せずに進めてきましたので、基本的に変数はメソッドの外で宣言しておくもの】として理解しているかも知れません。
  • それは必ずしも間違いというわけではありませんし、実際、その方法だけで書く人も多くいます。
  • ただ、変数は【なるべくスコープがせまい方が良い】という大原則があります。
    • ※スコープとは、【その変数が使える範囲】でしたね。
  • そのため、【そのメソッドでしか使わない変数】は【メソッドの中で宣言する方が良い】のです。
  • 理由は2点あります。
    • 第1に、メソッド外や別メソッドで同じ名前を使えます(バッテングしない)。
    • 第2に、メモリのムダ使いが防げます。
      • 少し詳しい話しをすると、変数が作成されるとコンピュータの内部では【メモリに保存領域を確保する】という処理が行われます。
      • その確保されたメモリ領域は、スコープ範囲を超えないと解放されません。使われていなくても領域は確保されたままになります。
      • つまり無意味に変数のスコープが広いと、ムダなメモリが使われるということです。
        • ​※自動でメモリを解放する仕組みをガベージコレクション(GC)と言い、ほとんどの言語には用意されていますが、CやC++などGCがない言語もあります。その場合は手動でメモリ解放の処理を書かなければ行けません。

変数の宣言場所

  • ただし、この議論の時に必ず【ループの中で変数の宣言をするのは、処理速度が遅くなるんじゃ?】という意見もあります。
  • でも、実際は影響がないので、ループの中で変数を宣言しても全然OKです。
  • メソッド内で宣言された変数を【ローカル変数】と言います。
    • ちなみに以前にやった【クラス変数】(staticをつけた変数)は【グローバル変数】とも言います。
  • 色々な変数の名前が出てきたので、まとめとくと、
    • ローカル変数 →
      • [作成方法:メソッド内で宣言する] [スコープ範囲:メソッド内のみ]
    • フィールド(メンバ変数) →
      •  [作成方法:クラス内、メソッド外で宣言する] [スコープ範囲:クラス内]
    • クラス変数(グローバル変数)→
      •  [作成方法:フィールドにstaticをつける] [スコープ範囲:プログラム全体]

変数の宣言場所

  • 尚、pubilcやprivateなどの【アクセス修飾子】は、上の変数の種類とは別です。
  • 色々あって、わけわかめになってくるのですが、
    • 上の色々な変数は【スコープの範囲(見える範囲)】で、
    • pubilcやprivateは【アクセス出来る範囲】です。
  • ​基本的にローカル変数は、作られてからすぐ消える存在なのでpublicやらは付けれません。(強制的にprivateのイメージ)
  • それ以外のフィールドやクラス変数はpubilcにすることが出来ます。
    • ​※尚、スコープの範囲に関しては特殊な状況では、上の通りにならない事もありますが、まず現段階では出くわさない書き方なので、気にしなくても良いです。
  • さて、いつも通り脱線しましたが、続きのプログラムを作っていきましょう。次は【キーボードの入力を取得する】部分です。
  • キーボードの入力は【Input.GetKey()】というメソッドで取得できます。
  • 引数に【どのキーか?】を指定すると、そのキーが【押されているとtrue】【押されていないとfalse】が戻り値として返されます。
  • bool型で返ってくるということは、下のようにif文などの条件に使うというわけです。

プレイヤーを動かす

  • 【どのキーか?】の指定は上のように【"◯◯"】というように指定します。
  • 十字キーの指定はそれぞれ以下の通りです。
    • 右矢印キー:"right"
    • 左矢印キー:"left"
    • 上矢印キー:"up"
    • 矢印キー:"down"
      • ​覚えやすいですね。次に続く。
        if (Input.GetKey ("right")){
            //ここにキーが押された処理を書く。
	}
  • 次は押された時の処理です。つまり【移動の処理】ということです。
  • これは、コイン落としゲームで作った【動く床】の処理とほとんど同じです。

プレイヤーを動かす

  • まずは、右矢印キーの処理を作りましょう。
  • 変数speedを変数moveHに代入しています。
    • ちなみにこの変数moveHHは【Horizontal(ホリゾンタル:水平)】の頭文字で、
    • もう一つの変数moveVVは【Vertical(バーティカル:垂直)】の頭文字です。
    • つまり【ヨコ方向の動きは変数moveH】【タテ方向の動きは変数moveV】として使う予定です。
  • ​この時点で変数moveH1回キーを押された時の移動距離】が入っている状態です。
  • ​そして、この変数moveHを変数nowP(コイツには【GetComponent<Rigidbody>().position】、つまりが現在の座標が入っていますね)と足し、【GetComponent<Rigidbody>().MovePosition】に代入し直すことによって、【1回キーを押された時の移動距離】分だけ移動をしています。
  • これが繰り返されることで、キーボードでプレイヤーが移動することができます
    • ​次に続く。
if (Input.GetKey ("right")){
    moveH = speed;
    GetComponent<Rigidbody>().MovePosition(nowP + new Vector3(moveH,0,moveV));
}
  • さて、このコードは繰返しの中で処理する必要がありますので、当然Updateメソッドに記入します。
  • ただ、今回は物理演算のが必要なオブジェクトRigidbodyコンポーネントがあるオブジェクト)なので、Updateメソッドを【FixedUpdate】メソッドにしないといけませんでしたね。
  • つまり、現時点では以下のようになります。
    • ※本来【input〜系】のメソッドは【Update】メソッドに入れたほうが良いのですが、とりあえず今はこのまま進みます。

プレイヤーを動かす

  • ちなみに【new Vector3(moveH,0,moveV)】に変更していないはずのmoveV(タテの移動距離)があるのは、後でタテ方向の動きを追加した時に、ヨコとタテと同時押しすると、ナナメ移動になるようにするためです。
  • ここで、一旦試してみましょう。
  • スクリプトをプレイヤーにアタッチし、Inspectorビューからspeed変数に数値を設定しましょう。とりあえずは0.3ぐらいが、見本のゲームに近いと思います。
  • もちろん今は右にしかいかないので、右に動けばOKです。
    • ※画面の外に飛んで行ってしまいますが、今はこれでOKです。

プレイヤーを動かす

  • スクリプトにコードを追加し、右以外の方向にも移動出来るようにしてください。
    • ヒント①:以下の画像を思い出してください。マイナス方向への動きは単純にspeedにマイナスをつけて代入すれば可能です。
    • 【GetComponent<Rigidbody>().MovePosition(now + new Vector3(moveH,0,moveV))】の部分はそのままでOKです。
      • ※変える方法もありますが。
    • ​​出来たら必ず見せてください。

試してみよう

  • 次は左右の動きに合わせて、機体が傾く(ヨコ回転させる)ようにしてみましょう。
  • オブジェクトを回転させるには【GetComponent<Rigidbody>().MoveRotation()】というメソッドを使います。
    • ※【〜.MovePosition()】と似ているので注意。
  • 【〜.MoveRotation()】の場合は、引数にQuaternion(クォータニオン:四元数)で指定することになります。
  • Quaternionにも色々なメソッドがありますが、一番カンタンな【Quaternion.Euler】を使います。

回転させる

void FixedUpdate () {
	Vector3 nowP = GetComponent<Rigidbody>().position;
	float moveH = 0;
	float moveV = 0;
        if (Input.GetKey ("right")){
            moveH = speed;
            GetComponent<Rigidbody>().MovePosition(now + new Vector3(moveH,0,moveV));
            GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f));
        }
}
  • Quaternion.Euler】は引数で与えたxyzを元に、四元数からEuler(オイラー)角というものに変換してくれます。
  • まぁあまり深く考えなくても良いので、xyzで回転を指定する方法だと思ってください。
  • 次は左矢印も同じようにしましょう。
  • 右矢印に設定したコードの【Quaternion.Euler (0.0f, 0.0f, -50.0f】をQuaternion.Euler (0.0f, 0.0f, 50.0f】にするだけでOKです。
  • 出来たら試して見ましょう。
    • ​※数字も色々変えてみてもいいでしょう。

回転させる

  • すでに気づいているかと思いますが、今のままだと、一度右か左を押すと、ずっとプレイヤーが傾いたままになってしまいます。
  • 左右の矢印キーを【離す】と、元の角度に戻るように設定します。
  • この【離す】判定を受け取るメソッドは【GetKeyUp()】メソッドになります。
  • 使い方はほとんど同じです。
if(Input.GetKeyUp ("right"){
        GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, 0.0f));
}
  • これで【右キーを離した時】を指定して回転を元に戻せます。
  • 左キーに関しては次のページで試してください。

回転させる

  • 右キーだけじゃなく、左キーを離した時もプレイヤーの傾きを元に戻せるようにしてください。
  • ただし【if文は増やさず】、下のif文に変更を加えてください。

試してみよう

  • さて、キーボードで動かす方法に関してはできました。
  • でも、もし遊ぶ人がゲームパッド(パソコンの繋いで使う、ゲーム用のコントローラー)などで遊ぼうとした場合、実は、このままだとまったく動かせません。

別の動かし方

ゲームパッド

  • またゲームパッドにはスティック型の入力方法がありますが、こいつは【押した(true)】【押していない(false)】という2通りの情報ではなく、押し具合によって微妙に数値が変化する(0.0〜1.0)なので、GetKey()メソッドのように戻り値がbool型メソッドでは入力が正しく取得できません。
  • そのため、Unityでは複数の入力機器に対応したメソッド【Input.GetAxis()】というのが用意されており、戻り値もfloat型になっているため、スティックの入力も正しく取得できます。
    • 次に続く。
  • では、実際にInput.GetAxis()】に切り替えてみましょう。
  • 今までのコードとの違いを理解したいので、まず【FixedUpdate () 】メソッドの中のコードは、一旦すべてコメントアウトしておいてください。※絶対に消さない。
    • ​コメントアウトとは、その部分のコードをコンピューターがムシするようにする設定です。
    • 行の先頭に//をつければ良いですが、一気にする場合は、コメントアウトしたい場所を選択し(マウスで囲んだ状態)で、【コントロールキー(Ctrl)+ Kキー】を同時押しした後に【コントロールキー(Ctrl)+ Cキー】を押してください。※Windowsの場合

Input.GetAxis()

void FixedUpdate () {
//	Vector3 nowP = GetComponent<Rigidbody>().position;
//	float moveH = 0;
//	float moveV = 0;
//       
//     if (Input.GetKey ("right")){
//         moveH = speed;
//         GetComponent<Rigidbody>().MovePosition(nowP + new Vector3(moveH,0,moveV));
//         GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f))
//     }
}
  • ※上のコードでは右キー("right")だけですが、左も上も下も全部不要です。一気にコメントアウトしてしまいましょう。一番下の}(なみかっこ)までコメントアウトしないよう注意。
    • わからなければ必ず聞いてください。
  • まず、下のようにコメントアウトした上に、【Vector3 nowP = GetComponent<Rigidbody>().position;】を再度記入し直してください。(ここは、コメントアウトしているVector3 nowP〜とまったく同じなので、コピペでOK)
  • その下に【moveH】と【moveV】変数を作りInput.GetAxis()】を以下のように代入してください

Input.GetAxis()

void FixedUpdate () {
        Vector3 nowP = GetComponent<Rigidbody>().position;
	float moveH = Input.GetAxis ("Horizontal");
	float moveV = Input.GetAxis ("Vertical");

//	Vector3 nowP = GetComponent<Rigidbody>().position;
//	float moveH = 0;
//	float moveV = 0;
//       
//     if (Input.GetKey ("right")){
//         moveH = speed;
//         GetComponent<Rigidbody>().MovePosition(nowP + new Vector3(moveH,0,moveV));
//         GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f))
//     }
}
  • 後は、この値が入った変数を座標にし、現在の座標(nowP)と足し合わせた場所に移動させればOKです。これはInput.GetKey()】と同じです。

Input.GetAxis()

void FixedUpdate () {
        Vector3 nowP = GetComponent<Rigidbody>().position;
	float moveH = Input.GetAxis ("Horizontal");
	float moveV = Input.GetAxis ("Vertical");
        GetComponent<Rigidbody>().MovePosition (nowP + new Vector3(moveH,0,moveV) * speed);

//	Vector3 nowP = GetComponent<Rigidbody>().position;
//	float moveH = 0;
//	float moveV = 0;
//       
//     if (Input.GetKey ("right")){
//         moveH = speed;
//         GetComponent<Rigidbody>().MovePosition(nowP + new Vector3(moveH,0,moveV));
//         GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f))
//     }
}
  • これで完成です。非常にカンタンになりましたね。
  • では、試してみましょう。十字キーだけじゃなく、w、a、s、dキーでも動くようになっています。
    • (パソコン版のマイクラなどと同じ操作です)
  • 動き方が微妙に違うと思いますが、ちゃんと動いたと思います。
  • 内部的にはInput.GetKey ()】の時と、ほとんど同じように動いています。
    • ※傾きに関しては、傾かない状態に戻っていますが、これは後で直します。

Input.GetAxis()

  • このように、基本はInput.GetAxis()】で作った方が良いです。
  • ぶっちゃけ【Input.GetKey ()】はただ遠回りしただけなのですが、Input.GetAxis()】だと、なぜ動いているのかイマイチ理解しにくいので、あえて【Input.GetKey ()】でも作ってもらいました。
  • ちなみにInput.GetKey ()】と【Input.GetAxis()】の微妙な動きの違いの原因は、【Input.GetAxis()】の場合、キーボードのキーを押しても、【スティックが押した時の動きを再現しようとする】ためです。
  • つまり本当はキーボードからの入力は【押した】か【押してない】の2つしかないのを、スティックで操作した時のように、【倒していない(0.0f)】から【軽く倒してる(0.3f)】や【強く倒してる(1.0f】といった微妙な入力の違いを再現しようと、数値に補正をかけるため、徐々にスピードがあがるような動きをします。
  • 反対に、数値に補正をかけないメソッド【Input.GetAxisRaw()】というものがあります。
  • 使い方は【Input.GetAxis()】とまったく同じです、【Input.GetAxisRaw()】の場合は、補正をかけない(キーボードでは【0か1】のになる)ため、基本的に【Input.GetKey ()】と同じ動きになります。
  • これはどちらでも良いですが、ココではInput.GetAxis()】で進めます。

Input.GetAxis()

  • さて、よりオブジェクトの動きを知るために、さらに別の動かし方もしてみましょう。
    • と言ってもInput.GetAxis()から、また変えるわけではありません。
  • 今までやった【Input.GetKey ()】や【Input.GetAxis()】や【Input.GetAxisRaw()】は【入力を受け取る】方法です。
    • 入力”の事をinput(インプット)と良い、【入力を受け取る】メソッドはすべて【Input.】から始まります。前にマウスの入力を受け取る時も【Input.GetMouseButtonDown()】というメソッドでしたね。
  • つまり【入力を受け取る】Inputメソッドの使い方を、3通り(以前のゲームを含めれば4通り)の方法学んだわけです。
  • 実際は他にもありますが、Inputに関しては、今までやった方法でほぼすべての事が出来ると思うので、特に困ることはないと思います。

Input.GetAxis()

  • 次に変えるのはプレイヤー(オブジェクト)の動き】自体です。
  • これも今まで何度もやってはいますが、色々な方法があるため、非常に重要なのにも関わらず、混乱しやすいポイントでもあります。
  • 一旦【オブジェクトの動かす】という事に関して、整理してみましょう。
    • 次に続く。
  • まず第一に【何を対して動きを与えるのか?】を整理しましょう。これはカンタンです。
    • 1transform】(トランスフォーム:オブジェクト自身)か
    • 2rigidbody】(リジッドボディ:オブジェクトの物理演算コンポーネント)になります。​​
  • 1transform】と【2rigidbody】は、内部処理の違いで、以下のような使い分けでした。
    • rigidbodyコンポーネントがあるオブジェクトは【rigidbody】を使うべき。
    • rigidbodyコンポーネントがないオブジェクトだけ【transform】を使うべき。

【オブジェクトの動かす】の整理

  • ​次に、【どんな動きを与えるか?】です。大きくわけて位置を変える】のと回転(方向)を変える】のがありますが、今は​位置を変える】ことだけに絞って考えます。
  • transform】の【位置を変える】方法は、
    • 1-1transform.position】(ポジション:座標)と、
    • 1-2transform.Translate()】(トランスレート:〜を動かす)があります。
  • 1-1transform.position】は単純でわかりやすい分、指定された座標に瞬間移動するだけなので、リアルな動きは出来ないやりづらい)です。
    • また、この【transform.position】は、座標が入ってるだけの「ただの変数」で、オブジェクトは、この座標の位置に描画されます。
    • この変数の値を代入し直すことで、その場所にオブジェクトをワープさせることで動かします。
  • 1-2transform.Translate()】はベクトルで動かす方法です。※まだ使ってません。
    • こちらはメソッドで、引数に与えられた座標データから、ベクトル(方向と大きさ)を算出し、その場所までちゃんと移動します。(ワープしない)
  • 次に、【2rigidbody】で動かす方法です。こちらはさらに色々な方法があります。
    • 2-1GetComponent<Rigidbody>().position
    • 2-2GetComponent<Rigidbody>().MovePosition()
    • 2-3GetComponent<Rigidbody>().velocity】(ベロシティ:速度)
    • 2-4GetComponent<Rigidbody>().AddForce()​(フォース:力)
  • 2-1GetComponent<Rigidbody>().position】は、動きとしては1-1transform.position】と同じで瞬間移動です。変数であるところも同じです。
    • この変数の値は1-1transform.position】と必ず一致するため、どちらかの変数を変更すると、もう片方も同じ値になります。
  • 2-2GetComponent<Rigidbody>().MovePosition()】は、1-2transform.Translate()】と似ていて瞬間移動にはならず、移動途中も物理演算が働きます。これはメソッドです。
  • 2-3GetComponent<Rigidbody>().velocity】は、オブジェクトに特定の座標軸(方向)に対して【速度】を与えることで動かします。
    • なんだかわかりにくいですが、これは変数ですので【rigidbodyには速度というプロパティがあり、例えばxの軸に対して速度を与える(数値を増やす)と、その方向に進む】ということです。
    • 感覚的にはx座標で動かすのと似てますが、オブジェクトに速度を与えた場合は、繰返し座標を変えたりする必要がなく、速度が失われない限り(0にならない限り)は移動し続けます。
    • 速度は何かにぶつかったり、質量や摩擦などの影響でなどで減っていきます。
  • 2-4GetComponent<Rigidbody>().AddForce()】​は、上の【速度】と違いがわかりにくく、混乱する可能性大のポイントですが、実は現実世界を例に考えると理解し易いです。
    • 次に続く。

オブジェクトの動き

  • 現実世界において、基本的に、物(オブジェクト)が動くきっかけは【力】が加えられた時です。
    • 力が加えられた結果、速度が生まれ、物は動きます。
  • 2-3GetComponent<Rigidbody>().velocity】(速度)と【2-4GetComponent<Rigidbody>().AddForce()】(力)の違いもソコです。
  • つまり【力】の部分をすっ飛ばして、ただ【速度】だけをプロパティ(変数)に指定しているのが2-3GetComponent<Rigidbody>().velocity】で、これは現実世界には起こり得ない現象です。
  • 反対に、現実世界と同じように、まず【力】を与え、その結果オブジェクトに【速度】が生まれ、オブジェクトが動くのが【2-4GetComponent<Rigidbody>().AddForce()】になります。
  • また、本来は同じ【力】を与えたとしても、物体の質量などによって【速度】は異なりますよね?
  • 2-4GetComponent<Rigidbody>().AddForce()】は、これをちゃんと計算してから【速度】にしてくれるメソッドというわけです。
    • 以上のことからもわかる通り2-4GetComponent<Rigidbody>().AddForce()】の方が、より現実世界と同じように(リアルに)に動きます。

オブジェクトの動き

  • とは言っても「じゃあ【力】で動かすのが1番良いのか?」というと、そういうわけではありません。
  • ゲームなんですから、無理に現実世界と同じようにする必要はないのです。
  • なので、ここで整理した移動方法は、どれも良く使います。
  • では、実際に【2-3GetComponent<Rigidbody>().velocity】と【2-4GetComponent<Rigidbody>().AddForce()】の両方の動きも作って、違いを確かめてみましょう。
  • さて、では速度で動かす場合と、力で動かす場合を比べてみましょう。
  • まずは、現在のコードはすべてコメントアウトしてから新しく書きましょう。
    • ※それぞれの作り方を比較出来るように残しています。消さないように。
    • ※コードの下のようにコードの説明を書いておくと、見直した時にわかりやすいですね。

速度で動かす

void FixedUpdate () {

//    ★この下は、Input.GetAxisで座標を動かすコード
//    Vector3 nowP = GetComponent<Rigidbody>().position;
//	float moveH = Input.GetAxis ("Horizontal");
//	float moveV = Input.GetAxis ("Vertical");
//   GetComponent<Rigidbody>().MovePosition (nowP + new Vector3(moveH,0,moveV) * speed);

//    ★この下は、Input.GetKeyで座標を動かすコード
//	Vector3 nowP = GetComponent<Rigidbody>().position;
//	float moveH = 0;
//	float moveV = 0;
//       
//     if (Input.GetKey ("right")){
//         moveH = speed;
//         GetComponent<Rigidbody>().MovePosition(nowP + new Vector3(moveH,0,moveV));
//         GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f))
//     }
}
  • では、ここに下のように新しいコードを書いていきます。
  • moveH】と【moveV】変数はまったく同じなのでコピペでOKです。
    • ※ココではコメントアウト部分は省略して書きますが、実際には消さないでください。
    • また【FixedUpdate ()】以外のコードに変更はありません。 

速度で動かす

void FixedUpdate () {
        float moveH = Input.GetAxis ("Horizontal");
        float moveV = Input.GetAxis ("Vertical");
        Vector3 nowP = new Vector3(moveH,0,moveV);
        GetComponent<Rigidbody>().velocity = nowP * speed;
}
  • 【速度】を与えてオブジェクトをぶっ飛ばすのは、以前にもやっていますが、今回はぶっ飛ばしてはダメなので、速度を与えたままではなく、キーを押していない時は止まるようにしています。
    • と言っても、見ての通り特別なことはしておらず、【Input.GetAxis()はキーが押されていない時は0を返す】ことを利用して、常に【.velocity】(速度)を更新することで、キーを離すと速度も0になるようになっています。
      • ※前にコインとかを、ぶっ飛ばしたときは速度を与えただけだったので、勝手に飛び続けていましたね。
      • 次に続く。
  • 動きましたでしょうか?
  • 座標で動かす時に比べて、数値が大きくしないと遅くなりすぎる以外は、それほど大きな違いはないと思います。

速度で動かす

  • 次は【力】で動かすパターンです。
  • 先ほどの【速度】で作ったコードはコメントアウトしましょう。
    • ​速度のコード、とコメントもつけておきましょう。
  • これでコードは完成していますが、speed変数が0.3fとかのままでは、かなり遅くなります。
  • Inspectorビューからspped変数を10ぐらいにして、実際に動かしてみてください。
  • 【速度】で作ったコードはコメントアウトしたら、下のコードを作ってください。
  • moveH】と【moveV】変数はまったく同じなのでコピペでOKです。
    • ※ココではコメントアウト部分は省略して書きますが、実際には消さないでください。
    • また【FixedUpdate ()】以外のコードに変更はありません。 

力で動かす

void FixedUpdate () {
        float moveH = Input.GetAxis ("Horizontal");
        float moveV = Input.GetAxis ("Vertical");
        GetComponent<Rigidbody>().AddForce(new Vector3(moveH,0,moveV) * speed);
}
  • .AddForce()が力を与えている部分です。
  • これはメソッドなので、これだけで力が加えられ、物体が動きはじめます。
  • まだ完成ではありませんが、この状態で動かしてみてください。
    • ​次に続く。
  • かなり奇妙な感じになったと思います。

力で動かす

  • まず、一旦力を加えるとずっとその方向に進んでいますね。
  • これは、座標や速度と違って変数に0や1を入れて動かしているわけではないので、一旦加えた力は、次に0の力を与えたとしても、0に上書きされるわけではありません。
  • つまり【x = x + 0】みたいな感じです。
  • 一方速度は変数の値を直接上書きしているのでx = 0】になるということです。
    • ​次ページ。
  • では、この動きを止める方法は?というと以下の書き方になります。

力で動かす

  • GetComponent<Rigidbody>().velocity】に、【new Vector3(0,0,0)】を突っ込んでいます。
  • つまり、GetComponent<Rigidbody>().velocity】の値を0にしているということです。
  • 「あれ?GetComponent<Rigidbody>().velocityって速度の指定じゃないの?」と思った方、正解です。
  • 結局、動きを止めるには速度のプロパティ(変数)をイジります。
  • つまり、【力】というプロパティはなく、与えた数値を【力】として物理演算し、その結果として【速度が生まれて動く】という流れなのです。
  • なので、速度自体を直接0にしてしまうと、動きは完全に止まります。
void FixedUpdate () {
        float moveH = Input.GetAxis ("Horizontal");
        float moveV = Input.GetAxis ("Vertical");
        GetComponent<Rigidbody>().AddForce(new Vector3(moveH,0,moveV) * speed);
        GetComponent<Rigidbody>().velocity = new Vector3(0,0,0);
}
  • この状態で動かしてみましょう。
  • すっごく遅くなると思います。
    • 次に続く。
  • さて、遅くなった原因ですが、現在のコードではキーを押した一瞬だけ、moveHかVの値が変わります。つまり力が生まれます。
  • でも、そのすぐ後に【GetComponent<Rigidbody>().velocity = new Vector3(0,0,0);】で速度が0になるため、速度が消えます。
    • キーを押し続けても、これが交互にくり返されるだけなので、速度は遅いままになります。
    • このことからも、【力】というプロパティは存在しておらず、【速度】でしか動いていないことがわかります。

力で動かす

  • これをちゃんとした速さになるようにする方法は色々考えられます。
    1. キーを押している間は速度を0にしない。
    2. 単純に【力】を大きくする。
    3. 物体の質量を小さくする。
  • 1と2に関しては、すでにやっているアプローチ方法と同じです。
    • 3に関しては初めて出てきた要素で、オブジェクト自体の質量を軽くすることで、同じ力でも早く進むように変えてみましょう。
      • ※質量とは重さという意味ですが、物理学的に言うと【動かしにくさ】の数値です。
  • Rigidbodyコンポーネントの中のmass(マス:質量)の数値を0.003ぐらいにしてください。
    • 出来たら試してみましょう。
  • 下の感じになればOKです。

力で動かす

  • ちゃんとした速さになりましたね。
  • ちなみに、【座標】や【速度】で動かす場合は質量はまったく影響しません。【力】で動かす場合のみ変化します。
  • また、別のオブジェクトとぶつかった時の動作にも影響します。
  • 終わったら、今作った【力】の動かし方も、コメントアウトしてください。
  • さて、これで【座標】【速度】【力】で動かす方法を、すべて学びました。
  • こうなってくると、「結局どれがええねん?」になりますが、ぶっちゃけ【力】で動かすのは調整が難しいので、なにがなんでも現実世界の動きと近づけたい、という場合以外は使わなくて良いと思います。
    • 特に今回のようなプレイヤーの動きに使うとめんどくさいだけです。
  • 例えば、ピンボールゲームやビリヤードゲームなど、オブジェクト通しがぶつかって、勝手に跳ね返って動くような動きをしたい場合は、力で動かすのが良いと思います。
    • (現実世界にあるゲームを作る場合は、出来る限り動きも現実世界に合わせないと違和感を感じやすい、という点でも、リアルな動きに)

力で動かす

  • 基本は【座標】か【速度】で考えて使いやすい方で良いと思います。
  • ここでは、【速度】で動かします。
    • ※速度で動かすコードだけコメントアウトを解除してください。
    • ※コメントアウトの解除は、コメントアウトの方法とは違って、以下の方法になります。
    • コメントアウト解除したい場所をマウスで囲ってから、【コントロールキー(Ctrl)+ Kキー】を同時押しした後に【コントロールキー(Ctrl)+ Uキー
  • そういえば、機体の傾きがなくなったままでした。これを復活させましょう。
  • 以前作ったコードは下の感じでしたね。

傾きを作る

  • これを速度で動かすコードに追加してみましょう。
GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f));
void FixedUpdate () {
        float moveH = Input.GetAxis ("Horizontal");
        float moveV = Input.GetAxis ("Vertical");
        Vector3 nowP = new Vector3(moveH,0,moveV);
        GetComponent<Rigidbody>().velocity = nowP * speed;
        GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, -50.0f));
}
  • これで動かしてみるとどうなるでしょう?
  • 試してみるまでもなくわかるかも知れませんが、とりあえずやってみましょう。
    • 次に続く。
  • こんな感じになりました。

傾きを作る

  • 最初から最後までずっと傾いたままですね。
  • これを直すためには、少し工夫してみます。傾きのコードを下のようにしてみます。
GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler (0.0f, 0.0f, moveH * -50.0f));
  • moveHは押していない時は0、押し続けると徐々に1に近づいていきますよね?
  • これを傾きに利用しています。実際に試してください。
  • 下の感じになればOKです。

傾きを作る

  • プレイヤーの動きは、これでかなり良い感じになったのではないでしょうか?
  • 残りは【画面端に出ていってしまう】問題ですね。
  • これもサクッと直してしまいましょう。
    • 次に続く。
  • さて、【画面端に出ていってしまう】問題の解決法を、単純に考えると【右端でなければ進める】とか【左端でなければ進める】という感じにする方法が思いつきますが、ちょっと冗長で、めんどくさいです。
  • Unityでは【特定の範囲】に制限するメソッドがありますので、それを使いましょう。

移動範囲を制限する

  • オブジェクトの動きを制限するメソッドに【Mathf.Clamp】というものがあります。
  • これは以下のように使います。
  • ちょっと横に長過ぎるので、見やすくしたのが下です。※横に長くなるコードは、引数ごとに改行するのが普通です。
GetComponent<Rigidbody>().position = new Vector3( Mathf.Clamp(GetComponent<Rigidbody>().position.x, -7, 7), 0.0f, Mathf.Clamp(GetComponent<Rigidbody>().position.z, -4, 14));
GetComponent<Rigidbody>().position = new Vector3( 
    Mathf.Clamp(GetComponent<Rigidbody>().position.x, -7, 7), 
    0.0f, 
    Mathf.Clamp(GetComponent<Rigidbody>().position.z, -4, 14)
);
  • 詳しくは次のページ。

移動範囲を制限する

GetComponent<Rigidbody>().position = new Vector3( 
    Mathf.Clamp(GetComponent<Rigidbody>().position.x, -7, 7), 
    0.0f, 
    Mathf.Clamp(GetComponent<Rigidbody>().position.z, -4, 14)
);
  • Vector3の引数にMathf.Clampが2回使われていますね。
  • Vector3の引数は(x, y, z)の並びになっているので、xとzの箇所でMathf.Clampを使っている、つまり制限をしているという事ですね。
  • Mathf.Clampの引数は、以下のようになっています。
    • 第1引数:対象の名前(今回はリジッドボディのxやy)
    • 第2引数:最小値
    • 第3引数:最大値
      • となっています。
  • では、このコードを【FixedUpdate()】の中の末尾に追加して見ましょう。
    • 次のページに続く。

移動範囲を制限する

  • こんな風に動けばOKです。
  • これでプレイヤーの動きはひとまず完成です。

お疲れ様です

  • ここまでで【プレイヤー】の動きが完成しました。
  • 次回は弾を発射出来るようにしていきます。
  • スペースシューター③へ続く】

スペースシューター2

By kinocode

スペースシューター2

  • 1,502