Setting weights in TargetGroup

I’m running into some confusion and I am hoping someone can help me. I am using a TargetGroup camera to track a group of objects. I add the objects to the TargetGroup at the start of the level. That works fine. When an object is flagged to be destroyed, I remove it from the TargetGroup. This is fine except that it causes a jitter in the camera. I would much prefer to lerp that object’s weight to zero and then remove it from the group. The problem is that I can’t figure out how to go about this lerping. Any ideas?

Thanks in advance for the help!

1 Like

Full disclosure: I’m the Product Manager, not tech support nor the engineer (most folks are still away for the holidays)…so please take my answer with a grain of salt!

I threw together an example of how you can solve this. I can’t say for sure that it’s the best answer. In particular, in a real situation, I wouldn’t want to put this control directly on the target. IMO it would be better to have the target dispatch an event and have a third party script take care of the decay and removal.

using Cinemachine;
using UnityEngine;

public class RemoveAfterDecay : MonoBehaviour
{
    public CinemachineTargetGroup group; // assign the group top which this target belongs
    public float decayRate = .95f; // decay rate for the weight (I found something around .995 worked well in my test)
    public float decayThreshold = .1f; // threshold for when decay should conclude and allow the item to be deleted

    private bool isDying = false;
  
    void Start()
    {
        Invoke("Dying", 2f); // This was just for my example...call Dying() when you want to flag something to be destroyed
    }

    void Dying()
    {
        isDying = true;
    }

    void Update()
    {
        if (isDying)
        {
            for (int a = 0; a < group.m_Targets.Length; a++)
            {
                var t = group.m_Targets[a];
                if (t.target == transform)
                {
                    // I'm pretty sure you need to create a new CinemachineTargetGroup.Target rather than update values.
                    // At least, I couldn't find any other way to do it.
                    // target and radius are copied from the old struct
                    // weight is multiplied by the decay rate
                    var newTarget = new CinemachineTargetGroup.Target{ target = t.target,
                        radius = t.radius,
                        weight = t.weight * decayRate };

                    // Remove if we're done...
                    if (newTarget.weight < decayThreshold)
                    {
                        Remove();
                    }
                    // ...if we're not done, apply the updated target
                    else
                    {
                        group.m_Targets[a] = newTarget;
                    }
                }
            }
        }
    }

    void Remove()
    {
        group.RemoveMember(transform);
        GameObject.Destroy(gameObject);
    }
}
2 Likes

Thanks for the help!

3 Likes

For anyone running into this issue, you can do it with Coroutines as well…

[SerializeField]
CinemachineTargetGroup _targetGroup;

[SerializeField]
float _targetEase = 0.15f;

public void AddTarget (Transform target)
{
    if (_targetGroup != null)
    {
        if (_targetGroup.FindMember(target) == -1)
        {
            _targetGroup.AddMember(target, 0, 1);
            StartCoroutine(easeInMember(target));
        }
    }
}

IEnumerator easeInMember(Transform target)
{
    int index = _targetGroup.FindMember(target);
    CinemachineTargetGroup.Target t = _targetGroup.m_Targets[index];
    while (t.weight < 0.66f)
    {
        t.weight = Mathf.MoveTowards(t.weight, 0.66f, _targetEase * Time.smoothDeltaTime);
        index = _targetGroup.FindMember(target);
        if (index >= 0)
        {
            _targetGroup.m_Targets[index] = t;
        }
        yield return new WaitForSeconds(0.01f);
    }
    t.weight = 0.66f;
}

public void RemoveTarget (Transform target)
{
    if (_targetGroup != null)
    {
        if (_targetGroup.FindMember(target) != -1)
        {
            StartCoroutine(easeOutMember(target));
        }
    }
}

IEnumerator easeOutMember(Transform target)
{
    int index = _targetGroup.FindMember(target);
    CinemachineTargetGroup.Target t = _targetGroup.m_Targets[index];
    while (t.weight > 0f)
    {
        t.weight = Mathf.MoveTowards(t.weight, 0, _targetEase * Time.smoothDeltaTime);
        index = _targetGroup.FindMember(target);
        if (index >= 0)
        {
            _targetGroup.m_Targets[index] = t;
        }
        yield return new WaitForSeconds(0.01f);
    }
    t.weight = 0;
    _targetGroup.RemoveMember(target);
    target.gameObject.SetActive(false);
}
2 Likes