1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PLATEAU SDK for Unityを使って久留米を歩いてみようハンズオン(2) - プレイヤーを作ってTPS風に動かそう

Posted at

はじめに

これの続きです。前回でマップを作りました(PLATEAUのデータを取り込んだだけ)。
今回はプレイヤーキャラクターを作って三人称視点で動かせるようにしていきます。

イメージはこんな感じ。

pubg.png
(「スマホ版『PUBG MOBILE』が本日5月16日よりサービス開始! 事前登録数は130万を突破」ファミ通 2018.05.16 より抜粋)

一応、本記事だけでもTPSゲームの第1歩目くらいには機能するかなと思います。

Playerキャラクターを動かす仕組みの概要

このようにプレイヤーのすぐ後ろにカメラを配置してあげることで三人称の視点を再現します。
UnityではHierarchyビューで設定した親子関係にあるObjectは連動して動いてくれるので、この状態でプレイヤーを移動させることで三人称での移動が実現できます。
image.png
image.png

Playerキャラクターの作成

Hierarchyビュー上で右クリックをすると次のようなウィンドウが表示されます。ここから「3D Objects > Capsule」を選択してください。
image.png

すると画面上に真っ白のカプセルが出現します。Cupsuleの名前は「Player」に変更しておきましょう。
これをSceneまたはInspectorビュー上で移動させてマップ上の初期位置にしたい場所まで持ってきましょう。(どこにあるか分からない場合は、Hierarchyビューで「Player」をダブルクリックするとその場所に飛ぶことができます。)
今回はJR久留米駅の前まで持ってきてみました。
image.png

更にこの状態でCupsuleを出したときと同様にHierarchyビューで右クリックから今度は「Camera」を選択します。出現したカメラの名前は「PlayerCamera」にしましょう。このカメラがプレイヤーの眼としての役割を果たしてくれます。
PlayerとPlayerCameraを親子の関係にしましょう。

image.png

この状態では一人称視点になっています。三人称にするには、カメラがプレイヤーをプレイヤーの少し後ろから観測して上げる必要があります。
image.png

カメラのInspectorの数値をいじってあげましょう。
PositionのY軸を少し上げてプレイヤーの上に、Z軸を少し下げてプレイヤーの後ろに下がらせます。
また、RotationのX軸を少しだけ回してあげてプレイヤーを見下ろす形にします。
image.png

これだけでもなんだかそれっぽい見た目になっています。

Playerキャラクターの動きの作成

続いて、プレイヤーを動かすプログラムを書いていきます。

プログラムを書く準備

まずはUnityのProjectビュー上で右クリックをして「Create > Folder」からフォルダを作成します。Assets配下に「Scripts」フォルダを作成しましょう。続けて、いま作成したScriptsフォルダ内で再度右クリックをし「Create > C# Script」からC#のファイルを作ります。名前は「Player」にしましょう。
image.png

こんな感じになっていたらOKです。このままPlayerをダブルクリックしてプログラムを書きに行きましょう。
image.png

別のタブでVisual Studio Codeか、Visual Studioのいずれかが開くと思います。
image.png

コード全体を次のように書き換えます。
フィールド変数のtransformではプレイヤーの位置や回転などの情報を保持します。Startではこれを初期化しています。

UpdateではMoveByKeyでキーボード入力による移動を、RotateByMouseでマウス入力による回転を呼び出しています。まだ中身が空っぽなので何も動きません。この2つのメソッドを充実させていきましょう。


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

public class Player : MonoBehaviour
{
    [SerializeField] float moveSpeed = 0.0f;
    [SerializeField] float rotateSpeed = 0.0f;
    Transform transform = null;

    // Start is called before the first frame update
    void Start()
    {
        this.transform = gameObject.transform;
    }

    // Update is called once per frame
    void Update()
    {
        this.MoveByKey();
        this.RotateHeadByMouse();
    }

    private void MoveByKey()
    {

    }

    private void RotateHeadByMouse()
    {

    }
}

このプログラムをPlayerに付与してあげましょう。
Hierarchyから「Player」を選択し、Inspectorで「Add Component」をクリックします。
image.png

現れたウィンドウで作成したプログラム「Player」を探してクリックします。
image.png

すると、このようなInspectorビューにこのような表示が追加されます。
プログラムで[SerializeField]をつけたフィールド変数はUnityEditorから数値をいじることができます。この数値をいじって移動速度moveSpeedや回転速度rotateSpeedを調整してあげましょう。

image.png

縦横の移動

まずは移動を実現します。MoveByKeyの中身を次のように書き換えてください。
Input.GetAxisは引数のstringで指定した入力値を教えてくれます。

    private void MoveByKey()
    {
        // 横方向の入力値を保持(A, ← or D, →)
        float horizontal = Input.GetAxis("Horizontal") * this.moveSpeed;
        // 縦方向のの入力値を保持(W, ↑ or S, ↓)
        float vertical = Input.GetAxis("Vertical") * this.moveSpeed;

        Vector3 currentPosition = this.transform.position;
        this.transform.position = new Vector3(currentPosition.x + horizontal, currentPosition.y, currentPosition.z + vertical);
    }

