Crank controller was a pretty tough script to design. The core problem to solve was acquiring the currentRotationPercentage, which was an ANGLE converting to a percentage. Once we had this currentRotationPercentage, we could properly get input from both keys and controllers, and rotate the crank smoothly, even controlling its speed, starting angle, etc.. Very useful!
using UnityEngine;
using UnityEngine.InputSystem;
public class CrankController : MonoBehaviour
{
[Header("Input Actions")]
[SerializeField] private InputActionAsset lightControllerControls;
private InputAction interactAction;
private InputAction rotateAction;
public GameObject player;
public Animator mokAnimator;
public GameObject spotlight;
public GameObject crank;
private float rotationSpeed = 0.2f;
public bool isInteractingWithCrank = false;
private float minRotationAngle = 0f;
private float maxRotationAngle = 180f;
private PlayerController playerController;
private Quaternion initialPlayerRotation;
private float initialRotationPercentage;
public float currentRotationPercentage = 0.5f;
// FOR Mok's crank animation
// detects if crank is being turned
public bool crankTurning = false;
// detects which animation should play based on whether rotation percentage increased or decreased
public bool rotationPercentageChange;
// AUDIO STUFF
public AudioSource crankAudioSource;
public AudioClip crankSound;
private void Awake()
{
playerController = player.GetComponent<PlayerController>();
// Set up the input actions
interactAction = lightControllerControls.FindAction("Interact");
rotateAction = lightControllerControls.FindAction("RotateLight");
}
void OnEnable()
{
rotateAction.Enable();
}
void OnDisable()
{
rotateAction.Disable();
}
void Update()
{
if (interactAction.triggered && !playerController.isInteracting && crank.GetComponent<Crank>().canCrank)
{
isInteractingWithCrank = playerController.isInteracting;
isInteractingWithCrank = !isInteractingWithCrank;
playerController.canMoveHorizontally = false;
if (isInteractingWithCrank)
{
initialPlayerRotation = player.transform.rotation;
initialRotationPercentage = GetLightRotationPercentage();
}
}
if (isInteractingWithCrank)
{
isInteractingWithCrank = playerController.isInteracting;
player.transform.rotation = initialPlayerRotation;
float rotationInput = rotateAction.ReadValue<float>();
if (Mathf.Abs(rotationInput) > 0.01f) // You can adjust the threshold to your liking
{
currentRotationPercentage += rotationInput * rotationSpeed * Time.deltaTime;
currentRotationPercentage = Mathf.Clamp01(currentRotationPercentage);
RotateCrank(currentRotationPercentage);
RotateLight(currentRotationPercentage);
PlayCrankSound();
if (initialRotationPercentage == currentRotationPercentage)
{
crankTurning = false;
}
else
{
crankTurning = true;
if (initialRotationPercentage < currentRotationPercentage)
{
rotationPercentageChange = true;
Debug.Log("Rotation is increasing");
}
if (initialRotationPercentage > currentRotationPercentage)
{
rotationPercentageChange = false;
Debug.Log("Rotation is decreasing");
}
}
}
else
{
PauseCrankSound();
}
}
else
{
playerController.canMoveHorizontally = true;
PauseCrankSound();
}
}
private void RotateCrank(float rotationPercentage)
{
float newZ = Mathf.Lerp(360f - maxRotationAngle, 360f - minRotationAngle, rotationPercentage);
crank.transform.localEulerAngles = new Vector3(0, 0, newZ);
}
private void RotateLight(float rotationPercentage)
{
float newX = Mathf.Lerp(minRotationAngle, maxRotationAngle, rotationPercentage);
spotlight.transform.localEulerAngles = new Vector3(newX, -90f, -90f);
}
public float GetLightRotationPercentage()
{
float currentX = spotlight.transform.localEulerAngles.x;
return (currentX - minRotationAngle) / (maxRotationAngle - minRotationAngle);
}
private void PlayCrankSound()
{
if (crankSound != null && !crankAudioSource.isPlaying)
{
crankAudioSource.clip = crankSound;
crankAudioSource.Play();
}
}
private void PauseCrankSound()
{
if (crankSound != null && crankAudioSource.isPlaying)
{
crankAudioSource.Pause();
}
}
private void StopCrankSound()
{
if (crankSound != null && crankAudioSource.isPlaying)
{
crankAudioSource.Stop();
}
}
}