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>();
if (navMeshAgent != null)
{
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 () || !characterAC.IsPlayer || characterAC.IsMovingAlongPath () || 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:
if (navMeshAgent != null)
{
navMeshAgent.enabled = false;
}
else
{
ACDebug.LogWarning ("A NavMeshAgent component is required on " + gameObject.name, this);
}
if (!m_Jump)
{
m_Jump = Input.GetButtonDown ("Jump");
}
break;
case ControlState.UnityPathfinding:
if (navMeshAgent != null)
{
navMeshAgent.enabled = true;
}
if (navMeshAgent != null && 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);
}
}
else
{
characterAC.Teleport (characterAC.GetTargetPosition (true));
ACDebug.LogWarning ("Character " + name + " cannot pathfind without a NavMeshAgent that is on the NavMesh - teleporting instead.", gameObject);
}
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);
}
}
}