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
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