Help us understand the problem. What is going on with this article?

[Unity] シンプルな2Dアクションを作る

More than 1 year has passed since last update.

アクションというかプラットフォーマーていうんですかね、足場があってジャンプするやつ。これの、可能な限り必要最小限のものを作ってみます。何かを作り始める際の取っ掛かりとしていかがでしょう。という気持ち。
なおこちらのブログの内容を踏襲しており、いわば実践編ですが、特に参照する必要はありません。今回のコードの根拠を掘り下げたいときに参考にするぐらいで。

キャラの身長を決める

作り始めにスケールを決めるのはけっこう大事なことです。ま、身長は1mにしときましょう。つまり1.0です。
ちなみに、これは自分に植え付けられた本能でもあるんですが、どんなスケールのゲームでもメインキャラを1.0にしとくと謎の罠に落ちる確率が下がります。ワールド全ての辻褄を合わせるのが大変でなければ、1.0にしましょう。

キャラをインポートする

適当なテクスチャを用意して、プレイヤーキャラにします。
テクスチャを持ってきたら、インポート設定で、テクスチャタイプを「スプライト(2DとUI)」にしましょう。

Kobito.Ls2Svj.png

サイズを1.0にする方法はカンタンで、インポートしたテクスチャの縦のドット数を「1ユニットのピクセル数」に入れれば良いです。ここの「1ユニット」というのは1.0のことですからね。

Kobito.AtfyQl.png

キャラをシーンに配置

いろんなやり方がありますが、インポートしたスプライトをシーンにドラッグ&ドロップしても良いです。
コンポーネントには

  • 2D リジッドボディ
  • 2D ボックスコライダー

を追加しましょう。

Kobito.YjWv2n.png

2D リジッドボディでは、回転しないようにConstraintを設定しておきます。

Kobito.J1KJBV.png

スクリプト記述

初期状態

Player というスクリプトを新規作成し、Player.csの記述を開始します。これはスクリプト作成直後。

Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

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

    }
}

左右移動

左右に移動するところを書きます。用意してくれたStartとUpdateはとりあえず消しちゃって、以下のように FixedUpdateを記述します。

Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour {
    // 追加
    void FixedUpdate() {
        var hori = Input.GetAxisRaw("Horizontal");
        var rb = GetComponent<Rigidbody2D>();
        var vel = rb.velocity;
        vel.x = hori * 2f;
        rb.velocity = vel;
    }
}

まあ手抜きかもしれませんけど、シンプルに記述するために左右の移動はvelocityに直接代入しちゃいます。
Input.GetAxisRawこれは状態を返すので、FixedUpdateで呼んでも大丈夫です。(ブログ参照

これだけでもう、左右には移動するんですよね。実行すると重力により落下し続けてしまうので、適当な足場を作れば動かして試すことも可能です。

ジャンプ

次はジャンプです。Update関数を記述します。

Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour {
    void FixedUpdate() {
        var hori = Input.GetAxisRaw("Horizontal");
        var rb = GetComponent<Rigidbody2D>();
        var vel = rb.velocity;
        vel.x = hori * 2f;
        rb.velocity = vel;
    }
    // 追加
    void Update() {
        if (Input.GetButtonDown("Jump")) {
            var rb = GetComponent<Rigidbody2D>();
            rb.AddForce(new Vector2(0f, 5f), ForceMode2D.Impulse);
        }
    }
}

Input.GetButtonDownは瞬間を返すので、Updateで呼ばないといけません。(ブログ参照
さらにAddForceをUpdateから呼んでしまいます。あれFixedUpdateじゃなくていいの?ForceMode2D.Impulseつまり力積なので大丈夫です。(ブログ参照

接地判定

もっともシンプルな実装はもう完了していますが、まあせめて、空中でもジャンプ可能なのを抑制しておきましょうか。
以下、コメントで // 追加 および // 変更 としてあるところです。

Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player2 : MonoBehaviour {
    [SerializeField] private LayerMask m_WhatIsGround; // 追加

    void FixedUpdate() {
        var hori = Input.GetAxisRaw("Horizontal");
        var rb = GetComponent<Rigidbody2D>();
        var vel = rb.velocity;
        vel.x = hori * 2f;
        rb.velocity = vel;
    }

    void Update() {
        var foot_pos = new Vector2(transform.position.x, transform.position.y - 0.6f); // 追加
        bool floating = (Physics2D.OverlapPoint(foot_pos, m_WhatIsGround) == null); // 追加
        if (!floating && Input.GetButtonDown("Jump")) { // 変更
            var rb = GetComponent<Rigidbody2D>();
            rb.AddForce(new Vector2(0f, 5f), ForceMode2D.Impulse);
        }
    }
}

Physics2D.OverlapPoint
で足元の位置のコリジョンを検出したら、ジャンプ可能としているわけです。身長は1mなので、足元は中心から数えて-0.6fすることで指定しています。やっぱりスケールを最初に決めておくと楽ですね。
そして、このときプレイヤー自身のコリジョンを検出してしまうのを避けるため、LayerMask メンバーを[SerializeField]して、地面のレイヤーに限定します。その上で、足場となるコリジョンをシーンに配置するときはこの地面のレイヤーに設定するようにしましょう。ここだけちょっと面倒ですけど、この先応用しようと思うと必要になるのでやっておきましょう。

完成

ScreenFlow.gif

リジッドボディを使うと斜めの足場もカンタンに作れて楽しいですね。めでたしめでたし。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away