Adapting zoom state look offset when crouched or prone

avalonsutra

New member
How can a property be changed depending on two states? Example:
  • Third-person camera and character
  • Has Crouching height change ability --> Crouch state with a camera look offset Y -0.5
  • Has Zoom ability --> Zoom state with camera look offset Y 0.0
Zooming while standing upright looks OK.
Zooming while crouched positions the camera too high.

I've already created a state preset that offsets the camera when going crouched (camera is lowered) but if the player then zooms the camera goes up again which is undesired.

Since the zoom state preset also changes the look offset (to move the camera near the character's shoulder) it resets the Y offset which conflicts with the Y offset when crouched or prone. How could this issue be solved?
 
This is one of the limitations of the state system. You are not able to combine two different states into a single preset. For this you will need to create a new script that listens for the ability activation status and set a new joined state based on that status. You can listen for the OnCharacterAbilityActive callback.

 
Thanks for the hints, I've copied the script from the Abilities docs page...

C#:
using UnityEngine;
using Opsive.UltimateCharacterController.Character.Abilities;
using Stellar.Core;
using EventHandler = Opsive.Shared.Events.EventHandler;


public class UCCAbilityListener : MonoBehaviour
{
    /// <summary>
    ///        Initialize the default values.
    /// </summary>
    public void Awake()
    {
        Debug.Log("Awake");
        EventHandler.RegisterEvent<Ability, bool>(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)
    {
        Debug.Log(ability + " activated: " + activated);
    }


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

Awake is called but OnAbilityActive seems to not be triggered when any ability is activated. Is there anything else I need to think of for this to work? Event System and UCC managers are added in the scene.
 
Last edited:
Did you add the script to the character GameObject? If not you will need to register the event with the character instead of the local GameObject.
 
Did you add the script to the character GameObject? If not you will need to register the event with the character instead of the local GameObject.
Ok, on the Character game object it works!
Just for completeness ...
> If not you will need to register the event with the character instead of the local GameObject.
How would this look, code-wise?

Is there any event for listenting to state changes? I found OnStateChange in the source but seems there's nothing coming through, e.g.

C#:
EventHandler.RegisterEvent<GameObject, string, bool>(gameObject, "OnStateChange", OnStateChange);

I got one related question... on the UC Locomotion component there's a section for events ... what would that be useful for? (I don't find any info in the docs about this.)

snag_20240503_0006.png
 
Last edited:
How would this look, code-wise?
You could have a public character GameObject field that you assign, and then use reference instead of gameObject when registering for the event.

I got one related question... on the UC Locomotion component there's a section for events ... what would that be useful for? (I don't find any info in the docs about this.)
That's the same thing as the built in event system, except using Unity's event system.
 
Hi Justin, thanks for taking the time to reply!

Reg.
> Is there any event for listenting to state changes? I found OnStateChange in the source but seems there's nothing coming through, e.g.

What could be the reason for not receiving events from OnStateChange? i've set it up the same way as OnCharacterAbilityActive?
 
OnStateChange is a global event so you don't register it on on any particular GameObject. If you do a search within the codebase you'll see some examples of its use. In addition, you'll need to make sure you enable the event on the State Manager.
 
Anything I can find in the Opsive source files for OnStateChange is this and it doesn't provide any example on how the event is listened to, except for on the stateElementContainer perhaps, which I doubt should be required for this. Would be great to have some usage example for this in the docs.
snag_20240506_0002.png
I'd assume it would be StateManager.OnStateChange += OnStateChanged but there is no such property on StateManager. There's SendStateChangeEvent which is not static, StateManager.Instance is private so can't be accessed. How is it supposed to be used?
 
Last edited:
The docs give an example of global events at the bottom:


When I searched I found OnStateChange within the MovementStateMonitor but just saw that that file is part of a deprecated VR add-on. Here's the usage:

Code:
EventHandler.RegisterEvent<GameObject, string, bool>("OnStateChange", OnStateChange);

You don't enable the event within code, it's on the State Manager inspector.
 
Ok, thanks this works! The tiny difference being that the first parameter (object obj) is omitted. On the doc page it is still part of the example code:
C#:
EventHandler.RegisterEvent<Vector3, Vector3, GameObject>(gameObject, "OnDeath", OnDeath);
 
Top