Adventure Creator Wikia
Advertisement

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:

  1. Take the existing ThirdPersonController or AIThirdPersonController prefab, and remove any existing control script (with ThirdPersonController, this is ThirdPersonUserControl; with AIThirdPersonController, this is AICharacterControl).
  2. Attach either AC's Player or NPC component
  3. In AC's Settings Manager, set your game's Movement method to either Point And Click or Direct
  4. Attach the script below to the character's root object
  5. (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 AC.Paths characterPaths;
	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 float m_moveMultiplier = 0.5f;
	private Camera m_mainCamera;
	private Vector3 agentPosition = Vector3.zero;
	private MotionControl originalMotionControl;

	private void Awake()
	{
		m_mainCamera = KickStarter.CameraMain;
		navMeshAgent = GetComponent<NavMeshAgent>();
		if (navMeshAgent != null)
		{
			navMeshAgent.updateRotation = false;
			navMeshAgent.updatePosition = false;
		}
		characterAC = GetComponent<Char>();
		originalMotionControl = characterAC.motionControl;
		characterAC.motionControl = MotionControl.JustTurning;
		characterPaths = GetComponent<Paths>();
		characterTP = GetComponent<ThirdPersonCharacter>();
	}

	private void OnEnable ()
	{
		characterAC = GetComponent<Char>();
		originalMotionControl = characterAC.motionControl;
		characterAC.motionControl = MotionControl.JustTurning;

		EventManager.OnCharacterSetPath += SetCharacterPath;
	}

	private void OnDisable ()
	{
		characterAC.motionControl = originalMotionControl;
		EventManager.OnCharacterSetPath -= SetCharacterPath;
	}

	private void Update()
	{
		UpdateControlState();
		UpdateMovement();
	}

	private void FixedUpdate()
	{
		if (controlState == ControlState.UnderDirectControl)
		{
			// Do all the input checks for direct input
			UpdateDirectInput();
		}
	}

	private void UpdateControlState()
	{
		if (!KickStarter.stateHandler.IsInGameplay() || !characterAC.IsPlayer || characterAC.IsMovingAlongPath() || KickStarter.settingsManager.movementMethod == MovementMethod.PointAndClick)
		{
			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)
				{
					 if (navMeshAgent.remainingDistance > navMeshAgent.stoppingDistance)
					 {
						if (characterAC.isRunning)
						{
								m_moveMultiplier = 1.0f;
						}
						else
						{
								m_moveMultiplier = 0.5f;
						}
						characterTP.Move(navMeshAgent.desiredVelocity * m_moveMultiplier, 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;

			default:
				break;
		}
	}

	private void UpdateDirectInput()
	{
		float h = Input.GetAxis ("Horizontal");
		float v = Input.GetAxis ("Vertical");
		bool crouch = Input.GetKey(KeyCode.C);
		if (m_mainCamera != null)
		{
			// calculate camera relative direction to move:
			if (KickStarter.settingsManager.directMovementPerspective)
			{
				Vector3 forwardVector = (characterAC.transform.position - m_mainCamera.transform.position).normalized;
				Vector3 rightVector = -Vector3.Cross(forwardVector, m_mainCamera.transform.up);
				m_Move = (v * forwardVector) + (h * rightVector);
			}
			else
			{
				m_CamForward = Vector3.Scale(m_mainCamera.transform.forward, new Vector3(1, 0, 1)).normalized;
				m_Move = v * m_CamForward + h * m_mainCamera.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()
	{
		if (navMeshAgent != null && navMeshAgent.isOnNavMesh)
		{
			navMeshAgent.Warp(transform.position);
		}
	}

	void OnAnimatorMove()
	{
		if (navMeshAgent != null)
		{
			agentPosition.x = transform.localPosition.x;
			agentPosition.y = navMeshAgent.nextPosition.y;
			agentPosition.z = transform.localPosition.z;
			navMeshAgent.nextPosition = agentPosition;
		}
	}

	void SetCharacterPath(Char character, Paths paths)
	{
		 navMeshAgent.SetDestination (characterAC.GetTargetPosition (true));
	}

}
Advertisement