This script allows for integration with Unity's own Third Person Controller, which is included in their own Standard Assets package. It can be used to move a character with both Direct and Point And Click methods, using the Third Person Controller script.
To use it:
- Take the existing ThirdPersonController or AIThirdPersonController prefab, and remove any existing control script (with ThirdPersonController, this is ThirdPersonUserControl; with AIThirdPersonController, this is AICharacterControl).
- Attach either AC's Player or NPC component
- In AC's Settings Manager, set your game's Movement method to either Point And Click or Direct
- Attach the script below to the character's root object
- (Optional) To allow for AC-controlled movement during e.g. cutscenes, also attach and configure a NavMeshAgent. The scene must also rely on Unity Navigation pathfinding, as covered in the AC Manual.
UnityThirdPersonIntegration.cs:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; using UnityStandardAssets.Characters.ThirdPerson; using AC; public class UnityThirdPersonIntegration : MonoBehaviour { private NavMeshAgent navMeshAgent; private AC.Char characterAC; private ThirdPersonCharacter characterTP; private enum ControlState { UnderDirectControl, UnityPathfinding, ACTurning }; private ControlState controlState = ControlState.ACTurning; private Vector3 m_CamForward; private Vector3 m_Move; private bool m_Jump; private void Start () { // Get component variables, init the NavMeshAgent, and force Manual motion control to the AC character navMeshAgent = GetComponentInChildren <NavMeshAgent>(); navMeshAgent.updateRotation = false; navMeshAgent.updatePosition = true; characterAC = GetComponent <Char>(); characterAC.motionControl = MotionControl.JustTurning; characterTP = GetComponent<ThirdPersonCharacter>(); } private void Update () { // Update what our current control state is UpdateControlState (); // Move the character according to the current control state UpdateMovement (); } private void FixedUpdate () { if (controlState == ControlState.UnderDirectControl) { // Do all the input checks for direct input UpdateDirectInput (); } } private void UpdateControlState () { // Check if we want to determine the character's position through AC, or just through direct input if (!KickStarter.stateHandler.IsInGameplay () || KickStarter.settingsManager.movementMethod == MovementMethod.PointAndClick) { // Check if we want to make the character pathfind, or do nothing while AC turns them if (characterAC.charState == CharState.Move) { controlState = ControlState.UnityPathfinding; } else { controlState = ControlState.ACTurning; } } else { controlState = ControlState.UnderDirectControl; } } private void UpdateMovement () { switch (controlState) { case ControlState.UnderDirectControl: navMeshAgent.enabled = false; if (!m_Jump) { m_Jump = Input.GetButtonDown ("Jump"); } break; case ControlState.UnityPathfinding: if (navMeshAgent != null) { navMeshAgent.enabled = true; if (navMeshAgent.isOnNavMesh) { navMeshAgent.SetDestination (characterAC.GetTargetPosition (true)); if (navMeshAgent.remainingDistance > navMeshAgent.stoppingDistance) { characterTP.Move (navMeshAgent.desiredVelocity, false, false); } else { characterTP.Move (Vector3.zero, false, false); } } } break; case ControlState.ACTurning: characterTP.Move (Vector3.zero, false, false); break; } } private void UpdateDirectInput () { float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); bool crouch = Input.GetKey(KeyCode.C); if (Camera.main != null) { // calculate camera relative direction to move: m_CamForward = Vector3.Scale (Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized; m_Move = v*m_CamForward + h*Camera.main.transform.right; } else { m_Move = v * Vector3.forward + h * Vector3.right; } if (Input.GetKey (KeyCode.LeftShift)) { m_Move *= 0.5f; } characterTP.Move (m_Move, crouch, m_Jump); m_Jump = false; } private void OnTeleport () { // This function is called by the Char script whenever the character has been teleported. if (navMeshAgent != null && navMeshAgent.isOnNavMesh) { navMeshAgent.Warp (transform.position); } } }