Opsive and Edy’s Vehicle Physics (EVP)

Version 1 of Third Person Controller (Ultimate Character Controller) and Edy’s Vehicle Physics Integration. As I only have the Third Person piece, I do not know how this will work with the First Person piece.

I am not completely happy with this integration, but it works and allows the player to control vehicles and enter/exit smoothly. I would like to enhance this to allow for passengers, changing seats, and using weapons while in a passenger seat but the current set-up won’t allow that as there are limitations I have yet to figure out how to overcome.

DOES NOT WORK WITH UCC Version 2.1.3 and NEWER due to changes Opsive made by adding “Move with Object”

Below is the video showing my settings and process.
https://youtu.be/bLE8c1S3Nn8

Below is the Vehicle Manager script to be added to each vehicle. Watch the video for how to set up.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EVP;

///
///<summary>
/// Chris "RedHawk" Ferguson copyright 2019
/// </summary>

public class EdyVehicleManager : MonoBehaviour
{
    #region Variables - Edy's Vehicle Physics
    VehicleStandardInput m_VehicleStandardInput;
    VehicleController m_VehicleController;
    VehicleAudio m_VehicleAudio;
    #endregion

    #region Variables - Public to be used by the UCC Ability System
    [Tooltip("This is the position that the UCC Character will be moved to upon entering.  Make sure it doesn't stick through the floor.")]
    public Transform drivePosition;
    [Tooltip("This is the position of the Left Hand.  If there is a steering wheel, add it there.")]
    public GameObject LeftHandIKTarget;
    [Tooltip("This is the position of the Right Hand.  If there is a steering wheel, add it there.")]
    public GameObject RightHandIKTarget;
    [Tooltip("This is the position of the Left Foot.  Make sure it doesn't stick through the floor.")]
    public GameObject LeftFootIKTarget;
    [Tooltip("This is the position of the Right Foot.  Make sure it doesn't stick through the floor.")]
    public GameObject RightFootIKTarget;
    #endregion

    // Start is called before the first frame update
    void Start()
    {
        #region Assign the Components from Edy's
        m_VehicleStandardInput = this.GetComponent<VehicleStandardInput>();
        m_VehicleController = this.GetComponent<VehicleController>();
        m_VehicleAudio = this.GetComponent<VehicleAudio>();
        #endregion

        #region Disable the appropriate components
        m_VehicleStandardInput.enabled = false;
        m_VehicleAudio.enabled = false;
        #endregion

        #region Make sure the Vehicle doesn't move around
        m_VehicleController.throttleInput = 0.0f;
        m_VehicleController.brakeInput = 1.0f;
        #endregion

        if (drivePosition == null)
        {
            Debug.Log("Drive Position was not assigned", gameObject);
            drivePosition = transform;
        }

        //General IK Target Warnings
        if (LeftHandIKTarget == null)
            Debug.Log("Left Hand IK Target is not set, so IK Left Hand won't work on this ", gameObject);
        if (RightHandIKTarget == null)
            Debug.Log("Right Hand IK Target is not set, so IK Right Hand won't work on this ", gameObject);
        if (LeftFootIKTarget == null)
            Debug.Log("Left Foot IK Target is not set, so IK Left Foot won't work on this ", gameObject);
        if (RightFootIKTarget == null)
            Debug.Log("Right Foot IK Target is not set, so IK Right Foot won't work on this ", gameObject);
    }

}

Below is the Ability which will automatically show up as an Ability Option on your character.

using UnityEngine;
using Opsive.UltimateCharacterController.Character.Abilities; //Used for DetectObjectAbilityBase
using Opsive.UltimateCharacterController.Camera; //Used for the UCC Camera Controller
using Opsive.UltimateCharacterController.Character; //Used for the UCC Character IK
using Opsive.UltimateCharacterController.Objects.CharacterAssist; //Used for the UCC AbilityIKTarget
using EVP; //Used for Edy's Vehicle Physics
 
