Unity学習サイト

ホーム / 主人公の移動


前回までフィールドを作成して鳥さんがフィールドに降り立つところまで できたかと思います。今回は鳥さんを動かせるようにしていきたいと思います。 少し間長くなりますが頑張っていきましょう。

今回の講座では下のミニゲームの内容まで作ることができます。

この講座での最終完成形

簡単なスクリプトの説明

まずは、スクリプトに関することを簡単に説明していきます。

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

public class Tori : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}
  

1~3行に記述されている文はUnity上にある、このシステム達を使用しますよ。という宣言になります。 スイッチをオンにするイメージです。
5行目はクラスの宣言になります。クラス名とUnityで作ったスクリプト名は 同じでなければなりません。エラーを吐きます。
7行目と13行目に記述されている文は頭に//が付いているのでコメントになります。 コードの補足などに使います。
8行目 void Start() はこのスクリプトが付いているゲームオブジェクトが生成された際 一番初めに一度だけ呼び出される関数になります。void 〇〇 ()という形は関数と呼ばれるものです。
14行目 void Update() はこのスクリプトが付いているゲームオブジェクトが存在している間 繰り返され続ける関数になります。

主人公の移動

お待たせしました、それではスクリプトの中身を書き換えて鳥さんを動かしていきましょう! まず、鳥さんを動かすために鳥さん自体の情報を取得しなければなりません。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tori : MonoBehaviour
{
    Rigidbody2D rigid2D;

    void Start()
    {
        this.rigid2D = GetComponent<Rigidbody2D>();
    }
}
  

今は使わない関数とか不要なものを消して表示してあります。
基本的な流れとしてはクラスの中で(クラスの中かつ関数内の外であればどこでもOK)箱を作って箱に 中身を入れて中身の数値などを変更する。という感じです。
6行目に追加したものは、鳥さんについているRigidbody2D(物理法則)コンポーネントを格納する rigid2Dという名前の箱を作りました。rigid2Dという名前は適当に付けました、 数学でいう変数xみたいなものです。流れの一番最初の箱を作る部分です。
10行目で箱にRigidbody2Dコンポーネントを入れる工程をしています。
これで鳥さんのRigidbody2D(物理法則)の情報を取得しました。

主人公の移動2

難しくてごちゃごちゃしてくるので細かく章分けしていきます。 初めに鳥さんの情報を取得しました!つぎは必要なパーツを揃えます!

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

public class Tori : MonoBehaviour
{
    Rigidbody2D rigid2D;
    float maxWalkSpeed = 2.0f;
    float walkForce = 30.0f;

    void Start()
    {
        this.rigid2D = GetComponent<Rigidbody2D>();
    }
}
    

8行目と9行目を追加しました。二つともフロートという形の箱にそれぞれ名前がついています。 8行目は移動の速さの上限の箱、9行目は移動の初速になります。

主人公の移動3

必要なパーツが揃ったらいよいよ動かすためのスクリプトを記述していきましょう。

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

  public class Tori : MonoBehaviour
  {
      Rigidbody2D rigid2D;
      float maxWalkSpeed = 2.0f;
      float walkForce = 30.0f;

      void Start()
      {
          this.rigid2D = GetComponent<Rigidbody2D>();
      }

      void Update()
    {
        //左右移動
        int key = 0;
        if (Input.GetKey(KeyCode.RightArrow))
            key = 1;
        if (Input.GetKey(KeyCode.LeftArrow))
            key = -1;
        //プレイやーの速度
        float speedx = Mathf.Abs(this.rigid2D.velocity.x);
        //スピードで制限
        if (speedx < this.maxWalkSpeed)
        {
            this.rigid2D.AddForce(transform.right * key * this.walkForce);
        }
      }
  }
      

16行目以降にUpdate関数を追加しました。なにやらたくさん追加されましたね、、。 頭痛がしてきそうですが一緒に頑張りましょう。 左右移動のところは、intという形にkeyという名前をつけて箱を作っています。先ほどの章で行った パーツの部分になります。if文によりint keyに0,1,-1と3つの値のどれかが常に入っている状態になって います。0は止まっている。1は右方向にー1は左方向に進むという具合になっています。

プレイヤーの速度の部分に関しては、フロートの形のspeedXという名前の箱が作られています。 Mathf.Absは値を負を取って絶対値で返すという役割をしています。左方向に進んでいるとき Xがマイナスになるので速度がマイナスになってしまいます、これを防ぐためにMathf.Absを使っています。 Mathf.Absのカッコの中身は鳥さんのX軸の情報です。

