You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HighGroundRoyaleNetcode/Assets/Scripts/Gameplay/GameplayObjects/Character/EdgePanningController.cs

158 lines
5.4 KiB
C#

using UnityEngine;
using Cinemachine;
using System.Collections;
using Unity.BossRoom.CameraUtils;
public class EdgePanningController : MonoBehaviour
{
public CinemachineFreeLook virtualCamera;
private CinemachineCameraOffset cameraOffset;
private Coroutine shakeCoroutine;
public float edgeThreshold = 50f; // Edge detection distance from screen edges
public float resetRadiusPercentage = 3f; // Center reset radius in percentage of screen
public float panSpeed = 0.1f; // How much to offset per frame
public float resetSpeed = 2f; // Speed of resetting panning
public Vector2 panLimit = new Vector2(0.5f, 0.5f); // Max panning limit (x, y)
private Vector3 defaultOffset;
private Vector3 panningOffset;
private bool isPanning = false;
private bool targetFound = false;
private bool shouldReset = false; // Flag to trigger reset immediately
private Transform targetCharacter; // The character the camera follows
private void Start()
{
cameraOffset = virtualCamera.GetComponent<CinemachineCameraOffset>();
if (cameraOffset == null)
{
Debug.LogError("[EdgePanningController] No CinemachineCameraOffset component found! Add it to the FreeLook Camera.");
return;
}
defaultOffset = cameraOffset.m_Offset;
panningOffset = defaultOffset;
}
private void Awake()
{
CameraController.OnCameraAttached += SetTargetCharacter;
}
private void OnDestroy()
{
CameraController.OnCameraAttached -= SetTargetCharacter;
}
private void SetTargetCharacter(Transform characterTransform)
{
targetCharacter = characterTransform.parent;
targetFound = true;
}
private void Update()
{
if (targetFound)
HandleEdgePanning();
}
private void HandleEdgePanning()
{
if (targetCharacter == null) return;
Vector3 newOffset = panningOffset;
Vector3 mousePos = Input.mousePosition;
float screenWidth = Screen.width;
float screenHeight = Screen.height;
// Center Reset Radius (3% of screen size)
float resetRadiusX = screenWidth * (resetRadiusPercentage / 100f);
float resetRadiusY = screenHeight * (resetRadiusPercentage / 100f);
Vector2 screenCenter = new Vector2(screenWidth / 2, screenHeight / 2);
bool isNearCenter = Mathf.Abs(mousePos.x - screenCenter.x) <= resetRadiusX &&
Mathf.Abs(mousePos.y - screenCenter.y) <= resetRadiusY;
bool isHoveringTarget = IsCursorOverTargetCharacter();
// ✅ If the cursor touches the center or target **even for a millisecond**, trigger reset
if (isNearCenter || isHoveringTarget)
{
shouldReset = true; // Set the flag so reset starts immediately
}
// ✅ If reset is triggered, smoothly return to default position
if (shouldReset && isPanning)
{
cameraOffset.m_Offset = Vector3.Lerp(cameraOffset.m_Offset, defaultOffset, Time.deltaTime * resetSpeed);
// ✅ Once back to default, stop resetting and reset flag
if (Vector3.Distance(cameraOffset.m_Offset, defaultOffset) < 0.01f)
{
isPanning = false;
panningOffset = defaultOffset;
shouldReset = false; // Reset flag
}
return;
}
// If cursor is near the edges, start panning (up to limit)
if (mousePos.x <= edgeThreshold) newOffset.x = Mathf.Max(defaultOffset.x - panLimit.x, newOffset.x - panSpeed);
if (mousePos.x >= screenWidth - edgeThreshold) newOffset.x = Mathf.Min(defaultOffset.x + panLimit.x, newOffset.x + panSpeed);
if (mousePos.y <= edgeThreshold) newOffset.y = Mathf.Max(defaultOffset.y - panLimit.y, newOffset.y - panSpeed);
if (mousePos.y >= screenHeight - edgeThreshold) newOffset.y = Mathf.Min(defaultOffset.y + panLimit.y, newOffset.y + panSpeed);
if (newOffset != panningOffset)
{
isPanning = true;
}
cameraOffset.m_Offset = Vector3.Lerp(cameraOffset.m_Offset, newOffset, Time.deltaTime * 3f);
panningOffset = cameraOffset.m_Offset;
}
private bool IsCursorOverTargetCharacter()
{
if (targetCharacter == null) return false;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity))
{
return hit.transform == targetCharacter;
}
return false;
}
public void ShakeCamera(float duration = 0.3f, float magnitude = 0.2f)
{
if (shakeCoroutine != null)
{
StopCoroutine(shakeCoroutine);
}
shakeCoroutine = StartCoroutine(ShakeRoutine(duration, magnitude));
}
private IEnumerator ShakeRoutine(float duration, float magnitude)
{
float elapsed = 0f;
Vector3 originalOffset = defaultOffset;
while (elapsed < duration)
{
float x = Random.Range(-1f, 1f) * magnitude;
float y = Random.Range(-1f, 1f) * magnitude;
float z = Random.Range(-1f, 1f) * magnitude;
cameraOffset.m_Offset = originalOffset + new Vector3(x, y, z);
elapsed += Time.deltaTime;
yield return null;
}
cameraOffset.m_Offset = originalOffset; // Reset to default offset
}
}