人工知性を作りたい

私が日々、挑戦したことや学んだことなどを紹介していく雑記ブログです。 (新しいAI技術HTM, 専門の音声信号処理, 趣味のアニメ等も書いてます。)

ユニティちゃんとカメラの向きをPS4コントローラ(dualshock4)で操作する【Unity】

 

本記事のテーマ

「ユニティちゃんをPS4コントローラ(dualshock4)で操作する」

下記DEMO動画でユニティちゃんを動かしている処理を紹介する。

左スティック:キャラクターを操作

右スティック:カメラの向きを操作

Demo


www.youtube.com

 

実装動画

本記事の実装を録画した動画です。


www.youtube.com

 

実装環境

  • Ubuntu20.04
  • UnityHub2.4.2
  • Unity 2019.4.21f1

 

ソースコード

Githubで管理

・controll-with-dualshock4ブランチ

ブランチの切り替えは下記画像の赤枠をクリックして変更できる。

f:id:hiro-htm877:20210502170814p:plain

github.com

 

ユニティちゃんのImport

ユニティちゃんのモデルをダウンロードする。

下記サイトの右上のDATADOWNLOADをクリックする。

ページ下のユニティちゃんライセンスに同意しましたにチェックをしデータをダウンロードをクリック。

UNITY-CHAN! OFFICIAL WEBSITE

すると、下記のページに移動する。

f:id:hiro-htm877:20210228132559p:plain

今回はSDユニティちゃん3Dモデルデータを使用する。

f:id:hiro-htm877:20210228132604p:plain

 ダウンロードフォルダに下記のような名前のパッケージがあると思う。

これらがUnityで使用するpackageになる。

 

・ユニティちゃん

SD_UnityChan-1.unitypackage

 

UnityへPackageをインストールする

[Assets]->[Import Package]->[Custom Package...]

f:id:hiro-htm877:20210228133716p:plain

DownloadsファルダからSD_UnityChan-1.unitypackageをインストールする。

するとおそらく、下記のような赤色のメッセージが出てくる。

f:id:hiro-htm877:20210228134233p:plain

Assets\unity-chan!\Unity-chan! Model\Scripts\AutoBlink.cs(8,23): error CS0234: The type or namespace name 'Policy' does not exist in the namespace 'System.Security' (are you missing an assembly reference?)

下記のサイトを参考に解決できる。

【Unity】Unity-Chan!(ユニティちゃん)でCS0234エラーが発生したときの調査結果と解決方法 - Qiita

することは、

「Edit」→「Project Settings」→「Player」の
Other Settings、ConfigurationsのApi Compatibillity Levelが.NET Standard 2.0になっているので、NET 4.xに変更する

f:id:hiro-htm877:20210228134727p:plain

ユニティちゃんを配置する

Unity画面下部のProject画面からユニティちゃんのモデルを探す。

[Assets]->[UnityChan]->[SD_unitychan]->[Prefabs]->[SD_unitychan_humanoid]

SD_unitychan_humanoidをUnity画面左のHierarchy画面にドラッグ&ドロップする。

f:id:hiro-htm877:20210228140146p:plain

 

 そして、ユニティちゃんが落ちないようにHierarchy画面で右クリック→3D Object→Planeを選択して生成する。

f:id:hiro-htm877:20210502151335p:plain

 

PS4コントローラ(dualshock4)から入力できるようにする

Unityでの入力設定はEdit→ProjectSettings→ImputMangerで行います。

新しい入力を追加する場合はSize欄の値を増やします。

今回、左スティックと右スティックを使います。

左スティックはHorizontal, Verticalという名前で存在していたので右スティックのRightHorizontal, RightVerticalの二つ分を追加するためにSizeの値は18→20に増やしました。

パラメータは下記の画像のように設定してください。

・RightHorizontal, RightVertical

f:id:hiro-htm877:20210502171007p:plain