動作確認をしてみましょう。▷マークのプレイボタンを押すとゲームを開始できます。
※PlayerのMoveSpeedを0より大きくしていないと移動距離が掛け算で0になってしまい動きません。
image.png

「WASD」または「矢印キー」での移動操作ができるようになりました。
move.gif

回転の実装(首振り)

このままでは方向転換はできませんので、Y軸方向に回転できるようにします。

次のようにします。移動と同様にInput.Axisでマウスの横方向の移動を検知し、その分だけ回転させます。

    private void RotateHeadByMouse()
    {
        // マウスの横方向の移動を保持
        float rotate = Input.GetAxis("Mouse X") * this.rotateSpeed;
        Vector3 rotation = new Vector3(0, rotate, 0);
        this.transform.Rotate(rotation);
    }

マウスの移動に合わせて回転してくれるようになりました。

rotate.gif

しかし、挙動をよく見ると回転と移動方向が連動していないことに気づきます。

移動と回転の連動

それもそのはず。移動は方眼紙の縦横のように決まった線の上を移動しており、回転はそれとは関係なく回っているだけです。これを解消するにはどうするべきか。移動のなかで回転の情報も参照して移動方向を決定すれば良いのです。

MoveByKeyメソッドを次のように書き換えます。
元のコードと変わったのは位置の更新部分。
もともとは、現在地に対してX軸方向は横の入力値horizontal、Z軸方向は縦の入力値を加算する単純なコードでした。
新しいコードでは、現在地に対して横向きの方向rightに横の入力値を掛けた数horizontal、前向きの方向forwardに縦の入力値verticalを掛けた数を足しています。
横向き、前向きの方向は単純にプレイヤーの位置を原点とした角度の計算で導出されています。

    private void MoveByKey()
    {
        // 横方向の入力値を保持(A, ← or D, →)
        float horizontal = Input.GetAxis("Horizontal") * this.moveSpeed;
        // 縦方向のの入力値を保持(W, ↑ or S, ↓)
        float vertical = Input.GetAxis("Vertical") * this.moveSpeed;

        Vector3 currentPosition = this.transform.position;
        // this.transform.position = new Vector3(currentPosition.x + horizontal, currentPosition.y, currentPosition.z + vertical);
        this.transform.position = currentPosition + this.transform.forward * vertical + this.transform.right * horizontal;
    }

これでマウスで首を振って向いている方向に合わせて進むことができるようになりました。

rotate_move.gif

まとめ

ゲームとして最低限の操作ができるようになったかなと思います。

ただし、このままでは縦横無尽に建物を突き抜けていたり、街の見た目も簡素だったり遊ぶにはまだまだ課題がたくさんあります。

これらを次回から一つずつ解消していきます。

おまけ 上下にも首を振る方法

実は首を上下に振れないままなので振れるようにしたコードも展開しておきます。
左右の回転と違って、首を上下に回すにはカメラのオブジェクトの管理も必要になって説明がやや面倒なのでシンプルにするため本編では省いていました。気になる人は参考にしてみてください。

Player.cs(追加版)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    [SerializeField] GameObject cameraObject = null;
    [SerializeField] float moveSpeed = 0.0f;
    [SerializeField] float rotateSpeed = 0.0f;
    [SerializeField] float upSpeed = 0.0f;
    Transform playerTransform = null;
    Transform cameraTransform = null;



    // Start is called before the first frame update
    void Start()
    {
        this.playerTransform = gameObject.transform;
        this.cameraTransform = this.cameraObject.transform;
    }

    // Update is called once per frame
    void Update()
    {
        this.MoveByKey();
        this.RotateHeadByMouse();
    }

    private void MoveByKey()
    {
        // 横方向の入力値を保持(A, ← or D, →)
        float horizontal = Input.GetAxis("Horizontal") * this.moveSpeed;
        // 縦方向のの入力値を保持(W, ↑ or S, ↓)
        float vertical = Input.GetAxis("Vertical") * this.moveSpeed;

        Vector3 currentPosition = this.playerTransform.position;
        this.playerTransform.position = currentPosition + this.playerTransform.forward * vertical + this.playerTransform.right * horizontal;
    }

    private void RotateHeadByMouse()
    {
        // マウスの横方向の移動を保持
        float rotate = Input.GetAxis("Mouse X") * this.rotateSpeed;
        Vector3 rotation = new Vector3(0, rotate, 0);
        this.playerTransform.Rotate(rotation);

        // マウスの縦方向の移動を保持 -> カメラを回転
        float up = Input.GetAxis("Mouse Y") * this.upSpeed;
        rotation = new Vector3(-up, 0, 0);
        this.cameraTransform.Rotate(rotation);

    }
}

連載記事一覧

第1回「環境構築, 導入」
第2回 「プレイヤーを作ってTPS風に動かそう」
第3回 建物に衝突するようにするか、見た目を整えるようにするかどっちかやります

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?