TPSっぽく自キャラとカメラを動かす

やりたいこと

最近、アーマードコア6というゲームをしたのだがそのゲームでは、PS5のコントローラーで、

左スティックの上下左右で、キャラクターを前後左右に移動し、

右スティックの上下左右で、視点を上下左右に回転していた。

それがカッコいいのでマネしたい。

イメージ

出来たのが、こんな感じ。

左スティックを上下左右、右スティックを上下左右、してる。

前提

Unity 2021.3.31f1 VisualStudio2019 Input System 1.7.0

今回の仕様

色々やり方あると思うが、今回はこんな感じでやってみた。

ただのCubeを動かす。前後左右に動かすが、CubeはただのCubeのまま。歩くモーションしたり、左右を向いたりはしない。

  • ①左スティックを前後に倒すと、Cubeが前後(奥⇔手前)に進む。
  • ②左スティックを左右に倒すと、Cubeが左右に動く。
  • ③右スティックを前後に倒すと、Cubeを中心に、視点が上回転、下回転する。
  • ④右スティックを左右に倒すと、視点が回りつつ、Cube自身も回転する。

※結果、Cubeの背中側を、ずっと見る感じになる。

やり方

Playerを追加

まず、HIerarchyを右クリックして、[3D Object] > [Cube] を追加する。

これを、主人公(Player)にする。(アーマードコアでいうところの自機のロボット)

そいつの名前を「Player」にする。
(Cubeを選んで、Inspectorの一番上に「Player」と入力する)

カメラを配置

Hierarchyの中に、MainCameraを入れる。 これで、Cubeを動かすと、カメラが勝手についてくるようにできる。

カメラの位置を、Cubeの真後ろくらいにもってくる。

こんな感じ。

## Player移動のスクリプトを書く

Projectウインドウの中の「Assets」の中「Scripts」フォルダを作る。

Scriptsフォルダの中で右クリックして、[Create] > [C# Script] を押して、スクリプトを作成する。

そいつを「PlayerController」という名前にする。

そのスクリプトを下記のようにする。

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

public class PlayerController : MonoBehaviour
{
    Rigidbody rb;
    public float moveAmount = 4.0f;
    public float jumpAmount = 20.0f;

    // Start is called before the first frame update
    void Start()
    {
        // ぶつかってきた相手のRigidBodyを取得
        rb = gameObject.GetComponent<Rigidbody>();

        Physics.gravity *= 5;
    }

    // Update is called once per frame
    void Update()
    {
        float lx = Gamepad.current.leftStick.ReadValue().x;
        float ly = Gamepad.current.leftStick.ReadValue().y;
        float rx = Gamepad.current.rightStick.ReadValue().x;
        float ry = Gamepad.current.rightStick.ReadValue().y;

        if (Mathf.Abs(lx) > 0.001f)
        {
            transform.Translate(Vector3.right * lx * Time.deltaTime * moveAmount);
        }

        if (Mathf.Abs(ly) > 0.001f)
        {
            transform.Translate(Vector3.forward * ly * Time.deltaTime * moveAmount);
        }

        if (Mathf.Abs(rx) > 0.001f)
        {
            //transform.Translate(Vector3.right * lx * Time.deltaTime * moveAmount);
            transform.Rotate(0, rx, 0);
        }

        if (Gamepad.current.buttonEast.wasPressedThisFrame)
        {
            // 真上に、相手の質量の1000倍の力を加える
            rb.AddForce(Vector3.up * rb.mass * jumpAmount, ForceMode.Impulse);
        }
    }
}

※今回やることに、キャラクターをジャンプさせる、とは書いてなかったが、このスクリプトにはジャンプさせる部分を書いてる。(消すの面倒だった)

このスクリプトを、Playerのところにドラッグして持っていき、関連付ける。

これで、上に挙げた、やること①②③④のうちの、①②④ができた。

あとは③のカメラ移動をやる。

カメラ移動のスクリプトを書く

Scripsフォルダに、「Kaiten」という名前のスクリプトをつくる。(名前は適当)

そのスクリプトを、下記のようにする。

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

public class Kaiten : MonoBehaviour
{
    public GameObject player;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        float lx = Gamepad.current.leftStick.ReadValue().x;
        float ly = Gamepad.current.leftStick.ReadValue().y;
        float rx = Gamepad.current.rightStick.ReadValue().x;
        float ry = Gamepad.current.rightStick.ReadValue().y;

        // X方向に一定量移動していれば横回転
        if (Mathf.Abs(rx) > 0.001f)
        {
            // 回転軸はワールド座標のY軸
            //transform.RotateAround(player.transform.position, Vector3.up, rx);
        }

        // Y方向に一定量移動していれば縦回転
        if (Mathf.Abs(ry) > 0.001f)
        {
            // 回転軸はカメラ自身のX軸
            transform.RotateAround(player.transform.position, transform.right, -ry);
        }
    }

    void OnGUI()
    {
        if (Gamepad.current == null) return;
                                                                                        // 私のWindows+私のコントローラーでは
        GUILayout.Label($"leftStick: {Gamepad.current.leftStick.ReadValue()}");         // 左アナログスティック
        GUILayout.Label($"rightStick: {Gamepad.current.rightStick.ReadValue()}");       // 右アナログスティック
        GUILayout.Label($"buttonNorth: {Gamepad.current.buttonNorth.isPressed}");       // Y(□)ボタン
        GUILayout.Label($"buttonSouth: {Gamepad.current.buttonSouth.isPressed}");       // A(〇)ボタン
        GUILayout.Label($"buttonEast: {Gamepad.current.buttonEast.isPressed}");         // B(×)ボタン
        GUILayout.Label($"buttonWest: {Gamepad.current.buttonWest.isPressed}");         // X(△)ボタン
        GUILayout.Label($"leftShoulder: {Gamepad.current.leftShoulder.ReadValue()}");   // Lボタン
        GUILayout.Label($"leftTrigger: {Gamepad.current.leftTrigger.ReadValue()}");     // ZLボタン
        GUILayout.Label($"rightShoulder: {Gamepad.current.rightShoulder.ReadValue()}"); // Rボタン
        GUILayout.Label($"rightTrigger: {Gamepad.current.rightTrigger.ReadValue()}");   // ZRボタン
    }
}

このスクリプトで実質やっているのは、カメラの縦回転だけ。

※横回転は、Playerのほうで、Player自身を回転させることで、カメラ回転風味にしてる。

また、OnGUI()のなかに書いたコードは、コントローラー入力を見えるようにするためのデバッグ用コードなので、動きには関係ない。

ここまでで、移動とカメラの回転ができた。

できあがり

これで、とりあえずやりたいことはできた。

何の役にも立たない動きをするだけだが、何となく大満足。

参考

ほぼこちらを真似させていただいた。ありがとうございます。

https://tech.pjin.jp/blog/2022/09/26/unity-move-camera