コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity 入門】【チュートリアル】2D アクションゲームを作る 2. 床や壁との当たり判定

目次

前回のチュートリアル

スクリプトの更新

スクリプトファイルを開いて下記のコードを貼り付けて保存します

Controller2D.cs

using UnityEngine;
using System.Collections;

[RequireComponent (typeof (BoxCollider2D))]
public class Controller2D : MonoBehaviour {

    public LayerMask collisionMask;

    const float skinWidth = .015f;
    public int horizontalRayCount = 4;
    public int verticalRayCount = 4;

    float horizontalRaySpacing;
    float verticalRaySpacing;

    BoxCollider2D collider;
    RaycastOrigins raycastOrigins;

    void Start() {
        collider = GetComponent<BoxCollider2D> ();
        CalculateRaySpacing ();
    }

    public void Move(Vector3 velocity) {
        UpdateRaycastOrigins ();
        if (velocity.x != 0) {
            HorizontalCollisions (ref velocity);
        }
        if (velocity.y != 0) {
            VerticalCollisions (ref velocity);
        }

        transform.Translate (velocity);
    }

    void HorizontalCollisions(ref Vector3 velocity) {
        float directionX = Mathf.Sign (velocity.x);
        float rayLength = Mathf.Abs (velocity.x) + skinWidth;

        for (int i = 0; i < horizontalRayCount; i ++) {
            Vector2 rayOrigin = (directionX == -1)?raycastOrigins.bottomLeft:raycastOrigins.bottomRight;
            rayOrigin += Vector2.up * (horizontalRaySpacing * i);
            RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, rayLength, collisionMask);

            Debug.DrawRay(rayOrigin, Vector2.right * directionX * rayLength,Color.red);

            if (hit) {
                velocity.x = (hit.distance - skinWidth) * directionX;
                rayLength = hit.distance;
            }
        }
    }

    void VerticalCollisions(ref Vector3 velocity) {
        float directionY = Mathf.Sign (velocity.y);
        float rayLength = Mathf.Abs (velocity.y) + skinWidth;

        for (int i = 0; i < verticalRayCount; i ++) {
            Vector2 rayOrigin = (directionY == -1)?raycastOrigins.bottomLeft:raycastOrigins.topLeft;
            rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
            RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);

            Debug.DrawRay(rayOrigin, Vector2.up * directionY * rayLength,Color.red);

            if (hit) {
                velocity.y = (hit.distance - skinWidth) * directionY;
                rayLength = hit.distance;
            }
        }
    }

    void UpdateRaycastOrigins() {
        Bounds bounds = collider.bounds;
        bounds.Expand (skinWidth * -2);

        raycastOrigins.bottomLeft = new Vector2 (bounds.min.x, bounds.min.y);
        raycastOrigins.bottomRight = new Vector2 (bounds.max.x, bounds.min.y);
        raycastOrigins.topLeft = new Vector2 (bounds.min.x, bounds.max.y);
        raycastOrigins.topRight = new Vector2 (bounds.max.x, bounds.max.y);
    }

    void CalculateRaySpacing() {
        Bounds bounds = collider.bounds;
        bounds.Expand (skinWidth * -2);

        horizontalRayCount = Mathf.Clamp (horizontalRayCount, 2, int.MaxValue);
        verticalRayCount = Mathf.Clamp (verticalRayCount, 2, int.MaxValue);

        horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);
        verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);
    }

    struct RaycastOrigins {
        public Vector2 topLeft, topRight;
        public Vector2 bottomLeft, bottomRight;
    }

}

Player.cs

using UnityEngine;
using System.Collections;

[RequireComponent (typeof (Controller2D))]
public class Player : MonoBehaviour {

    float moveSpeed = 6;
    float gravity = -20;
    Vector3 velocity;

    Controller2D controller;

    void Start() {
        controller = GetComponent<Controller2D> ();
    }

    void Update() {

        Vector2 input = new Vector2 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical"));

        velocity.x = input.x * moveSpeed;
        velocity.y += gravity * Time.deltaTime;
        controller.Move (velocity * Time.deltaTime);
    }
}

床の作成

f:id:baba_s:20180122124517p:plain

Unity メニューの「GameObject>3D Object>Quad」を選択します

f:id:baba_s:20180122124529p:plain

作成した「Quad」を選択して「Mesh Collider」を右クリックして
「Remove Component」を選択します

f:id:baba_s:20180122124541p:plain

「Add Component」ボタンを押して入力欄に「BoxCollider2D」と入力して
表示された「Box Collider 2D」を選択します

f:id:baba_s:20180122124557p:plain

「Quad」を選択した状態でパラメータを下記のように設定します

  • 「Position」の入力欄に左から順に「0」「-2」「0」と入力
  • 「Scale」の入力欄に左から順に「10」「0.35」「1」と入力

f:id:baba_s:20180122124618p:plain

「Materials」フォルダを右クリックして「Create>Material」を選択します

f:id:baba_s:20180122124654p:plain

作成したマテリアルを選択して「Shader」のプルダウンメニューから
「Unlit>Color」を選択します

f:id:baba_s:20180122124702p:plain

作成したマテリアルを「Quad」オブジェクトにドラッグします

f:id:baba_s:20180122124713p:plain

これで床の配置が完了しました

プレイヤーの色の変更

f:id:baba_s:20180122124720p:plain

「Player」マテリアルを選択して赤枠で囲まれたアイコンをクリックします

f:id:baba_s:20180122124731p:plain

表示された Color ウィンドウの入力欄に上から順に
「255」「0」「0」「255」と入力して閉じます

f:id:baba_s:20180122124743p:plain

これで、プレイヤーの色が赤色になりました

床のレイヤーの設定

f:id:baba_s:20180122124758p:plain

「Quad」オブジェクトを選択した状態で
「Layer」のプルダウンメニューから「Add Layer...」を選択します

f:id:baba_s:20180122124807p:plain

「Layers」を開いて「User Layer 9」に「Obstacle」と入力します

f:id:baba_s:20180122124819p:plain

もう一度「Quad」オブジェクトを選択して
「Layer」のプルダウンメニューから「9. Obstacle」を選択します

f:id:baba_s:20180122130836p:plain

「Player」オブジェクトを選択して
「Collision Mask」のプルダウンメニューから「Obstacle」を選択します

f:id:baba_s:20180122131024g:plain

これで Unity を再生すると、左右の矢印キーで
プレイヤーが床の上を動くようになったことが確認できます

壁の配置

f:id:baba_s:20180122131250p:plain

「Quad」を選択して Ctrl + D を押します

f:id:baba_s:20180122131316p:plain

複製した「Quad (1)」を選択した状態でパラメータを下記のように設定します

  • 「Position」の入力欄に左から順に「-2.5」「-1.5」「0」と入力
  • 「Scale」の入力欄に左から順に「1」「1」「1」と入力

f:id:baba_s:20180122131239g:plain

これで Unity を再生すると、プレイヤーが壁にぶつかった時に
停止することが確認できます

次のチュートリアル