Unityで二人組のアニメーションをランダム遷移させるスクリプトメモ

アニメーション 二人組 スクリプト Unity
※記事内に広告が含まれています。

バーチャル3Dクリエイター神部まゆみです(*^-^*)

この記事はUnityで二人組のアニメーションをランダム遷移させるスクリプトを書いたので、それについてのメモです。

以前一人用のやつは作ったけど、今回は二人版ね。

動作確認した最新バージョンは Unity 6000.0.32 です。

●PRスペース●
■PR■

現在人気商品が最大90%以上オフで買えるAmazonプライム感謝祭先行セールをやってるみたいです(2025/10/10 23:59まで )。

Amazonプライム感謝祭 先行セール開催中 最大90%以上オフ

燃えにくく安全性の高いエレコム ナトリウムイオンモバイルバッテリーがかなり安くなっているので私も買いました。

エレコム ナトリウムイオン モバイルバッテリー

品薄だからか配送まで一ヶ月くらいかかるみたいですが、そろそろモバイルバッテリーが消耗している人におススメです。

エレコム モバイルバッテリー 9000mAh 45W 【世界初】ナトリウムイオン電池 USB PD対応

〇まゆみマート|BOOTH

BOOTHでVRoidテクスチャやVRChat向けオブジェクトなどを販売しています。いいねしてくれると励みになります(*^-^*)

こんな感じで動く

エロいアニメーションの差分を作りまくってランダムに動かしたら良い感じになるんじゃないかと思い作りましたが(笑)、良い感じに遷移させられました。

まぁエロいのに使うくらいかな、用途としては。

一応スクリプトを残しておきます。

二人組のアニメーションをランダム遷移させるスクリプト PairedRandomAnimationSwitcher.cs

ChatGPT氏に書いてもらいました。

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

public class PairedRandomAnimationSwitcher : MonoBehaviour
{
    [System.Serializable]
    public class AnimationPair
    {
        public string animationNameA; // キャラA用
        public string animationNameB; // キャラB用
        public int loopCount = 1;     // 同期ループ回数
    }

    public Animator animatorA; // 一人目のAnimator
    public Animator animatorB; // 二人目のAnimator

    public List<AnimationPair> animationPairs = new List<AnimationPair>();

    public float transitionDelay = 0.5f;
    public float transitionTime = 0.3f;

    private int currentLoop = 0;
    private AnimationPair currentPair;
    private float speedMultiplier = 1.0f;

    void Start()
    {
        if (animatorA == null || animatorB == null)
            Debug.LogError("Animator A または B が設定されていません");

        StartCoroutine(PlayRandomAnimationPairs());
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1)) speedMultiplier = 0.5f;
        if (Input.GetKeyDown(KeyCode.Alpha2)) speedMultiplier = 1.0f;
        if (Input.GetKeyDown(KeyCode.Alpha3)) speedMultiplier = 1.5f;

        animatorA.speed = speedMultiplier;
        animatorB.speed = speedMultiplier;
    }

    IEnumerator PlayRandomAnimationPairs()
    {
        while (true)
        {
            currentPair = animationPairs[Random.Range(0, animationPairs.Count)];
            currentLoop = 0;

            while (currentLoop < currentPair.loopCount)
            {
                animatorA.CrossFade(currentPair.animationNameA, transitionTime);
                animatorB.CrossFade(currentPair.animationNameB, transitionTime);

                yield return new WaitForSeconds(GetAnimationLength(animatorA)); // 片方の長さで同期
                currentLoop++;
            }

            yield return new WaitForSeconds(transitionDelay);
        }
    }

    private float GetAnimationLength(Animator animator)
    {
        return animator.GetCurrentAnimatorStateInfo(0).length / speedMultiplier;
    }
}

使い方など

使い方を書いておきます。

事前に同じフレーム数のアニメーションを二人一組で作っておく

