193 lines
8.8 KiB
C#
193 lines
8.8 KiB
C#
using System; // For Action event
|
|
using UnityEngine;
|
|
|
|
namespace OnlyScove.Scripts
|
|
{
|
|
public class CameraController : MonoBehaviour
|
|
{
|
|
public enum CameraViewMode { ThirdPerson, FirstPerson }
|
|
|
|
[SerializeField] InputReader inputReader;
|
|
[SerializeField] Transform followTarget; // Player's root for TPV
|
|
[SerializeField] float positionSmoothTime = 0.12f;
|
|
[SerializeField] float rotationSmoothTime = 5f;
|
|
[SerializeField] Vector2 framingOffset;
|
|
|
|
[Header("Components")]
|
|
[SerializeField] private CameraRotationHandler rotationHandler = new CameraRotationHandler();
|
|
[SerializeField] private CameraZoomHandler zoomHandler = new CameraZoomHandler();
|
|
[SerializeField] private CameraCollisionHandler collisionHandler = new CameraCollisionHandler();
|
|
[SerializeField] private CameraOcclusionTransparency occlusionTransparency = new CameraOcclusionTransparency();
|
|
[SerializeField] private CameraDynamicFOV dynamicFOV = new CameraDynamicFOV();
|
|
[SerializeField] private CameraCharacterFading characterFading = new CameraCharacterFading();
|
|
[SerializeField] private CameraSideBias sideBias = new CameraSideBias();
|
|
[SerializeField] private CameraShakeManager shakeManager = new CameraShakeManager();
|
|
|
|
[Header("First Person View Settings")]
|
|
[SerializeField] Transform fpvTarget; // Specific transform on the player (e.g., eye level)
|
|
[SerializeField] float fpvPositionSmoothTime = 0.05f;
|
|
[SerializeField] float fpvRotationSmoothTime = 0.05f;
|
|
[SerializeField] float fpvFOV = 80f;
|
|
[SerializeField] float transitionDuration = 0.3f;
|
|
[SerializeField] float tpvBaseFOV = 60f; // Existing base FOV for TPV
|
|
|
|
private Vector3 _currentVelocity;
|
|
private Camera _cam;
|
|
private CameraViewMode _currentViewMode = CameraViewMode.ThirdPerson;
|
|
private CameraViewMode _targetViewMode = CameraViewMode.ThirdPerson;
|
|
private float _transitionTimer = 0f;
|
|
private bool _inTransition = false;
|
|
|
|
// Properties to get current smoothing values based on view mode
|
|
private float CurrentPositionSmoothTime => _currentViewMode == CameraViewMode.FirstPerson ? fpvPositionSmoothTime : positionSmoothTime;
|
|
private float CurrentRotationSmoothTime => _currentViewMode == CameraViewMode.FirstPerson ? fpvRotationSmoothTime : rotationSmoothTime;
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (inputReader != null)
|
|
{
|
|
inputReader.OnToggleViewEvent += ToggleCameraView;
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (inputReader != null)
|
|
{
|
|
inputReader.OnToggleViewEvent -= ToggleCameraView;
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_cam = GetComponent<Camera>();
|
|
Cursor.visible = false;
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
|
|
rotationHandler.Initialize(transform);
|
|
dynamicFOV.Initialize(tpvBaseFOV: tpvBaseFOV, fpvFOV: fpvFOV); // Pass TPV and FPV base FOVs
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
HandleViewTransition();
|
|
|
|
if (inputReader != null)
|
|
{
|
|
// Input-related updates are handled differently based on view mode
|
|
rotationHandler.HandleRotation(inputReader, followTarget, CurrentRotationSmoothTime, _currentViewMode);
|
|
|
|
if (_currentViewMode == CameraViewMode.ThirdPerson)
|
|
{
|
|
zoomHandler.HandleZoom(inputReader);
|
|
sideBias.HandleSideBias(inputReader);
|
|
}
|
|
else
|
|
{
|
|
// Disable side bias and zoom in FPV
|
|
sideBias.HandleSideBias(null); // Pass null to effectively disable
|
|
zoomHandler.HandleZoom(null); // Pass null to effectively disable
|
|
}
|
|
dynamicFOV.HandleDynamicFOV(_cam, inputReader, _currentViewMode);
|
|
}
|
|
|
|
Vector3 focusPosition;
|
|
float targetDistance;
|
|
|
|
if (_currentViewMode == CameraViewMode.ThirdPerson)
|
|
{
|
|
// TPV specific calculations
|
|
transform.rotation = rotationHandler.CurrentRotation; // Set rotation from handler
|
|
focusPosition = followTarget.position + rotationHandler.CurrentRotation * new Vector3(framingOffset.x + sideBias.CurrentSideBias, framingOffset.y, 0);
|
|
targetDistance = collisionHandler.CheckCollision(focusPosition, rotationHandler.CurrentRotation, zoomHandler.CurrentDistance, zoomHandler.MinDistance);
|
|
characterFading.HandleCharacterFading(targetDistance);
|
|
occlusionTransparency.HandleTransparency(transform, focusPosition);
|
|
}
|
|
else // FirstPerson
|
|
{
|
|
// FPV specific calculations
|
|
// Rotation is derived from fpvTarget, not input from rotationHandler
|
|
transform.rotation = fpvTarget.rotation; // Directly set FPV rotation
|
|
focusPosition = fpvTarget.position;
|
|
targetDistance = 0; // FPV has no distance to player
|
|
|
|
// Disable TPV-specific effects
|
|
characterFading.HandleCharacterFading(0); // Fully opaque character in FPV
|
|
occlusionTransparency.HandleTransparency(transform, fpvTarget.position); // Can still have occlusion transparency for environment in FPV
|
|
}
|
|
|
|
// Calculate target position using the currently set transform.rotation
|
|
Vector3 targetPosition = focusPosition - transform.rotation * new Vector3(0, 0, targetDistance);
|
|
|
|
// Handle camera shake
|
|
shakeManager.HandleShake();
|
|
|
|
// Apply final position and rotation
|
|
transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref _currentVelocity, CurrentPositionSmoothTime) + shakeManager.ShakeOffset;
|
|
}
|
|
|
|
private void ToggleCameraView()
|
|
{
|
|
if (_inTransition) return; // Prevent multiple toggles during transition
|
|
|
|
_targetViewMode = (_currentViewMode == CameraViewMode.ThirdPerson) ? CameraViewMode.FirstPerson : CameraViewMode.ThirdPerson;
|
|
_inTransition = true;
|
|
_transitionTimer = 0f;
|
|
}
|
|
|
|
private void HandleViewTransition()
|
|
{
|
|
if (!_inTransition) return;
|
|
|
|
_transitionTimer += Time.deltaTime;
|
|
float t = _transitionTimer / transitionDuration;
|
|
t = Mathf.Clamp01(t); // Clamp t between 0 and 1
|
|
|
|
// Smoothly interpolate parameters during transition
|
|
if (_currentViewMode == CameraViewMode.ThirdPerson && _targetViewMode == CameraViewMode.FirstPerson)
|
|
{
|
|
// TPV -> FPV transition
|
|
// Interpolate FOV
|
|
_cam.fieldOfView = Mathf.Lerp(dynamicFOV.CurrentTpvBaseFOV, fpvFOV, t);
|
|
// Interpolate position and rotation
|
|
transform.position = Vector3.Lerp(transform.position, fpvTarget.position, t);
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, fpvTarget.rotation, t);
|
|
}
|
|
else if (_currentViewMode == CameraViewMode.FirstPerson && _targetViewMode == CameraViewMode.ThirdPerson)
|
|
{
|
|
// FPV -> TPV transition
|
|
// Interpolate FOV
|
|
_cam.fieldOfView = Mathf.Lerp(fpvFOV, dynamicFOV.CurrentTpvBaseFOV, t);
|
|
// For position and rotation, we'll let the TPV logic take over after transition.
|
|
// If a smooth exit from FPV to TPV is desired for position/rotation,
|
|
// more complex calculations would be needed here to store TPV target position/rotation at the start.
|
|
}
|
|
|
|
if (t >= 1f)
|
|
{
|
|
_currentViewMode = _targetViewMode;
|
|
_inTransition = false;
|
|
// Re-initialize rotation handler for new view mode context
|
|
rotationHandler.Initialize(transform);
|
|
|
|
// Ensure FOV is set correctly at the end of transition
|
|
_cam.fieldOfView = (_currentViewMode == CameraViewMode.FirstPerson) ? fpvFOV : dynamicFOV.CurrentTpvBaseFOV;
|
|
|
|
// For FPV, ensure camera matches fpvTarget immediately after transition
|
|
// This is already handled by the `transform.position = Vector3.SmoothDamp...` and `transform.rotation = fpvTarget.rotation` in Update
|
|
}
|
|
}
|
|
|
|
public void Shake(float intensity, float duration)
|
|
{
|
|
shakeManager.Shake(intensity, duration);
|
|
}
|
|
|
|
public void TriggerFallImpactShake(float fallHeight)
|
|
{
|
|
shakeManager.TriggerFallImpactShake(fallHeight);
|
|
}
|
|
|
|
public Quaternion PlanarRotation => rotationHandler.PlanarRotation;
|
|
}
|
|
} |