Dynamic FOV

bluemanD

New member
How could I add dynamic FOV to my controller? I have a player setting that changes FOV at runtime and want to have the FOV increase a little when running. Is there a way to do this?

====EDIT====

This is the code I wrote. To change the FOV, you will need to do four things.
  1. Add an enum value for the state you want.
  2. Create a state preset and set the PlayerMovementType enum to what you want.
  3. Add a property for your FOV.
  4. Add a case in the switch statement for the PlayerMovementType you added.
Everything should work. If I find any bugs I will update this code.

NOTE: Wherever you see YOUR_FOV_SETTING or YOUR_GAME_PAUSED, you will have to add your own values here. For YOUR_FOV_SETTING you will need to add whatever your setting variable is for FOV or a constant value if you don't allow the player to change the FOV in game. For YOUR_GAME_PAUSED, you can remove the if statement if you can't pause the game, and if you can pause the game just add in your way of checking to see if the game is paused.

You can also use this with any other controller or for whatever your needs are, not just this controller. Just remove the code for the Opsive Character Controller and make necessary changes and it should works.

VERSION 1.0.1
Added in crouching which lowers the FOV.
C#:
using Opsive.Shared.StateSystem;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Opsive.UltimateCharacterController.Camera;

public class DynamicFOV : StateBehavior
{
    // Player camera in scene.
    public CameraController camera;

    // Inspector settings.
    public bool useDynamicFOV;
    public float extraFOV = 5;
    public float changeDuration = 1f;
    [SerializeField] [InspectorName("FOV Curve")] private AnimationCurve fovCurve;

    // Player movement types.
    private PlayerMovementType _previousMovementType;
    private PlayerMovementType _currentPlayerMovementType;
    // Property changed in the state preset.
    public PlayerMovementType CurrentPlayerMovementType { get { return _currentPlayerMovementType; } set { _currentPlayerMovementType = value; } }
  
    // Used for changing the FOV setting in game.
    private float currentFOV;
    private float currentExtraFOV;
  
    // The elapsed time is set in the Update method.
    private float elapsedTime;

    // The FOVs.
    private float NormalFOV
    {
        get
        {
            return CurrentSettings.currentFOV;
        }
    }
    private float RunningFOV
    {
        get
        {
            return CurrentSettings.currentFOV + extraFOV;
        }
    }
    private float CrouchingFOV
    {
        get
        {
            return CurrentSettings.currentFOV - extraFOV;
        }
    }


    private void Start()
    {
        ResetFOV();
    }

    // Resets the FOV back to the current setting, set by the player, and changes the movement type back to walking.
    private void ResetFOV()
    {
        elapsedTime = 0;
        CurrentPlayerMovementType = PlayerMovementType.walking;
        currentFOV = YOUR_FOV_SETTING ;
        camera.GetViewType<Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes.Combat>().FieldOfView = YOUR_FOV_SETTING;
        camera.GetComponent<Camera>().fieldOfView = YOUR_FOV_SETTING ;
    }

    private void Update()
    {
        // This setting is set in the inspector and can easily work as a setting set by the player at runtime.
        if (useDynamicFOV)
        {
            if (!YOUR_GAME_PAUSED)
            {
                if (_previousMovementType != CurrentPlayerMovementType)
                {
                    elapsedTime = 0;
                }
                _previousMovementType = CurrentPlayerMovementType;

                // Gets the percentage completed.
                elapsedTime += Time.deltaTime;
                float percentageComplete = elapsedTime / changeDuration;

                // Lerps to the new FOV.
                switch (CurrentPlayerMovementType)
                {
                    case PlayerMovementType.running:
                        LerpCameraFOV(RunningFOV, percentageComplete);
                        break;
                    // Optional crouch type.
                    case PlayerMovementType.crouching:
                        LerpCameraFOV(CrouchingFOV, elapsedTime / (changeDuration / 2));
                        break;
                    default:
                        LerpCameraFOV(NormalFOV, percentageComplete);
                        break;
                }
            }
            else
            {
                // If the game is paused, then the game will set the FOV here. This code allows the player to set the FOV in game.
                SetCameraFOV(YOUR_FOV_SETTING + currentExtraFOV);
            }

            currentFOV = camera.GetViewType<Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes.Combat>().FieldOfView;
            currentExtraFOV = currentFOV - YOUR_FOV_SETTING;
        }
        // If it's not enabled then the code will always set the FOV back to the current setting.
        else
        {
            ResetFOV();
        }
    }

    // This is the code to lerp the camera's FOV.
    private void LerpCameraFOV(float fov, float percentageComplete)
    {
        // Opsive code.
        camera.GetViewType<Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes.Combat>().FieldOfView =
        Mathf.Lerp(camera.GetViewType<Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes.Combat>().FieldOfView, fov, fovCurve.Evaluate(percentageComplete));

        // Unity code.
        camera.GetComponent<Camera>().fieldOfView = Mathf.Lerp(camera.GetComponent<Camera>().fieldOfView, fov, fovCurve.Evaluate(percentageComplete));

        if (camera.GetComponent<Camera>().fieldOfView == NormalFOV)
        {
            elapsedTime = 0;
        }
        else if (camera.GetComponent<Camera>().fieldOfView == RunningFOV)
        {
            elapsedTime = 0;
        }
    }

    // Sets the FOV without a smooth transition.
    private void SetCameraFOV(float fov)
    {
        camera.GetViewType<Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes.Combat>().FieldOfView = fov;
        camera.GetComponent<Camera>().fieldOfView = fov;
    }
}

// The different movement types. More can easily be added.
public enum PlayerMovementType
{
    walking,
    running,
    crouching
}
 
Last edited:
Yes, you can get a reference to the view type and then change the field of view property. Take a look at the docs for an example of getting the field of view.
 
Doesn't this only set it to a set value? I want it to add to the current FOV, set by the player, by a certain amount. Am I wrong on how this works?
 
Using your own script you can change the property to whatever value you want as well as whenever you want.
 
I made the class to handle dynamic FOV. Thanks for leading me in the right direction! It took a second to wrap my head around but it works! And my setting for changing FOV works still! Thank you!
 
Just as an addition. You can also use the state system to adjust the FOV (e.g. the speed change ability sets the state "Run" which can be used with a preset to alter the FOV value). But it only allows to set a predefined / fixed value.
 
Top