スピードで制御と書いてあるところは先ほどの章で書いたパーツのMaxWalkSpeedよりプレーヤーの速度 が下回っているときAddForceで力を加え続けるというコードになります。前の章で作ったパーツのwalkForce とどちらの方向に進むのかと右方向への力の向きがかっこの中に入っています。

さて、このままアタッチするとどうなるか。実はこのままだとしっかり動いてくれません 画像の軸が固定されていないので転がって行ったり飛んで行ったりすごい動きをします。 なので、画像の軸を固定してやれば変な挙動はしなくなります。 ヒエラルキーウィンドウのtoriをクリックしてインスペクターウィンドウのRigidbody2Dコンポーネント の下のほうにあるFreezeRotationのZにチェックを入れて下さい。これで変な挙動は無くなります。

それではUnityにアタッチしてどうなるか見てみましょう。

下がこのスクリプトをアタッチしたゲームです。鳥さんは左右の矢印で動きます

実際に動かして確認してみましょう

しかし、、次の問題が、、、。。

画像の反転

やっと移動できたと思ったその矢先、鳥さん進む方向を向いてくれないですね。 これに関してもスクリプトを書いてあげなければなりません。
この講座の復習だと思って手順を踏んでやっていきましょう。まずは数値の入る箱をフィールドに作りましょう。

public float defScalex;

次に箱に情報を入れましょう。void Start関数内コード を書き加えます。

this.defScalex = transform.localScale.x;

最後に取得した数値を変更します。Update関数の最下部に下記のif文を書き加えましょう。

//移動時の反転
        if (key != 0)
        {
            transform.localScale = new Vector3(-1 * key * defScalex, transform.localScale.y, 1);
        }

このコードは、keyが0ではないときにtransform.localScaleの値を変更するという文になります。
new Vector3は(x,y,z)の値を変更することができます。画像の反転にはほぼX軸の変更だけでできます。 Xの部分に-1 * key * defScalexが入っています。これは、defScalexは初めの画像のX軸が入っています。 また、Keyには入力された矢印に対応する値が入っています。
例えば、右矢印を押すとKeyに1が代入されnew Vecter3(-1*1*1,y,z)になり、Xはー1になりますので画像が反転し鳥の進行方向になる という具合です。左矢印を押すとKeyにー1が代入されXは1になりますので画像の反転は変わらず鳥は右を向いたままになるという具合です。
出来たらUnityにアタッチして動きを確認してみます。

実際に動かして確認してみましょう

うまく出来てますね、ここまでのソースコードです。

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

public class Tori : MonoBehaviour
{
    Rigidbody2D rigid2D;
    float maxWalkSpeed = 2.0f;
    float walkForce = 30.0f;
    public float defScalex;

    void Start()
    {
        this.rigid2D = GetComponent<Rigidbody2D>();
        this.defScalex = transform.localScale.x;
    }

    void Update()
    {
        //左右移動
        int key = 0;
        if (Input.GetKey(KeyCode.RightArrow))
            key = 1;
        if (Input.GetKey(KeyCode.LeftArrow))
            key = -1;
        //プレイやーの速度
        float speedx = Mathf.Abs(this.rigid2D.velocity.x);
        //スピードで制限
        if (speedx < this.maxWalkSpeed)
        {
            this.rigid2D.AddForce(transform.right * key * this.walkForce);
        }
        //移動時の反転
        if (key != 0)
        {
            transform.localScale = new Vector3(-1 * key * defScalex, transform.localScale.y, 1);
        }
    }
}

応用編

下にコードへの理解が深まるプログラムを作りました。エンターでコードが切り替わります。

float maxWalkSpeed = 2.0f;
float walkForce = 30.0f;

ここのコードのMaxWalkSpeedとWolkForceの値を変更するとどうなるかがわかります。

WebGL

鳥さんのジャンプ

鳥さんが左右移動できるようになりましたね!それでは、ジャンプもできるようにしましょう。 ジャンプも歩くのと同じように初動の力を使って動きます。歩くのと違うのはスピードの制限 がない点です。それでは、今まで通りの手順でやっていきます。

まずは、ジャンプの初動の力の入る箱をフィールドに作ります。

 float jumpForce = 5.0f;

つぎに、スペースキーが押された時上方向に先ほど作ったJumpForceを加えるというコードを Update関数内に追加します。

if (Input.GetKeyDown(KeyCode.Space))
        {
            this.rigid2D.AddForce(transform.up * this.jumpForce, ForceMode2D.Impulse);
        }