・Horizontal, Vertical

f:id:hiro-htm877:20210502175747p:plain

ユニティちゃんを動かすスクリプト

PlayerController.cs 

 

 

 

 

▶クリックでソースコードを展開
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 2.0f;
    public float rotationSpeed = 360.0f;
 
    GameObject camera;  // 外部のオブジェクトを参照する
 
    Animator animator;
 
    // Start is called before the first frame update
    void Start()
    {
        camera = GameObject.FindGameObjectWithTag("MainCamera");
        animator = this.GetComponentInChildren();
    }
 
    // Update is called once per frame
    void Update()
    {
        // Debug.Log(Input.GetAxis("D-pad X"));
        // Debug.Log(Input.GetAxis("D-pad Y"));
        // ゲームパッドの左スティックのベクトルを取得する
        Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
         
        // 他のオブジェクトのスクリプトを読み込む(スクリプトはクラス扱い)
        CameraController cameraScript = camera.GetComponent();
 
        // カメラのY軸角度から回転行列を生成する
        Quaternion rot = Quaternion.Euler(0, cameraScript.cameraRotation.y * Mathf.Rad2Deg + 90, 0);
 
        // 逆行列を生成する
        Matrix4x4 m = Matrix4x4.TRS(Vector3.zero, rot, Vector3.one);
        Matrix4x4 inv = m.inverse;
 
        // 回転行列をかけたベクトルに変換する
        direction = inv.MultiplyVector(direction);
 
        if (direction.magnitude > 0.001f)
        {
            // Slerpは球面線形補間、Vector3.Angleは二点間の角度(degree)を返す
            Vector3 forward = Vector3.Slerp(this.transform.forward, direction, rotationSpeed * Time.deltaTime / Vector3.Angle(this.transform.forward, direction));
 
            // ベクトル方向へ向かせる
            transform.LookAt(this.transform.position + forward);
        }
 
        // 座標移動させる
        transform.position += direction * moveSpeed * Time.deltaTime;
 
        // アニメーターコントローラへ値を渡す
        animator.SetFloat("Blend", direction.magnitude);

        // if (Input.GetKey("joystick button 0")) {
        //     animator.SetBool("is_jumping", true);
        // } else {
        //     animator.SetBool("is_jumping", false);
        // }

        if(Input.GetKey("space")){
            Debug.Log("Pushed Tab");

        }
    }
}

 

 

 

 

 

カメラをキャラクタに追従させるスクリプト

CameraController.cs

 

 

 

 

▶クリックでソースコードを展開
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class CameraController : MonoBehaviour
{
    // 外部オブジェクトの参照
    GameObject player;
 
    public Vector3 cameraRotation = new Vector3();
    Vector3 currentCamRotation = new Vector3();
 
    public float dist = 4.0f;
    Vector3 currentLookAtPos = new Vector3();
 
    // Start is called before the first frame update
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("unitychan");
    }
 
    // Update is called once per frame
    void Update()
    {
        // ゲームパッド右スティックからの値を加算する
        cameraRotation += new Vector3(-Input.GetAxis("RightVertical"), -Input.GetAxis("RightHorizontal"), 0) * 2.0f * Time.deltaTime;
 
        // X軸回転の制限
        // Default: Mathf.Clamp(cameraRotation.x, 15 * Mathf.Deg2Rad, 60 * Mathf.Deg2Rad);
        cameraRotation.x = Mathf.Clamp(cameraRotation.x, 0 * Mathf.Deg2Rad, 60 * Mathf.Deg2Rad);
 
        // 遅延用の角度との差分をとる
        Vector3 diff = cameraRotation - currentCamRotation;
        currentCamRotation += WrapAngle(diff) * 0.2f;
 
        // 角度からベクトルを計算する
        Vector3 craneVec = new Vector3
        (
            Mathf.Cos(currentCamRotation.x) * Mathf.Cos(currentCamRotation.y),
            Mathf.Sin(currentCamRotation.x),
            Mathf.Cos(currentCamRotation.x) * Mathf.Sin(currentCamRotation.y)
        );
 
        // 注視点の座標
        Vector3 lookAtPos = player.transform.position + new Vector3(0, 1, 0);
 
        currentLookAtPos += (lookAtPos - currentLookAtPos) * 0.2f;
 
        // カメラの座標を更新する
        this.transform.position = currentLookAtPos + craneVec * dist;
 
        // プレイヤーの座標にカメラを向ける(これは最後にする)
        this.transform.LookAt(currentLookAtPos);
    }
 
    // 角度を0~360°に収める関数
    Vector3 WrapAngle(Vector3 vector)
    {
        vector.x %= Mathf.PI * 2;
        vector.y %= Mathf.PI * 2;
        vector.z %= Mathf.PI * 2;
 
        return vector;
    }
}

 

 

 

 

 

 

 

 

 

