武器を持ったVRoidをAnimancerでアニメーションさせる(Unity)

久しぶりに投稿します。

ちょっと前にVRoidというサービスを知り、3Dモデルが非常に身近になったのを感じてました。その際は男性用モデルがほぼなく、作りたいゲームに合わないと判断、一度スルーしたのですが、

最近になって再度調べていると、男性モデルをアップしてくれている方がいらっしゃるじゃないですか!

これはゲームに使用できる可能性が出てきた…ということで、簡単に3Dモデルを使用するシーンを作ることにしました。

 

【想定するシーン】

・VRoidより出力したキャラクターで3Dモデルを用意

・キャラクターはUnityで扱う。キャラクターのアニメーション(モーション)はUnityのAssetで賄う

・Animancerというアセットを使い、スクリプトからアニメーション切替制御を行う。

・キャラクターは画面奥に向かって永遠に走り続けることができる

・走っている最中に持っている剣を振ることができる(マウスクリックで振る)

 

 

モデルの用意

使用モデル

 

スナック☆アツコ資材館さん、素敵なモデルの提供感謝!

Boothより.vroidファイルをダウンロードしたらVRoidStudioより.vrmファイルを出力し、unityのシーンにドラッグアンドドロップするだけで3Dモデルが読み込まれる…という手軽さ!

少し前では考えられないくらい楽になったのを実感しますね!

 

モーションの用意

UnityはAssetStoreでいろんなモーションが販売されています。

今回は何かのバンドルセールで買ったときに入っていた以下モーションを使用します。

Elevate your workflow with the Melee Warrior Animations asse…

いつもの通りインポートし、フォルダ内のファイルを使用します。なお、アニメーションは、△矢印を展開して見る必要があるものもある様。

 

Animancerの使用例

基本的な使い方(導入)はそこそこ別のサイトで書かれています。

 

Unityのよしなしごとや趣味のブログ

こんばんわ 今日も内定は受けたものの、宵越しの金が無いため東奔西走しております(どなたかお仕事ください…) 急なお金が必…

Qiita

1. 前提 Unity アセット真夏のアドベントカレンダー 2019 のために書かれた記事です。 この記事は、U…

 

注記1

外部リンクにあるソースのうち、AnimancerComponent.CrossFade(Action)はエラーにより使用できなかった。

Animancerの公式を見たところ、CrossFadeは関数ではなく、Playの引数としてパラメータを与えて実装する様。

 

 

 

3Dモデルに武器を持たせる

以下の手順で行う。対して難しくはない。

①空のゲームオブジェクトを作り、その子に武器のPrefabを設置する。

②キャラクターの手の部分の子として①で作ったゲームオブジェクトを位置調整の上配置する。

③適当に再生したりして微妙な位置調整する

 

背景画像を永遠に生成する

はじめはTerrain等の地形生成を検討したが、最終的にモバイル向けを考えるとどうしても描画処理関係が気になる。

そこで、軽量Prefabを使いまわしてリソース節約する方法とした。

建物としては以下を使用した。これもいつかのアセットバンドルセールでいつの間にか入手していたもの。

Elevate your workflow with the POLYGON Western - Low Poly 3D…

 

方法は以下の通り

①複数個建物を並べたものを1つのPrefabとする。

②①をPrefabの幅に合わせて等間隔でいくつか配置する。

③②をキャラクターの移動量に合わせて画面奥から手前に動かす

④建物を手前に動かすのをキャラクターの移動モーション中のみに制限する

要は、キャラクターは動かさずその場で足踏みし、建物を手前に動かすことで前方に移動しているように見せる、

まあ古くからある方法ですね。

以下を空のゲームオブジェクトにaddComponentし再生すれば画面奥に移動する感じが表現できました。


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

public class BattleSceneController : MonoBehaviour
{
    [SerializeField]
    private List<Transform> LoadSideTransformlist;
    [SerializeField]
    private int LoadSideBuildingWidth;
    [SerializeField]
    private int LoadSideSpacing;


    [SerializeField]
    private AnimancerComponent _Animancer;

    [SerializeField]
    private ClipTransition _Idle;

    [SerializeField]
    private ClipTransition _Action;

    private bool idling;

    private void OnEnable()
    {
        _Action.Events.OnEnd = (() =>
        {
            _Animancer.Play(_Idle);
            idling = true;
        });
        _Animancer.Play(_Idle);
        idling = true;
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            _Animancer.Play(_Action);

            idling = false;
        }
        else if(idling)
        {
            var deltaTime = Time.deltaTime;
            var distance = 10.0f * deltaTime; // 10m/s×delta_t
            LoadSideTransformlist.ForEach(x =>
            {
                Vector3 xyz;
                if(x.position.z < -LoadSideBuildingWidth)
                {
                    xyz = new Vector3(x.position.x, x.position.y, x.position.z - distance
                        + LoadSideTransformlist.Count * (LoadSideBuildingWidth + LoadSideSpacing));
                }
                else
                {
                    xyz = new Vector3(x.position.x, x.position.y, x.position.z - distance);
                }
                x.position = xyz;
            } );
        }
    }
}

 

以上

久しぶりにUnity触った気がする。