これで完成??と思いたいのですが、これだとスペースを押せばずっと飛んで行けてしまいます。 地面に接地しているときに一度だけジャンプするようにするためにはもうひと手間、、いや、さん手間ぐらい加えます。

まずは、鳥さんに当たり判定をつけます。Add Component→Physics2D→Capsule Collider 2Dでもう一つカプセルコライダーをつけます。この コライダーは当たり判定用の物になります。つけたコライダーのIs Toriggerにチェックをしてください。これで当たり判定が付きました。

次に、ヒエラルキーウィンドウのTileMapにGroundというタグを追加します。Tagと書いてある横のドロップダウンを開いて 一番下にあるAdd Tagというボタンを押してください。

下の画面が開きますので、+を押してGroundというタグを新たに制作しましょう。

そうしたら、またヒエラルキーウィンドウのTileMapを押してTagのドロップダウンを確認すると一番下から二番目のところに先ほど 追加したGurundというTagが作られていますのでそのTagを選択してください。

次に鳥のスクリプトでこのタグを取得出来つようにコードを追加します。 スクリプトを開きアップデート関数の終了の}かっこの外、フィールドに void OnTriggerEnter2D関数作ります、この関数はサークルコライダーが 衝突を検知したときに呼び出される関数になります。
if文は衝突感知したときのTagがGroundであればという文です。

void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            print("グランドに接地したよ");
        }

上記のコードをUnityにアタッチして再生するとプロジェクトウィンドウの隣に ある、コンソールウィンドウにprintで書いた「グランドに接地したよ」という 言葉がプリントされています。これで地面との衝突を感知することができました。

地面についているとき判定はできたので、飛んでいるときの判定を作っていきます。 一番上のフィールドにboolという箱を作ります。

public bool jump = false;

boolというものはチェックボックスになっていて上記のようにFalseの時はチェックが外れています。 boolの前にPublicと付いていますが、これをつけるとインスペクターウィンドウで操作ができるようになります。 また、Publicは公共のという意味があり。数値等の受け渡しもできるようになります。

if (Input.GetKeyDown(KeyCode.Space) && !jump) {
            this.rigid2D.AddForce(transform.up * this.jumpForce, ForceMode2D.Impulse);
            jump = true;
        }

先ほど書いたジャンプに関するif文に条件を追加しました。&& !jumpという条件 について&&は二つ以上の条件が満たされたときの意味があります。!jumpはjumpが trueではないとき、つまりジャンプしてないときという意味になります。
この二つが満たされたとき、jumpをtrueにするというものを追加しました。

先ほど書いた、衝突判定のところにもコードを追加します。 先ほど書いた衝突判定のコードは地面に接地したときに呼び出されるものでしたので コードが呼び出されたときはjumpをしていないつまりfalseにします。
jump = false;を追加しましょう。

void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            jump = false;
            print("グランドに接地したよ");
        }

    }

これでジャンプに関するすべての作業が終了しました。

これで今回の講座は終わりです!!お疲れ様でした!!
最後にスクリプトを貼っておきます参考にして下さい。

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

public class Tori : MonoBehaviour
{
    Rigidbody2D rigid2D;
    float maxWalkSpeed = 2.0f;
    float walkForce = 30.0f;
    float jumpForce = 5.0f;
    public float defScalex;
    public bool jump = false;

    void Start()
    {
        this.rigid2D = GetComponent();
        this.defScalex = transform.localScale.x;
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.Return))
        {
            SceneManager.LoadScene("Main");
        }
        //左右移動
        int key = 0;
        if (Input.GetKey(KeyCode.RightArrow))
            key = 1;
        if (Input.GetKey(KeyCode.LeftArrow))
            key = -1;
        //プレイやーの速度
        float speedx = Mathf.Abs(this.rigid2D.velocity.x);
        //スピードで制限
        if (speedx < this.maxWalkSpeed)
        {
            this.rigid2D.AddForce(transform.right * key * this.walkForce);
        }
        //移動時の反転
        if (key != 0)
        {
            transform.localScale = new Vector3(-1 * key * defScalex, transform.localScale.y, 1);
        }
        //ジャンプ
        if (Input.GetKeyDown(KeyCode.Space) && !jump)
        {
            this.rigid2D.AddForce(transform.up * this.jumpForce, ForceMode2D.Impulse);
            jump = true;
        }
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
        {
            jump = false;
            print("グランドに接地したよ");
        }

    }
}

次の講座へ

ホームへ