見出し画像

【Unity】CinemachineのTargetGroupのTargetを動的に増やす方法

ご!ピクジンです。

今回はUnityのCinemachineに関するちょっとした実験です。

Cinemachineはカメラがプレイヤーをいい感じに追従してくれる機能です。
いろんな機能がほぼノーコードでできる。すごい!

使い方は簡単で、CinemachineVirtualCameraのFollowに追いかけさせたいオブジェクト(主にプレイヤー)を指定してあげるだけ。
今回は白い四角に設定。

スクリーンショット 2021-03-04 20.14.35

画像6

so good
たったこれだけでカメラが追従してくれます。


場合によっては他のオブジェクト(例えば敵)も常時カメラに入れたいこともあるでしょう。
そんな時はTargetGroupを使います。

下の例では白い四角と黒い丸と緑の丸をTargetに設定。

スクリーンショット 2021-03-04 20.20.33

スクリーンショット 2021-03-04 20.22.45

画像7

ビューティフォー
白い四角と2つの丸が離れるほどカメラが引いていくのが確認できます。


さて、ここで疑問なのが「Targetはインスペクター上でしか設定できないのか?」ってことです。

どうにかできないかと思い、とりあえずはソースコードを確認してみましょう。
するとこんなものがありました。

//CinemachineTargetGroup.cs

    /// <summary>Add a member to the group</summary>
       /// <param name="t">The member to add</param>
       /// <param name="weight">The new member's weight</param>
       /// <param name="radius">The new member's radius</param>
       public void AddMember(Transform t, float weight, float radius)
       {
           int index = 0;
           if (m_Targets == null)
               m_Targets = new Target[1];
           else
           {
               index = m_Targets.Length;
               var oldTargets = m_Targets;
               m_Targets = new Target[index + 1];
               Array.Copy(oldTargets, m_Targets, index);
           }
           m_Targets[index].target = t;
           m_Targets[index].weight = weight;
           m_Targets[index].radius = radius;
       }

       /// <summary>Remove a member from the group</summary>
       /// <param name="t">The member to remove</param>
       public void RemoveMember(Transform t)
       {
           int index = FindMember(t);
           if (index >= 0)
           {
               var oldTargets = m_Targets;
               m_Targets = new Target[m_Targets.Length - 1];
               if (index > 0)
                   Array.Copy(oldTargets, m_Targets, index);
               if (index < oldTargets.Length - 1)
                   Array.Copy(oldTargets, index + 1, m_Targets, index, oldTargets.Length - index - 1);
           }
       }

ターゲットを加えたり、逆に取り除くメソッドのようです。
こういうものがあるんだったら使ってしまいましょう。
というわけでこんなものを用意しました。

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

namespace Cinemachine
{
   public class target_switch : MonoBehaviour
   {
       CinemachineTargetGroup cinemachineTargetGroup;

       [SerializeField]
       private Transform[] circle = new Transform[4];

       // Start is called before the first frame update
       void Start()
       {
           cinemachineTargetGroup = GetComponent<CinemachineTargetGroup>();
       }

       public void switchOn(int i)
       {
           cinemachineTargetGroup.AddMember(circle[i], 1, 0);
       }

       public void switchOff(int i)
       {
           foreach (var item in cinemachineTargetGroup.m_Targets)
           {
               if (item.target == circle[i])
               {
                   cinemachineTargetGroup.RemoveMember(circle[i]);
                   return;
               }
           }
       }
   }
}

このスクリプトをTargetGroupを持つオブジェクトに追加し、Transformの配列にターゲットにしたいオブジェクトを指定してあげます。

スクリーンショット 2021-03-04 20.58.55

下記のSwitchらでターゲットにするか否かを切り替えます。
(Onにした時にswitchOn(int i)、OFFにした時にswitchOff(int i)を呼び出します)

スクリーンショット 2021-03-04 21.13.40

そして結果が以下になります。(なぜかUIが見えなくなってます)

画像8


以上です。
ゲームで使うなら、特定エリアに入ったりオブジェクト間の距離によって切り替えてあげるといいかもしれませんね。

またこんど。

いいなと思ったら応援しよう!