No edit summary Tag: Visual edit |
No edit summary Tag: Visual edit |
||
(2 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
− | This script allows for integration with Unity's |
+ | This script allows for integration with Unity's [https://assetstore.unity.com/packages/essentials/starter-assets-third-person-character-controller-196526 Starter Assets - Third Person Controller] asset. |
To use it: |
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.<br> |
||
+ | # Import AC into a project that is already set up with the Third Person Controller asset |
||
⚫ | |||
+ | # Copy/paste the script below into a C# file named StarterAssetsInput_AC |
||
− | using System.Collections; |
||
+ | # Locate the asset's PlayerArmature prefab, and remove its Starter Assets Input component |
||
− | using System.Collections.Generic; |
||
+ | # Add the new Starter Assets Input AC component, as well as AC's Player component |
||
+ | # In the Player component's Inspector, set the Animation engine to Mecanim, and clear the parameter fields beneath |
||
+ | |||
⚫ | |||
using UnityEngine; |
using UnityEngine; |
||
+ | #if ENABLE_INPUT_SYSTEM |
||
− | using UnityEngine. |
+ | using UnityEngine.InputSystem; |
− | using UnityStandardAssets.Characters.ThirdPerson; |
||
+ | #endif |
||
using AC; |
using AC; |
||
+ | namespace StarterAssets |
||
− | public class UnityThirdPersonIntegration : MonoBehaviour |
||
{ |
{ |
||
⚫ | |||
− | |||
+ | public class StarterAssetsInputs_AC : StarterAssetsInputs |
||
− | 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; |
||
− | |||
⚫ | |||
{ |
{ |
||
⚫ | |||
− | m_mainCamera = KickStarter.CameraMain; |
||
+ | public bool acTurnsCamera; |
||
⚫ | |||
⚫ | |||
− | if (navMeshAgent != null) |
||
+ | AC.Char acCharacter; |
||
+ | bool underACControl; |
||
⚫ | |||
⚫ | |||
{ |
{ |
||
⚫ | |||
− | navMeshAgent.updateRotation = false; |
||
⚫ | |||
− | navMeshAgent.updatePosition = false; |
||
} |
} |
||
⚫ | |||
− | characterAC = GetComponent<Char>(); |
||
⚫ | |||
⚫ | |||
− | characterPaths = GetComponent<Paths>(); |
||
− | characterTP = GetComponent<ThirdPersonCharacter>(); |
||
⚫ | |||
− | |||
− | private void OnEnable () |
||
⚫ | |||
− | EventManager.OnCharacterSetPath += SetCharacterPath; |
||
⚫ | |||
− | |||
− | private void OnDisable () |
||
⚫ | |||
− | EventManager.OnCharacterSetPath -= SetCharacterPath; |
||
− | } |
||
− | |||
⚫ | |||
− | { |
||
− | UpdateControlState(); |
||
− | UpdateMovement(); |
||
− | } |
||
− | |||
− | private void FixedUpdate() |
||
− | { |
||
− | if (controlState == ControlState.UnderDirectControl) |
||
{ |
{ |
||
+ | underACControl = !KickStarter.stateHandler.IsInGameplay () || |
||
− | // Do all the input checks for direct input |
||
⚫ | |||
− | UpdateDirectInput(); |
||
+ | acCharacter.IsMovingAlongPath (); |
||
⚫ | |||
⚫ | |||
− | } |
||
+ | if (underACControl) |
||
− | |||
− | private void UpdateControlState() |
||
− | { |
||
⚫ | |||
⚫ | |||
− | if (characterAC.charState == CharState.Move) |
||
{ |
{ |
||
+ | Vector3 moveDirection = acCharacter.GetTargetPosition () - transform.position; |
||
− | controlState = ControlState.UnityPathfinding; |
||
+ | MoveInput (moveDirection); |
||
⚫ | |||
− | + | ||
⚫ | |||
− | { |
+ | { |
− | controlState = ControlState.ACTurning; |
||
+ | Vector3 lookDirection = acCharacter.GetTargetRotation () * Vector3.forward; |
||
+ | lookDirection.y = 0f; |
||
+ | LookInput (lookDirection); |
||
⚫ | |||
} |
} |
||
} |
} |
||
− | + | ||
+ | private Vector2 GetInputVector (Vector3 worldDirection) |
||
{ |
{ |
||
+ | worldDirectionworldDirection.y = 0f; |
||
− | controlState = ControlState.UnderDirectControl; |
||
+ | if (worldDirection.sqrMagnitude > 1f) worldDirection.Normalize (); |
||
⚫ | |||
+ | Vector3 cameraForward = KickStarter.CameraMainTransform.forward; |
||
− | } |
||
+ | cameraForward.y = 0f; |
||
+ | cameraForward.Normalize (); |
||
+ | Vector3 cameraRight = KickStarter.CameraMainTransform.right; |
||
− | private void UpdateMovement() |
||
+ | cameraRight.y = 0f; |
||
− | { |
||
+ | cameraRight.Normalize (); |
||
− | switch (controlState) |
||
⚫ | |||
− | case ControlState.UnderDirectControl: |
||
− | if (navMeshAgent != null) |
||
⚫ | |||
− | navMeshAgent.enabled = false; |
||
− | } |
||
− | else |
||
− | { |
||
− | ACDebug.LogWarning("A NavMeshAgent component is required on " + gameObject.name, this); |
||
− | } |
||
⚫ | |||
− | { |
||
− | m_Jump = Input.GetButtonDown("Jump"); |
||
− | } |
||
− | break; |
||
+ | float forwardAmount = Vector3.Dot (cameraForward, worldDirection.normalized); |
||
− | case ControlState.UnityPathfinding: |
||
+ | float rightAmount = Vector3.Dot (cameraRight, worldDirection.normalized); |
||
− | 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; |
||
+ | return new Vector2 (rightAmount, forwardAmount); |
||
− | case ControlState.ACTurning: |
||
⚫ | |||
− | characterTP.Move (Vector3.zero, false, false); |
||
− | break; |
||
+ | #if ENABLE_INPUT_SYSTEM |
||
− | default: |
||
+ | public new void OnMove(InputValue value) |
||
− | break; |
||
⚫ | |||
+ | if (underACControl) return; |
||
+ | MoveInput(value.Get<Vector2>()); |
||
} |
} |
||
− | } |
||
+ | public new void OnLook(InputValue value) |
||
− | private void UpdateDirectInput() |
||
− | { |
||
− | float h = Input.GetAxis ("Horizontal"); |
||
− | float v = Input.GetAxis ("Vertical"); |
||
− | bool crouch = Input.GetKey(KeyCode.C); |
||
− | if (m_mainCamera != null) |
||
{ |
{ |
||
+ | if(cursorInputForLook) |
||
− | // 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 |
||
{ |
{ |
||
+ | LookInput(value.Get<Vector2>()); |
||
− | 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; |
||
− | } |
||
+ | public new void OnJump(InputValue value) |
||
− | private void OnTeleport() |
||
− | { |
||
− | if (navMeshAgent != null && navMeshAgent.isOnNavMesh) |
||
{ |
{ |
||
+ | if (underACControl) return; |
||
− | navMeshAgent.Warp(transform.position); |
||
+ | JumpInput(value.isPressed); |
||
} |
} |
||
− | } |
||
+ | public new void OnSprint(InputValue value) |
||
− | void OnAnimatorMove() |
||
− | { |
||
− | if (navMeshAgent != null) |
||
{ |
{ |
||
+ | if (underACControl) { SprintInput (acCharacter.isRunning); return; } |
||
− | agentPosition.x = transform.localPosition.x; |
||
+ | SprintInput(value.isPressed); |
||
− | agentPosition.y = navMeshAgent.nextPosition.y; |
||
− | agentPosition.z = transform.localPosition.z; |
||
− | navMeshAgent.nextPosition = agentPosition; |
||
} |
} |
||
+ | #endif |
||
− | } |
||
− | void SetCharacterPath(Char character, Paths paths) |
||
− | { |
||
− | navMeshAgent.SetDestination (characterAC.GetTargetPosition (true)); |
||
} |
} |
||
⚫ | |||
− | |||
} |
} |
||
</syntaxhighlight> |
</syntaxhighlight> |
Latest revision as of 05:56, 27 September 2023
This script allows for integration with Unity's Starter Assets - Third Person Controller asset.
To use it:
- Import AC into a project that is already set up with the Third Person Controller asset
- Copy/paste the script below into a C# file named StarterAssetsInput_AC
- Locate the asset's PlayerArmature prefab, and remove its Starter Assets Input component
- Add the new Starter Assets Input AC component, as well as AC's Player component
- In the Player component's Inspector, set the Animation engine to Mecanim, and clear the parameter fields beneath
StarterAssetsInput_AC.cs:
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
using AC;
namespace StarterAssets
{
public class StarterAssetsInputs_AC : StarterAssetsInputs
{
public bool acTurnsCamera;
AC.Char acCharacter;
bool underACControl;
void Awake ()
{
acCharacter = GetComponent<AC.Char> ();
acCharacter.motionControl = MotionControl.Manual;
}
void Update ()
{
underACControl = !KickStarter.stateHandler.IsInGameplay () ||
(!acCharacter.IsPlayer || KickStarter.settingsManager.movementMethod == MovementMethod.PointAndClick) ||
acCharacter.IsMovingAlongPath ();
if (underACControl)
{
Vector3 moveDirection = acCharacter.GetTargetPosition () - transform.position;
MoveInput (moveDirection);
if (acTurnsCamera)
{
Vector3 lookDirection = acCharacter.GetTargetRotation () * Vector3.forward;
lookDirection.y = 0f;
LookInput (lookDirection);
}
}
}
private Vector2 GetInputVector (Vector3 worldDirection)
{
worldDirectionworldDirection.y = 0f;
if (worldDirection.sqrMagnitude > 1f) worldDirection.Normalize ();
Vector3 cameraForward = KickStarter.CameraMainTransform.forward;
cameraForward.y = 0f;
cameraForward.Normalize ();
Vector3 cameraRight = KickStarter.CameraMainTransform.right;
cameraRight.y = 0f;
cameraRight.Normalize ();
float forwardAmount = Vector3.Dot (cameraForward, worldDirection.normalized);
float rightAmount = Vector3.Dot (cameraRight, worldDirection.normalized);
return new Vector2 (rightAmount, forwardAmount);
}
#if ENABLE_INPUT_SYSTEM
public new void OnMove(InputValue value)
{
if (underACControl) return;
MoveInput(value.Get<Vector2>());
}
public new void OnLook(InputValue value)
{
if(cursorInputForLook)
{
LookInput(value.Get<Vector2>());
}
}
public new void OnJump(InputValue value)
{
if (underACControl) return;
JumpInput(value.isPressed);
}
public new void OnSprint(InputValue value)
{
if (underACControl) { SprintInput (acCharacter.isRunning); return; }
SprintInput(value.isPressed);
}
#endif
}
}