Hi,
Im wondering what the best way to change cinemachine components at runtime is or if I have I found a bug.
Basically, I’ve been setting up a scripted cinemachine environment for a game where every camera has identical settings. The cameras are all generated at runtime by creating CinemachineFreelook cameras and adjusting them as appropriate with common settings (it would be really nice to have something to handle common settings in the released code BTW).
Some of my CinemachineFreelook cameras need to point at groups of GameObjects. This, I found from nosing about in the API was fairly easy to do by swapping out the CinemachineComposer for the CinemachineGroupComposer (which looking at/follows a runtime created CinemachineTargetGroup). The component swapping is done like this example snippet:
// freeLook is a CinemachineFreelook.
vcams[i] = freeLook.GetRig(i).GetComponent<CinemachineVirtualCamera>();
// original method from 2.1.10
vcams[i].DestroyCinemachineComponent<CinemachineComposer>();
composers[i] = vcams[i].AddCinemachineComponent<CinemachineGroupComposer>();
... go on to setup things...
This worked brilliantly in v2.1.10 and several previous versions, however, in v2.1.12 it fails with a lengthy stack trace.
MissingReferenceException: The object of type ‘CinemachineComposer’ has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
Cinemachine.CinemachineComposer.get_IsValid () (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Components/CinemachineComposer.cs:115)
Cinemachine.CinemachineComposer.PrePipelineMutateCameraState (Cinemachine.CameraState& curState) (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Components/CinemachineComposer.cs:172)
Cinemachine.CinemachineVirtualCamera.CalculateNewState (Vector3 worldUp, Single deltaTime) (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Behaviours/CinemachineVirtualCamera.cs:432)
Cinemachine.CinemachineVirtualCamera.InternalUpdateCameraState (Vector3 worldUp, Single deltaTime) (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Behaviours/CinemachineVirtualCamera.cs:133)
Cinemachine.CinemachineCore.UpdateVirtualCamera (ICinemachineCamera vcam, Vector3 worldUp, Single deltaTime) (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Core/CinemachineCore.cs:244)
Cinemachine.CinemachineCore.UpdateAllActiveVirtualCameras (Vector3 worldUp, Single deltaTime) (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Core/CinemachineCore.cs:172)
Cinemachine.CinemachineBrain.UpdateVirtualCameras (UpdateFilter updateFilter, Single deltaTime) (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Behaviours/CinemachineBrain.cs:439)
Cinemachine.CinemachineBrain.LateUpdate () (at /Users/martin/Library/Unity/cache/packages/packages.unity.com/com.unity.cinemachine@2.1.12/Runtime/Behaviours/CinemachineBrain.cs:393)
Now, when the game is running in editor mode, simply clicking on the generated CM camera that is emitting these errors fixes it and the game runs normally. So something else must be happening.
In CM v.2.1.10, inside CinemachineVirtualCamera.cs DestroyCinemachineComponent implementation the method uses Unitys DestroyImmediate() to destroy the component.
However, in CM c.2.1.12 this has been replaced by a RuntimeUtility.DestroyObject() that uses Destroy() if the application is playing. Hacking this change out removes the stack traces and also makes the game run normally [as does having a local re-implementation of the v2.1.10 code in my csharp].
So presumably, the parts of CM in the stack trace above have trouble with not destroying the object immediately.
My question is really, is this a bug introduced by the changes in DestroyCinemachineComponent? or is my approach completely flawed because there is a better way that I am unaware of?
Kind regards,
Martin.