キャラクターにAnimatorを追加

今回はBrendTreeを使用します。

Projectsの下にAnimatorsディレクトリを作成し、その中で右クリック→Create→Animator Controllerを新規作成する。

名前はUnitychanAnimatorとしました。

(ディレクトリは作成しなくても問題ありません)

f:id:hiro-htm877:20210502161447p:plain

オレンジのBrendTreeをダブルクリックします。

次にBrendTreeを選択してInspector内のMotionにStanding@loopとRunning@loopを追加します。

(genericとhumaroidの2つがありますがhumaroidの方を選択します)

f:id:hiro-htm877:20210502161718p:plain

 

 スクリプトとAnimatorを反映する

【スクリプト】

・PleyerController.cs

SD_unitychan_humanoidのInspector画面へドラッグ・アンド・ドロップする。

・CameraController.cs

MainCamera.csのInspector画面へドラッグ・アンド・ドロップする。

 

【Animator】

・UnitychanAnimator

SD_unitychan_humanoidのInspector画面→AnimatorのControllerに使用されているAnimatorを作成したものに変更する。

歯車をクリックしてUnitchanAnimatorを選択する。

 

Objectにtagをつける

CameraControllerのStartクラスの中に以下の処理があります。

player = GameObject.FindGameObjectWithTag("unitychan");

この処理はカメラがユニティちゃんに追従するためにユニティちゃんのオブジェクトを取得しています。

取得の仕方はObject名で取得する「GameObject.Find()」などいくつかありますが今回はTagからObjectを取得します。

そのためにまずはSD_unitychan_humanoidにTagを付けないといけません。

画像にある、TagがUntagged担っていると思いますのでここをクリックして"Add Tag"を選択します。

f:id:hiro-htm877:20210503062024p:plain

すると以下のような画面に変わりますので"+"ボタンを押して、unitychanという名前で追加してください。

f:id:hiro-htm877:20210503062148p:plain

最後にもう一度SD_unitychan_humanoidのInspector画面に戻り、Tagをunitychanに変更して保存すると終了です。

f:id:hiro-htm877:20210503062356p:plain

 

 無効化する処理/パラメータ

・SD_unitychan_humanoidにデフォルトでattachされているスクリプトを無効化する。

f:id:hiro-htm877:20210502180122p:plain

 

 ・FaceUpdate.csの処理の一部をコメントアウトする

自作のAnimatorに変更すると出現するエラーに対応する処理をコメントアウトします。

	void ChangeFace (string str)
		{
			isKeepFace = true;
			current = 1;
			// anim.CrossFade (str, 0);
		}

 

 

以上で実装は修了になります。

再生ボタンを押下するとコントローラに反応してユニティちゃんが動き出すと思います。 

もし、動かない場合はコメント欄にて報告して頂けますと助かります。

 

参考記事

Unity: キャラクターとカメラ | とあるデザイナーのテクニカルノート

 

関連記事 

www.hiro877.com