I see that cinemachine is open sourced, but there doesn’t look to be any documentation on the best way to contribute.
Is there a standard for contributing?
Also was wondering what the best way to vote / express that a feature is needed? Forum or as an issue on the GitHub repo maybe?
Great product over all!
I’m just looking to get an event fired when one camera finishes blending from another. I figured I would either vote on this for a future release or build out myself and add a pull request.
You’ll need to define the feature a little better. Blends can be nested. Do you want a notification when any blend ends? Or just when transitioning from a state of blends to no blend? And what about other manager-style vcams, like StateDrivenCamera and ClearShot? They can have their own blends of their children. Should they issue the event also? What if the brain has a single vcam active (no blend), but that vcam is itself the result of a blend (e.g. SDC or ClearShot)?
Perhaps the best solution, if you have a specific need, is to implement a simple polling script, as suggested in the other thread on this topic.
I think it would make the most sense to send an event when any blend ends. Perhaps it sends along some additional information with the event though that specifies the from camera / to Camera as well as the manager if any that invoked the blend. This way you should be able to discern where the blend is coming from.
While I know polling is an option, it’s a bit hacky in my opinion and I really think cinemachine should have this functionality built in.
I wen’t ahead and came up with one very scary zombie extension method to accomplish what I’m after. Here it is posted below for all to see. Although I myself am not convinced if what I’ve come up with is a beauty or a monstrosity. Although it does work.
CinemachineBrainExtensions.cs
public static class CinemachineBrainExtensions
{
private static event Action<ICinemachineCamera, ICinemachineCamera> OnCameraBlendCompleteEvent;
private static CinemachineBrain cinemachineBrain;
private static ICinemachineCamera fromCamera;
public static void SubscribeOnCameraBlendCompleteEvent(this CinemachineBrain cinemachineBrain,
Action<ICinemachineCamera,ICinemachineCamera> eventHandler)
{
CinemachineBrainExtensions.cinemachineBrain = cinemachineBrain;
cinemachineBrain.m_CameraActivatedEvent.AddListener(OnCameraActivateEvent);
OnCameraBlendCompleteEvent += eventHandler;
}
public static void UnsubscribeOnCameraBlendCompleteEvent(this CinemachineBrain cinemachineBrain,
Action<ICinemachineCamera, ICinemachineCamera> eventHandler)
{
OnCameraBlendCompleteEvent -= eventHandler;
}
private static void OnCameraActivateEvent(ICinemachineCamera toCamera, ICinemachineCamera fromCamera)
{
if (fromCamera == null)
{
return;
}
var oldFromCamera = CinemachineBrainExtensions.fromCamera;
CinemachineBrainExtensions.fromCamera = fromCamera;
if (oldFromCamera != null)
{
return;
}
var blendCompleteTimer = new GameObject("Cinemachine Blend Complete Timer");
blendCompleteTimer.AddComponent<CinemachineBlendCompleteTimer>().CheckBlendingFinished();
}
private class CinemachineBlendCompleteTimer : MonoBehaviour
{
public void CheckBlendingFinished()
{
InvokeRepeating(nameof(InternalCheckBlendingFinished),0,0.1f);
}
private void InternalCheckBlendingFinished()
{
if (!cinemachineBrain.IsBlending)
{
Destroy(gameObject);
OnCameraBlendCompleteEvent?.Invoke(cinemachineBrain.ActiveVirtualCamera,fromCamera);
fromCamera = null;
}
}
}
}
Used like this
//to subscribe
cinemachineBrain.SubscribeOnCameraBlendCompleteEvent(OnBlendCompleteHandler);
//to unsubscribe
cinemachineBrain.UnsubscribeOnCameraBlendCompleteEvent(OnBlendCompleteHandler);
//some random event handler method you can use for testing
private void OnBlendCompleteHandler(ICinemachineCamera toCamera, ICinemachineCamera fromCamera)
{
Debug.LogFormat("FROM CAMERA: {0} TO CAMERA: {1}",fromCamera.Name,toCamera.Name);
}
While the monstrosity above does work, it only works for one CinemachineBrain. I did have a blast hacking something up as an extension method so I wouldn’t have to use a helper script though :p.
Check the below post for a much better implementation!