Best way to trigger cinemachine camera change on interact/ability?

Sangemdoko

Moderator
Staff member
Hi,

I was just wondering what is the best way to make my camera transitions when using Third Person Cinemachine viewType?

I am using a freeLookCamera by default which looks at the character from far and I would like to transition to other virtual cameras on ability activation or state change.

Case scenario 1:
I interact with a switch which opens a door. I can have a virtual camera that looks at the door and I transition between the character camera and the door camera while the door is opening.

In this case I could have a script that changes the priority of the door virtual camera on the interaction event.

Case scenario 2:
I start a conversation with an NPC (using the Dialogue System by PixelCrushers) using the "Converse" ability, I can set a "Converse" state. Now I would like the camera to zoom in and look at both the NPC and the character in an angle includes the full body of both and that faces the NPC. The camera would also need to not move while moving the mouse.

From what I understand that would be hard to achieve using camera states (or is there a state that changes which virtual camera has priority?). I could use the Dialogue system sequencer to place a camera, but I would have to do so for each conversation. I would prefer to have a default camera, which is set by the "Converse" ability and that can be overridden by the sequencer in a more cinematic conversation.

Case scenario 3:
Zoom while aiming target. I guess this one is similar to case 2. But this time the character would move.

Should I use another view type for this? or do I transition to another virtual camera?


So my question is how do I change the priority of a virtual camera when I use an ability/change state? Do I have to write my own script linking each additional virtual camera to a state? If I use the state changes to set my virtual cameras is there a way to pass an argument like the target transform?

Thank you for your time
 
By the way, I tried implementing a simple OnStateChangeEvent script which listens to state changes in the abilities and invokes functions set up in the inspector. I thought I could use it to change the priority on my conversation virtual camera.

But this does not work. OnAbilityActiveEvent does not get called.

Code:
public class OnStateChangeEvent : MonoBehaviour
    {
        public string state;
        public UnityEvent m_OnStateActivateEvent;
        public UnityEvent m_OnStateDeActivateEvent;

        UltimateCharacterLocomotion characterLocomotion;
        // Start is called before the first frame update
        void Start()
        {
            characterLocomotion = GetComponent<UltimateCharacterLocomotion>();
            //characterLocomotion.StateChange += ChangingState;
            characterLocomotion.OnAbilityActiveEvent.AddListener(AbilityActivated);
        }

        void AbilityActivated(Ability ability, bool activated)
        {
            Debug.Log(ability);
            Debug.Log(ability.State);
            Debug.Log(activated);
            if (ability.State == state)
            {
                if (activated)
                {
                    m_OnStateActivateEvent.Invoke();
                }
                else
                {
                    m_OnStateDeActivateEvent.Invoke();
                }
            }
        }
    }

From reading the documentation I understand that I should be using the EventHandler but I do not know the parameters to register to a state change/ability activate event. Is there a list of the events I can register to? They are specified as string values so I'm not sure where to look for them.

Am I going about this the wrong way? Is there a more in-depth documentation for the API?

Thank you for your time.
 
The Cinemachine View Type is not able to select/view different virtual cameras so for this case I would extend the View Type to include that. Ability.State points to the state name that it should enable or disable so instead of checking against that I would check against the actual ability. This page has an example of registering for the event: https://opsive.com/support/documentation/ultimate-character-controller/character/abilities/

The API docs can be generated if you open up your Object Browser within your IDE - this isn't online since it's easy to do within the IDE.
 
Hi,

Thank you for the prompt answer. I didn't know Object Browser was a thing I'm glad you told me about it.

So I tried making an extension of the view type and I got it working but there are a few things which I am sure could be improved but I do not know how.

Here is my current script:
C#:
using Cinemachine;
using Opsive.UltimateCharacterController.Events;
using Opsive.UltimateCharacterController.Character.Abilities;
using Opsive.UltimateCharacterController.Character;

namespace SleepingPenguinz.PhaeProject.OpsiveUCCSupport
{
    /// <summary>
    /// Allows Multiple Virtual Cinemachine Camera to be used by the CameraController. If a FreeLook virtual camera is used the CinemachineSpringExtension component should be added so it will respond to spring events.
    /// Version 2.1 or later of Cinemachine is required.
    /// </summary>
    public class CinemachineMVC : Opsive.UltimateCharacterController.ThirdPersonController.Camera.ViewTypes.Cinemachine
    {
        public UltimateCharacterLocomotion characterLocomotion;
        public CinemachineVirtualCamera converseCamera;

        /// <summary>
        /// Initializes the default values.
        /// </summary>
        public override void Awake()
        {
            base.Awake();

            //Why is m_CharacterLocomotion null?
            EventHandler.RegisterEvent<Ability, bool>(characterLocomotion.gameObject, "OnCharacterAbilityActive", OnAbilityActive);
        }

        /// <summary>
        /// The specified ability has started or stopped.
        /// </summary>
        /// <param name="ability">The ability that has been started or stopped.</param>
        /// <param name="activated">Was the ability activated?</param>
        private void OnAbilityActive(Ability ability, bool activated)
        {
            if(ability == characterLocomotion.GetAbility<Converse>())
            {
                converseCamera.Priority = activated ? 15 : 5;
            }
        }

        /// <summary>
        /// The GameObject has been destroyed.
        /// </summary>
        public override void OnDestroy()
        {
            EventHandler.UnregisterEvent<Ability, bool>(characterLocomotion.gameObject, "OnCharacterAbilityActive", OnAbilityActive);
            base.OnDestroy();
        }
    }
}

So, first of all, I do not understand why m_CharacterLocomotion is null in both Awake and OnDestroy. It would make a lot more sense if I used the Character gameObject set in the CameraController inspector. I thought the CameraController was supposed to attach the character to the viewType.

Here I use the GetAbility method to find Converse. If possible I was thinking of having a serialized struct (ability, virtual camera) array that I could set in the inspector. That way I could easily add/remove virtual Camera ability changes. But there is no way to set an Ability in the inspector, if I used a string how can I convert the string to the Ability Type? Of course, that's not necessary I can do without.

One thing I am not sure how it works is the viewType full name in the inspector. How come your viewTypes start with "Third Person" but mine does not? Just curious.

One last thing I realised the cinemachineSpringExtension does not get added to my component. I have no errors or warnings in the console but I get this when I add it (notice the empty script field):
1547980634560.png
and this when I click away and come back:
1547980672794.png
Any ideas what could cause this problem?
 
I thought the CameraController was supposed to attach the character to the viewType.
CharacterLocomotion will be assigned within AttachCharacter.

But there is no way to set an Ability in the inspector, if I used a string how can I convert the string to the Ability Type?
Abilities are object's so there's no way for Unity to display them. You can use UnityEngineUtility.GetType to convert from a string to a type.

One thing I am not sure how it works is the viewType full name in the inspector. How come your viewTypes start with "Third Person" but mine does not?
The Cinemachine View Type is in the ThirdPersonController namespace.

One last thing I realised the cinemachineSpringExtension does not get added to my component. I have no errors or warnings in the console but I get this when I add it (notice the empty script field):
I'm not sure on that - have you tried a fresh project?
 
Top