VeryAnimationやUmotio Proなどのアセットを使うと複数のモデルのアニメーションを同期させて編集できるので便利です。

↓は単体のアニメーションプレビューだけど、VeryAnimationやUmotion Proなら一緒に動かしてプレビューしながら編集できます。

二人のトランスフォーム座標を合わせる

二人組のアニメーションを作る時点で位置を合わせてると思うけど一応。

アニメーション 二人組 スクリプト
アニメーション 二人組 スクリプト

アニメーションウィンドウでプレビューする場合、0,0,0じゃないと位置がズレるっぽいです。

まぁ再生時には関係ないみたいだけども。

適当なオブジェクトにアタッチしてアニメーターコントローラーとアニメーションなどを指定

空のオブジェクトを作ってスクリプトをアタッチしました。

2人のモデルのアニメーターを指定し、アニメーションのペアを手動で入れる。何回ループするかや遷移間隔なども指定できます。

アニメーション 二人組 スクリプト

アニメーターに動かしたいアニメーションを読み込んでおく

読み込んでおかないと正常に動きません。

アニメーション 二人組 スクリプト

「時間をループ」などアニメーションクリップの設定 ※重要

これをしないと途中でアニメーションが終わってポーズだけになってしまった。

アニメーション 二人組 スクリプト

ポーズにベイクをチェック、基準を元 はVeryAnimationのデフォルト設定だからこれにしてるけど、二人のモデルの設定が違うと位置がズレるので設定は同じにしておいたほうが良いと思います。

ルートモーションを適用 にもチェック

特に両者の設定が違うとズレるので、一応二人ともチェックしておいた方が良いと思う。

アニメーション 二人組 スクリプト

これで動く

位置がズレたりアニメーションが別々になってしまう場合は、設定を見直したほうが良いかもしれない。

追記:同じアニメーションを指定するとズレるっぽい…

↓だと3パターンのアニメーションを指定してるけど、同じアニメーションが二回続くとズレるっぽい。

アニメーション 二人組 スクリプト

二人とも同じアニメーションだと問題ないのだけど、どちらかだけが前回と同じアニメーションだと、アニメーション遷移の微妙な遅延でズレるっぽい。

アニメーションを複製しておけば別アニメーション扱いになるので大丈夫だった。

追記:キー入力でアニメーションカテゴリを切り替えてランダム遷移させるスクリプトも書いた

最初はAカテゴリに指定したアニメーションをランダム遷移、2キーを押したらBカテゴリに指定したアニメーション…みたいに切り替えられるようにした。

キーは4カテゴリまで対応しています。

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

public class PairedRandomAnimationSwitcher2 : MonoBehaviour
{
    [System.Serializable]
    public class AnimationPair
    {
        public string animationNameA; // キャラA用
        public string animationNameB; // キャラB用
        public int loopCount = 1;     // 同期ループ回数
    }

    [System.Serializable]
    public class AnimationCategory
    {
        public string categoryName;
        public List<AnimationPair> animationPairs = new List<AnimationPair>();
    }

    public Animator animatorA; // 一人目のAnimator
    public Animator animatorB; // 二人目のAnimator

    public List<AnimationCategory> categories = new List<AnimationCategory>();

    public float transitionDelay = 0.5f;
    public float transitionTime = 0.3f;

    [Header("速度プリセット")]
    public float speedPreset1 = 0.5f;
    public float speedPreset2 = 1.0f;
    public float speedPreset3 = 1.5f;

    private float speedMultiplier;
    private int currentLoop = 0;
    private AnimationPair currentPair;
    private int currentCategoryIndex = 0;
    private Coroutine animationCoroutine;

    void Start()
    {
        if (animatorA == null || animatorB == null)
        {
            Debug.LogError("Animator A または B が設定されていません");
            return;
        }

        if (categories.Count == 0)
        {
            Debug.LogError("カテゴリが設定されていません");
            return;
        }

        speedMultiplier = speedPreset2;
        animationCoroutine = StartCoroutine(PlayRandomAnimationFromCategory());
    }

