2020.02.09 (最終更新日:2020/02/09)

【Unity】3Dでタッチした位置にプレイヤーを移動させる簡単な方法

unity

各記事のサムネイル
吹き出しの画像

しろう

こんにちは、しろうです!今はセブ島で記事を書いてます!笑

韓国の空港で1夜を過ごす必要があったのでUnityの勉強をしていたのですが『3Dでタッチした位置にプレイヤーを移動させる方法』を今回は勉強したので復習がてら分かりやすく解説していきます。

汎用性は高いと思うので、是非この機会に覚えてしまいましょう!

↓完成イメージ(画質荒くてすいませんm(_ _)m)

ちなみに今回の記事ではUdemyで購入した教材『RPG Core Combat Creator: Learn Intermediate Unity C# Coding』を参考にさせて頂きましたm(_ _)m

タッチした位置に人を移動させる:下準備

まずは下準備として、3Dオブジェクトとマップを用意してください。

この時の3Dオブジェクトは好きなものでOKです。

今回は【Create】>【3D Object】>【Capsule】よりカプセルの形をした3Dオブジェクトで実行します。

そして、3Dオブジェクト(以下、Player)にインスペクターから【Add Component】>【Navigation】>【Nav Mesh Agent】を追加してください。

 

マップは【Terrain】を使って適当にサクッと作っちゃってください。笑

 

Navigationで移動範囲を調整する

【Window】>【AI】>【Navigation】の順にクリックしてください。

すると、下記画像のようにマップの一部が青色で表示されるはずです。

この青色に表示されている部分がPlayerが移動できるエリアになります。

微調整したい場合は【Navigation】>【Bake】で『Agent Radius』や『Max Slope』の値を変更して、右下の【Bake】をクリックすれば適用される範囲が変化します。

他にも【Voxel Size】とかの値をいじればメッシュの大きさを変化させられますので、色々試してみてください。

参考までに(*・ω・)ノUnity公式リファレンス:Advanced NavMesh Bake Settings

タッチした位置にプレイヤーを移動させるスクリプトを書く

タッチした位置にプレイヤーを移動させるスクリプトは下記の通りになりますので、こちらをプレイヤーにアタッチしてください。

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

public class Mover : MonoBehaviour
{

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {

            MoveToCursor();
        }

    }

    private void MoveToCursor()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        bool hasHit = Physics.Raycast(ray, out hit);
        if (hasHit)
        {
            GetComponent<NavMeshAgent>().destination = hit.point;
        }
    }

}

 

Camera.main.ScreenPointToRay(Input.mousePosition) は引数に与えた位置にカメラからray(光線)を発射して、コライダーを持ったオブジェクトに当たると、オブジェクトの情報を返します。

今回は引数にInput.mousePosition を与えることで、Ray型の変数reyにマウスがタッチした位置のpositionを代入しています。

少し意味不明に感じるかもしれませんが、要するにカメラから見えない線が発射されて、その線と当たったコライダーのポジションを取得しているわけです。

 

Physics.Raycast(ray, out hit); は引数に(origin , direction , maxDistance , layerMask , queryTriggerInteraction)を指定します。

origin ワールド座標でのレイの開始地点
direction レイの方向
maxDistance レイが衝突を検知する最大距離
layerMask レイヤーマスクはレイキャストするときに選択的に衝突を無視するために使用します。
queryTriggerInteraction トリガーに設定されているものも検索対象にするか

 

少し難しく見えるかもしれませんが、必要な情報は「origin(光線の開始位置)」と「direction(光線の角度)」だけであり、今回この2つについては変数rayに既に格納されているため、rayで2つ分の役割を果たしてくれています。

そしてout hit という引数を与えることで当たったオブジェクトをhitに格納するっぽいです。

この「out」という修飾子がかなり謎で、調べてもわかりやすく解説されているサイトが全くありません。当たったオブジェクトの情報をhitに格納するために必要なんだなー程度に考えておくといいと思います。

一応参考サイトを貼っておきます:out (ジェネリック修飾子) (C# リファレンス)

 

そして、それをbool型のhasHitに代入して、if文の条件としてhasHitを指定。

これによって Physics.Raycast(ray, out hit); がtrue、つまりカメラから出た光線がコライダーを持つオブジェクトに当たった時、GetComponent<NavMeshAgent>().destination = hit.point; が実行される関数MoveToCursor() の完成。

あとはこれをUpdateメソッド内に記述すれば、マウスでタッチした位置にキャラクターが動くようになります。

カメラをプレイヤーに追従するようにする

あとはカメラもプレイヤーを追従するようにいじっておきましょう。

やり方は簡単で、空のオブジェクト(仮に「Follow Camera」とします。)を用意して子要素に「Main Camera」を加える。

そして、「Follow Camera」 のTransfom.Positionに常にプレイヤーの位置を代入すれば、子要素である「Main Camera」も必然的に追従するようになるという感じです。

スクリプトは下記の通りです。

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

public class FollowCamera : MonoBehaviour
{
    [SerializeField] Transform player;
    
    
    void Update()
    {
        transform.position = player.position;
    }
}

 

あとはこれを「Follow Camera」にアタッチします。

そして[SerializeField]によって生成されたインスペクターのPlayer項目にPlayerをドラッグ&ドロップすることを忘れないように注意してください。(下記画像では「taget」となっている部分です。)

これにて完成です。

以外と簡単に実装できちゃいましたね☺️

Rayらへんがちょっと謎ですが、まぁこの辺りは都度調べて理解を深めていくようにしましょう(*´ω`*)ノ

それではまたっっっ

参考教材:『RPG Core Combat Creator: Learn Intermediate Unity C# Coding