FANDOM


This script demonstrates how AC characters can be integrated with Kinematic Character Controller.

It integrates with the Example Character Controller, to allow user-control of Players during gameplay, and AC-control of NPCs and players during cutscenes. Note that AC v1.62.5 or later is required.

To use it:

  1. Prepare your KCC character as normal using the Example Character Controller
  2. Attach either AC's NPC or Player component (tagging the GameObject as Player if the latter
  3. Attach the script below as a component named KCCIntegration:

KCCIntegration.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using KinematicCharacterController;
using KinematicCharacterController.Examples;
using AC;

public class KCCIntegration : MonoBehaviour
{

public AC.Char characterAC;
public ExampleCharacterController kinematicController;

private enum ControlState { Null, UnderDirectControl, UnityPathfinding, ACTurning };
private ControlState controlState = ControlState.Null;


private void Update ()
{
// Update what our current control state is
UpdateControlState ();

// Move the character according to the current control state
UpdateMovement ();
}


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:
UpdateDirectInput ();
break;

case ControlState.UnityPathfinding:
UpdatePathfindInput ();
break;

case ControlState.ACTurning:
UpdateJustTurningInput ();
break;
}
}


private void UpdateDirectInput ()
{
// Pass inputs to controller as normal

PlayerCharacterInputs characterInputs = new PlayerCharacterInputs();

// Build the CharacterInputs struct
characterInputs.MoveAxisForward = Input.GetAxisRaw ("Vertical");
characterInputs.MoveAxisRight = Input.GetAxisRaw ("Horizontal");
characterInputs.CameraRotation = Camera.main.transform.rotation;
characterInputs.JumpDown = Input.GetKeyDown (KeyCode.Space);
characterInputs.CrouchDown = Input.GetKeyDown (KeyCode.C);
characterInputs.CrouchUp = Input.GetKeyUp (KeyCode.C);

// Apply inputs to character
kinematicController.SetInputs (ref characterInputs);
}


private void UpdatePathfindInput ()
{
// Read the AC.Char script's GetTargetPosition and GetTargetRotation methods to dictate how the Controller / Motor should be affected

Vector3 targetPosition = characterAC.GetTargetPosition ();
Vector3 targetDirection = (targetPosition - kinematicController.Motor.TransientPosition).normalized;

KinematicCharacterController.Examples.AICharacterInputs inputs = new KinematicCharacterController.Examples.AICharacterInputs ();

inputs.MoveVector = targetDirection;
kinematicController.SetInputs (ref inputs);

kinematicController.Motor.RotateCharacter (characterAC.GetTargetRotation ());
}


public void UpdateJustTurningInput ()
{
// Stop regular input, halt movement, and use GetFrameRotation to manually enforce the per-frame rotation

KinematicCharacterController.Examples.AICharacterInputs inputs = new KinematicCharacterController.Examples.AICharacterInputs ();
kinematicController.SetInputs (ref inputs);

kinematicController.Motor.BaseVelocity = Vector3.zero;
kinematicController.Motor.SetRotation (characterAC.GetFrameRotation ());

}


private void OnTeleport ()
{
// This function is called by the Char script whenever the character has been teleported.

kinematicController.Motor.BaseVelocity = Vector3.zero;
kinematicController.Motor.SetPosition (characterAC.GetTargetPosition ());
kinematicController.Motor.SetRotation (characterAC.GetTargetRotation ());

if (kinematicController.OrientationMethod == OrientationMethod.TowardsCamera)
{
ACDebug.LogWarning ("Setting rotation to " + characterAC.GetTargetRotation () + ", but may not stick since the Orienation Method is Towards Camera.", gameObject);
}
}

}