    void Update()
    {
        // カテゴリ切り替え
        if (Input.GetKeyDown(KeyCode.Alpha1)) ChangeCategory(0);
        if (Input.GetKeyDown(KeyCode.Alpha2) && categories.Count > 1) ChangeCategory(1);
        if (Input.GetKeyDown(KeyCode.Alpha3) && categories.Count > 2) ChangeCategory(2);
        if (Input.GetKeyDown(KeyCode.Alpha4) && categories.Count > 3) ChangeCategory(3);

        // 速度切り替え
        if (Input.GetKeyDown(KeyCode.Alpha7)) speedMultiplier = speedPreset1;
        if (Input.GetKeyDown(KeyCode.Alpha8)) speedMultiplier = speedPreset2;
        if (Input.GetKeyDown(KeyCode.Alpha9)) speedMultiplier = speedPreset3;

        animatorA.speed = speedMultiplier;
        animatorB.speed = speedMultiplier;
    }

    void ChangeCategory(int newIndex)
    {
        if (newIndex < 0 || newIndex >= categories.Count) return;

        currentCategoryIndex = newIndex;

        // 安全にすべてのコルーチン停止
        StopAllCoroutines();

        // 即ランダムなアニメを再生して切り替え感を出す
        var category = categories[currentCategoryIndex];
        if (category.animationPairs.Count > 0)
        {
            currentPair = category.animationPairs[Random.Range(0, category.animationPairs.Count)];
            currentLoop = 0;
            animatorA.CrossFade(currentPair.animationNameA, transitionTime);
            animatorB.CrossFade(currentPair.animationNameB, transitionTime);
        }

        // 新しいカテゴリで再生コルーチン再スタート
        animationCoroutine = StartCoroutine(PlayRandomAnimationFromCategory());
    }

    IEnumerator PlayRandomAnimationFromCategory()
    {
        while (true)
        {
            var category = categories[currentCategoryIndex];

            if (category.animationPairs.Count == 0)
            {
                Debug.LogWarning($"カテゴリ {category.categoryName} にアニメーションがありません");
                yield return null;
                continue;
            }

            // 最初の再生時は ChangeCategory で既に CrossFade 済みなら飛ばしてもいい
            if (currentLoop == 0)
            {
                yield return new WaitForSeconds(GetAnimationLength(animatorA));
                currentLoop++;
            }

            while (currentLoop < currentPair.loopCount)
            {
                animatorA.CrossFade(currentPair.animationNameA, transitionTime);
                animatorB.CrossFade(currentPair.animationNameB, transitionTime);
                yield return new WaitForSeconds(GetAnimationLength(animatorA));
                currentLoop++;
            }

            yield return new WaitForSeconds(transitionDelay);

            // 次のランダムアニメへ
            currentPair = category.animationPairs[Random.Range(0, category.animationPairs.Count)];
            currentLoop = 0;
        }
    }

    private float GetAnimationLength(Animator animator)
    {
        return animator.GetCurrentAnimatorStateInfo(0).length / speedMultiplier;
    }
}

↓みたいにカテゴリ名を指定して分けられるようにしてある。

アニメーション ランダム遷移 エロ

1~4キーでカテゴリ切り替え、7~9でスピード切り替えです。

エロモーションを想定して作ったけど、最初は通常の反復モーション、次にヒートアップして…みたいな感じを想定して作ってみたw

割と良い感じに遷移させられたから、とりあえず短い差分アニメーションを作って放り込んでおけば割と自然な感じでメリハリのあるアニメーションが作れるかな?

おわりに

案外簡単にできて良かった。

まぁエロいアニメーションに使うくらいしか使い道はなさそうだけど(;^_^A

また何かあれば追記します(*^-^*)

タイトルとURLをコピーしました