Hi, I used this series:
Everything works fine. But I’ve tried multiple times to add a feature that I can’t figure out. Basically, when the player is moving for more than a second, I want the camera to automatically pan around behind the player and continue to do so until the player stops. But if the player stops running before the camera is righted, I want the camera to stop panning. Here are my scripts
CameraManager.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class CameraManager : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float zoom;
[SerializeField] private MouseSensitivity mouseSensitivity;
[SerializeField] private CameraAngle cameraAngle;
[SerializeField] private float autoRotateSpeed;
private CameraRotation cameraRotation;
private float distanceToPlayer;
private Vector2 input;
private void Awake() => distanceToPlayer = Vector3.Distance(transform.position, target.position);
public void Look(InputAction.CallbackContext context)
{
input = context.ReadValue<Vector2>();
}
private void Update()
{
cameraRotation.yaw += input.x * mouseSensitivity.horizontal * Time.deltaTime;
cameraRotation.pitch += input.x * mouseSensitivity.vertical * Time.deltaTime;
cameraRotation.pitch = Mathf.Clamp(cameraRotation.pitch, cameraAngle.min, cameraAngle.max);
}
private void LateUpdate()
{
AutoRotate();
transform.eulerAngles = new Vector3(cameraRotation.pitch, cameraRotation.yaw, 0.0f);
transform.position = target.position - transform.forward * distanceToPlayer / zoom;
}
}
[Serializable]
public struct MouseSensitivity
{
public float horizontal;
public float vertical;
}
public struct CameraRotation
{
public float pitch;
public float yaw;
}
[Serializable]
public struct CameraAngle
{
public float min;
public float max;
}
PlayerController.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
private CharacterController characterController;
private Camera mainCamera;
[SerializeField] private float jumpHeight;
[SerializeField] private float doubleJumpHeight;
[SerializeField] private float rotationSpeed = 500f;
[SerializeField] private Movement movement;
[SerializeField] private float speed;
[SerializeField] private int maxNumberOfJumps = 2;
[SerializeField] private float gravityStrength = 3.0F;
private static Vector2 input;
private static Vector3 direction;
private float gravity = -9.81F;
private float velocity;
private int numberOfJumps;
private void Awake()
{
characterController = GetComponent<CharacterController>();
mainCamera = Camera.main;
}
private void Update() {
ApplyRotation();
ApplyGravity();
ApplyMovement();
}
private void ApplyRotation()
{
if (input.sqrMagnitude == 0) return;
direction = Quaternion.Euler(0.0f, mainCamera.transform.eulerAngles.y, 0.0f) * new Vector3(input.x, 0.0f, input.y);
var targetRotation = Quaternion.LookRotation(direction, Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
}
private void ApplyMovement()
{
var targetSpeed = movement.isSprinting ? movement.speed * movement.multiplier : movement.speed;
movement.currentSpeed = Mathf.MoveTowards(movement.currentSpeed, targetSpeed, movement.acceleration * Time.deltaTime);
characterController.Move(direction * movement.currentSpeed * Time.deltaTime);
}
private void ApplyGravity()
{
if (IsGrounded() && velocity < 0.0F)
{
velocity = -1.0F;
} else
{
velocity += gravity * gravityStrength * Time.deltaTime;
}
direction.y = velocity;
}
public void Move(InputAction.CallbackContext context)
{
input = context.ReadValue<Vector2>();
direction = new Vector3(input.x, 0.0F, input.y);
}
public void Jump(InputAction.CallbackContext context)
{
if (!context.started) return;
if (!IsGrounded() && numberOfJumps >= maxNumberOfJumps) return;
if (numberOfJumps == 0) StartCoroutine(WaitForLanding());
numberOfJumps++;
if (numberOfJumps == 1) {
velocity = jumpHeight;
}
else
{
velocity = doubleJumpHeight;
}
}
public void Sprint(InputAction.CallbackContext context)
{
movement.isSprinting = context.started || context.performed;
}
private IEnumerator WaitForLanding()
{
yield return new WaitUntil(() => !IsGrounded());
yield return new WaitUntil(IsGrounded);
numberOfJumps = 0;
}
private bool IsGrounded() => characterController.isGrounded;
}
[Serializable]
public struct Movement
{
[HideInInspector] public bool isSprinting;
public float speed;
public float multiplier;
public float acceleration;
[HideInInspector] public float currentSpeed;
}