Developer

【Unity実践】#8 プレイヤーをドラッグ(スワイプ)で移動させる【ランゲーム】
2021.10.08
Lv2

【Unity実践】#8 プレイヤーをドラッグ(スワイプ)で移動させる【ランゲーム】

今回の内容

前回はプレイヤーにカメラを追従させました。
今回はちょっと難関で、マウスのドラッグやスマートフォンのスワイプ操作でプレイヤーを左右に移動させます。

※初めての方はこちらから
【第1回記事】導入とサンプルの紹介

実装方針の整理

スワイプによる移動の実装方針は以下となります。

1.現在のマウス位置と少し前(1フレーム前)のマウス座標を取得
2.それらの差分から、ワールド座標における実際の移動距離を計算
3.道幅を超える場合は補正した上で、実際にプレイヤーを移動させる

手順1では、Input.mousePosition という命令でマウス位置を取得しますが、
注意点としてその際に取得できる位置は、スクリーン座標上の位置となっています。
そのため手順2でスクリーン座標からワールド座標への変換という過程が必要となっています。

スクリーン座標とは、画面の左下を基準とし、画面解像度に対応した座標系のことです。
下図はスクリーン座標のイメージ図です。

計算の方法は以下を採用します。

マウス位置の差分 / 画面の横幅 * 道幅

マウスの差分は Input.mousePosition から計算
画面の横幅は Screen.Width で取得
道幅は6 を定数化したものを使用

これらを踏まえて、次のセクションで実際のコードを見ていきます。

PlayerScriptに追加実装

先ほどの方針を元に PlayerScript を変更したのが以下です。

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

public class PlayerScript : MonoBehaviour
{
    Animator animator;

    bool isRunning;

    const float LOAD_WIDTH = 6f;
    const float MOVE_MAX = 2.5f;
    Vector3 previousPos, currentPos;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        // スワイプによる移動処理
        if (Input.GetMouseButtonDown(0))
        {
            previousPos = Input.mousePosition;
        }
        if (Input.GetMouseButton(0))
        {
            // スワイプによる移動距離を取得
            currentPos = Input.mousePosition;
            float diffDistance = (currentPos.x - previousPos.x) / Screen.width * LOAD_WIDTH;

            // 次のローカルx座標を設定 ※道の外にでないように
            float newX = Mathf.Clamp(transform.localPosition.x + diffDistance, -MOVE_MAX, MOVE_MAX);
            transform.localPosition = new Vector3(newX, 0, 0);

            // タップ位置を更新
            previousPos = currentPos;
        }

        isRunning = true;
        animator.SetBool("IsRunning", isRunning);
    }
}

この連載の中では初めてガッツリコードを書いているので難しいかもしれません。
以下で順に解説します。

11~13行目

    const float LOAD_WIDTH = 6f;
    const float MOVE_MAX = 2.5f;
    Vector3 previousPos, currentPos;

LOAD_WIDTH は道幅、MOVE_MAX は道の中心からのプレイヤーの最大移動距離を定数化したものです。
previousPos が1フレーム前のマウス位置、currentPos が現在のマウス位置を設定するプロパティです。

23~26行目

        if (Input.GetMouseButtonDown(0))
        {
            previousPos = Input.mousePosition;
        }

Input.GetMouseButtonDown(0) はマウスの左ボタンがクリックされた瞬間や、
スマートフォンの場合は画面がタップされた瞬間であることを判定をしています。
ドラッグやスワイプ開始時の処理がこのブロックとなっています。
その時点でのマウス位置を previousPos に格納しています。

27~49行目

        if (Input.GetMouseButton(0))
        {
            // スワイプによる移動距離を取得
            currentPos = Input.mousePosition;
            float diffDistance = (currentPos.x - previousPos.x) / Screen.width * LOAD_WIDTH;
 
            // 次のローカルx座標を設定 ※道の外にでないように
            float newX = Mathf.Clamp(transform.localPosition.x + diffDistance, -MOVE_MAX, MOVE_MAX);
            transform.localPosition = new Vector3(newX, 0, 0);
 
            // タップ位置を更新
            previousPos = currentPos;
        }

Input.GetMouseButton(0) はマウスの左ボタンがクリックされている間や、
スマートフォンの場合は画面がタップされている間であることを判定しています。
ドラッグやスワイプ中の処理がこのブロックとなっています。

30、31行目では最新のマウス位置を取得し、それを元にプレイヤーの移動距離を計算しています。
これが方針の所で記載した、スクリーン座標からワールド座標への変換です。
(今回の場合は、解像度基準から道幅基準に置き変えていると言えます。)

34行目ではプレイヤーの移動後のx座標を計算させています。
その際、プレイヤーの移動後のx座標が、境界を越えていないかを判定しています。
Mathf.Clamp関数 と、境界には定数で用意した MOVE_MAX を使用しました。

35行目で実際にプレイヤーの座標を変更し、38行目で次の更新に備えて previousPos を更新しています。

(公式リファレンス)
Input.GetMouseButtonDown
Input.GetMouseButton

感度の調整ができるようにする

ついでに、ドラッグやスワイプ操作による移動の感度を調整しやすくしておきましょう。

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

public class PlayerScript : MonoBehaviour
{
    Animator animator;

    bool isRunning;

    public float sensitivity = 1f;
    const float LOAD_WIDTH = 6f;
    const float MOVE_MAX = 2.5f;
    Vector3 previousPos, currentPos;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        // スワイプによる移動処理
        if (Input.GetMouseButtonDown(0))
        {
            previousPos = Input.mousePosition;
        }
        if (Input.GetMouseButton(0))
        {
            // スワイプによる移動距離を取得
            currentPos = Input.mousePosition;
            float diffDistance = (currentPos.x - previousPos.x) / Screen.width * LOAD_WIDTH;
            diffDistance *= sensitivity;

            // 次のローカルx座標を設定 ※道の外にでないように
            float newX = Mathf.Clamp(transform.localPosition.x + diffDistance, -MOVE_MAX, MOVE_MAX);
            transform.localPosition = new Vector3(newX, 0, 0);

            // タップ位置を更新
            previousPos = currentPos;
        }

        isRunning = true;
        animator.SetBool("IsRunning", isRunning);
    }
}

}

11行目に感度を設定するためのプロパティ sensitivity を追加しました。
33行目で移動距離にこれを掛けることで、感度調整が可能となっています。

連載では 1倍としていますが、お好みで上げたり下げたりしてみて下さい。
なお、public で定義したのは、FPSなどでよくあるゲーム内から感度を調節する機能を意識した形です。
そういった機能を用意しないのであれば、定数で実装するのもアリだと思います。

動作確認

ここまでで動作確認してみましょう。
マウスドラッグに合わせてプレイヤーが左右に移動していれば成功です。

おわりに

今回はかなり難しかったと思いますが、走る部分の実装がかなり完成に近づきました。
次回はタップ中のみ走るような調整を行いたいと思います!

 

 
関連リンク ➡ 「初心者のための」Unityゲーム制作 目次

© Unity Technologies Japan/UCL