///<summary>
/// Chris "RedHawk" Ferguson copyright 2019
/// </summary>
 
public class EdyDriveAbility : DetectObjectAbilityBase
{
    #region Vairables - Edy's Vehicle Physics
    VehicleStandardInput m_VehicleStandardInput;
    VehicleController m_VehicleController;
    VehicleAudio m_VehicleAudio;
    VehicleViewConfig m_ViewConfig;
    Vector3 m_DefaultAchorOffset = Vector3.zero;
    EdyVehicleManager m_EdyVehicleManager;
    VehicleCameraController m_VehicleCameraController;
    #endregion

    #region Variables - General
    Transform m_PreviousParent;
    Transform m_Vehicle;
    Collider[] m_OriginalColliders;
    CameraController UCCCameraController;
    Animator m_Animator;
    #endregion

    public override void Start()
    {
        base.Start();
        //Locate the UCCCameraController since DetectObjectAbilityBase does not already have a reference to it
        UCCCameraController = Object.FindObjectOfType<CameraController>();
        //Locate the VehicleCameraController which should be on the same parent as the UCCCameraController
        m_VehicleCameraController = UCCCameraController.GetComponentInParent<VehicleCameraController>();
        //Disable Edy Vehicle Camera Controller if it exists
        if (m_VehicleCameraController)
        {
            m_VehicleCameraController.enabled = false;
        }
        //Locate the Animator which is always on the parent of the UCCCharacterController
        m_Animator = m_CharacterLocomotion.transform.GetComponent<Animator>();
    }

    //Prevent Ability from being prematurely stopped
    public override bool CanForceStopAbility()
    {
        return false;
    }
 
    ///<summary>
    /// The ability has started.
    /// </summary>
 
    protected override void AbilityStarted()
    {
        base.AbilityStarted();
        //DO GET IN STUFF
        #region Assign Edy's Vehicle Pieces
        m_Vehicle = m_DetectedObject.GetComponentInParent<VehicleStandardInput>().transform;
        m_EdyVehicleManager = m_Vehicle.GetComponentInChildren<EdyVehicleManager>();
        m_VehicleStandardInput = m_Vehicle.GetComponent<VehicleStandardInput>();
        m_VehicleController = m_Vehicle.GetComponent<VehicleController>();
        m_VehicleAudio = m_Vehicle.GetComponent<VehicleAudio>();
        m_ViewConfig = m_Vehicle.GetComponent<VehicleViewConfig>();
        #endregion

        #region UCC Colliders and Parenting
        //Locate the Colliders and Disable them so we don't get any conflicts
        m_OriginalColliders = m_CharacterLocomotion.Colliders;
        m_OriginalColliders[0].transform.parent.gameObject.SetActive(false);
        //Set a reference to the current UCCCharacterController Parent, and change the Parent to the Vehicle drive spot
        m_PreviousParent = m_CharacterLocomotion.transform.parent;
        m_CharacterLocomotion.transform.parent = m_EdyVehicleManager.drivePosition;
        //Disable the UCCCharacterLocomotion because it causes movement issues
        m_CharacterLocomotion.enabled = false;
        //Enable the Animator because UCC automatically turns it off
        m_Animator.enabled = true;

        //Use the position contained in the Vehicle Manager
        if (m_EdyVehicleManager == null)
        {
            m_CharacterLocomotion.SetPosition(m_Vehicle.transform.position);
            m_CharacterLocomotion.SetRotation(m_Vehicle.transform.rotation);
            Debug.Log("There was no EdyVehicleManager on this Vehicle", m_GameObject);
        }
        else
        {
            m_CharacterLocomotion.SetPosition(m_EdyVehicleManager.drivePosition.position);
            m_CharacterLocomotion.SetRotation(m_EdyVehicleManager.drivePosition.rotation);
        }

        //IK Targets - TURN ON
        CharacterIK m_characterIK = m_CharacterLocomotion.gameObject.GetComponent<CharacterIK>();
        m_characterIK.SetAbilityIKTarget(m_EdyVehicleManager.LeftFootIKTarget.transform, m_EdyVehicleManager.LeftFootIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        m_characterIK.SetAbilityIKTarget(m_EdyVehicleManager.RightFootIKTarget.transform, m_EdyVehicleManager.RightFootIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        m_characterIK.SetAbilityIKTarget(m_EdyVehicleManager.LeftHandIKTarget.transform, m_EdyVehicleManager.LeftHandIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        m_characterIK.SetAbilityIKTarget(m_EdyVehicleManager.RightHandIKTarget.transform, m_EdyVehicleManager.RightHandIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        #endregion

        #region Edy's Vehicle Physics Stuff
        //Save UCC Camera Anchor Offset
        m_DefaultAchorOffset = UCCCameraController.AnchorOffset;

        if (m_ViewConfig != null)
        {
            if (m_VehicleCameraController != null)
            {
                m_VehicleCameraController.enabled = true;
                UCCCameraController.enabled = false;
                m_VehicleCameraController.target = m_Vehicle;
                m_VehicleCameraController.SetViewConfig(m_ViewConfig);
            }
            else
            {
                Debug.Log("No VehichelCameraController found with Edy's script on ", UCCCameraController.gameObject);
                Vector3 tempVector3 = Vector3.zero;
                tempVector3.z = m_ViewConfig.viewDistance * -1f;
                tempVector3.y = m_ViewConfig.viewHeight;
            }
        }
        m_VehicleStandardInput.enabled = true;
        m_VehicleAudio.enabled = true;
        #endregion

    }
 
    ///<summary>
    /// The Ability has ended
    /// </summary>
 
    ///
    protected override void AbilityStopped(bool force)
    {
        base.AbilityStopped(force);
        //DO GET OUT STUFF

        #region Edy's Vehicle Physics Stuff
        //Stop the vehicle and put the brakes on
        m_VehicleController.throttleInput = 0.0f;
        m_VehicleController.brakeInput = 1.0f;
        //Disable the EVP Input
        m_VehicleStandardInput.enabled = false;
        //Disable the EVP Audio
        m_VehicleAudio.enabled = false;
        //Switch the Camera Controlls back to UCC
        if (m_VehicleCameraController != null)
        {
            UCCCameraController.enabled = true;
            m_VehicleCameraController.enabled = false;
        }
        #endregion

        #region UCC Colliders and Un-Parenting
        //Disable the Animator first because UCC will control it
        m_Animator.enabled = false;
        //Enable the UCC Locomotion Controller
        m_CharacterLocomotion.enabled = true;
        //Un-Parent
        m_CharacterLocomotion.transform.parent = m_PreviousParent;
        //Move character to Enter Position
        m_CharacterLocomotion.SetPositionAndRotation(m_DetectedObject.transform.position, m_DetectedObject.transform.rotation);
        //Turn Colliders back On
        m_OriginalColliders[0].transform.parent.gameObject.SetActive(true);
        //IK Targets - TURN OFF
        CharacterIK m_characterIK = m_CharacterLocomotion.gameObject.GetComponent<CharacterIK>();
        m_characterIK.SetAbilityIKTarget(null, m_EdyVehicleManager.LeftFootIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        m_characterIK.SetAbilityIKTarget(null, m_EdyVehicleManager.RightFootIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        m_characterIK.SetAbilityIKTarget(null, m_EdyVehicleManager.LeftHandIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        m_characterIK.SetAbilityIKTarget(null, m_EdyVehicleManager.RightHandIKTarget.GetComponent<AbilityIKTarget>().Goal, 0f);
        #endregion

    }
}

As always, feel free to make suggestions on how I can improve this.  Please make those suggestions on the Opsive Forum under my Edy’s integrations post. https://opsive.com/forum/index.php?threads/edys-vehicle-physics.720/