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

282 lines
8.9 KiB
C#

using UnityEngine;
using Cinemachine;
using System.Collections;
4 months ago
using Unity.BossRoom.CameraUtils;
public class EdgePanningController : MonoBehaviour
{
[Header("Camera References")]
[Tooltip("Assign your Cinemachine FreeLook here.")]
public CinemachineFreeLook virtualCamera;
// This is the hero (or unit) we want to eventually recenter on.
private Transform targetCharacter;
// We create (or assign) a separate GameObject that the FreeLook will Follow/LookAt.
private Transform cameraTarget;
[Header("Edge Panning Settings")]
[Tooltip("Distance in pixels from screen edge to start panning.")]
public float edgeThreshold = 10f;
[Tooltip("Pan speed in world units per second.")]
public float panSpeed = 20f;
[Tooltip("Maximum distance (in world units) the camera can pan away from the hero.")]
public float maxPanDistance = 30f;
[Header("Centering / Return Settings")]
[Tooltip("Delay (seconds) after panning stops before auto-centering on hero begins.")]
public float returnDelay = 0.5f;
[Tooltip("Speed at which cameraTarget moves back to hero when auto-returning.")]
public float returnSpeed = 15f;
// Smoothing for the automatic “return to hero” motion
[Header("Smoothing")]
[Tooltip("Time for SmoothDamp when auto-centering back to hero.")]
public float smoothTime = 0.1f;
// State-tracking
4 months ago
private bool isPanning = false;
private bool isReturning = false;
private float timeSincePanStopped = 0f;
private Vector3 currentVelocity = Vector3.zero;
// Free camera (debug) mode
private bool isFreeRoamMode = false;
[Tooltip("Speed for free-roam mode.")]
public float freeRoamSpeed = 20f;
4 months ago
private void Awake()
{
CameraController.OnCameraAttached += SetTargetCharacter;
}
4 months ago
private void OnDestroy()
{
CameraController.OnCameraAttached -= SetTargetCharacter;
}
private void Start()
{
if (virtualCamera == null)
{
Debug.LogError("EdgePanningController: You must assign a CinemachineFreeLook to virtualCamera.");
enabled = false;
return;
}
// Initially, well leave cameraTarget null until we know who the hero is.
}
/// <summary>
/// Called (by BossRooms CameraController) when the hero/character is attached.
/// </summary>
4 months ago
private void SetTargetCharacter(Transform characterTransform)
{
// characterTransform is actually the child transform of the player prefab.
// We'll treat its parent as the "hero root".
4 months ago
targetCharacter = characterTransform.parent;
// Create a new, empty GameObject to serve as the cameras focus point.
if (cameraTarget == null)
{
GameObject go = new GameObject("CameraTarget");
cameraTarget = go.transform;
}
// Place the cameraTarget initially on the heros position.
cameraTarget.position = targetCharacter.position;
// Tell the FreeLook to Follow/LookAt this cameraTarget
virtualCamera.Follow = cameraTarget;
virtualCamera.LookAt = cameraTarget;
}
private void LateUpdate()
{
// Toggle free-roam for debugging
if (Input.GetKeyDown(KeyCode.Backspace))
{
ToggleFreeRoamMode();
}
if (isFreeRoamMode)
{
HandleFreeRoam();
return;
}
if (targetCharacter == null || cameraTarget == null)
return;
HandleDotaStylePanning();
}
private void HandleDotaStylePanning()
{
Vector3 mousePos = Input.mousePosition;
Vector3 panDirection = Vector3.zero;
bool nearEdge = false;
// LEFT EDGE?
if (mousePos.x <= edgeThreshold)
{
float strength = 1f - (mousePos.x / edgeThreshold);
panDirection.x = -strength;
nearEdge = true;
}
// RIGHT EDGE?
else if (mousePos.x >= Screen.width - edgeThreshold)
{
float strength = 1f - ((Screen.width - mousePos.x) / edgeThreshold);
panDirection.x = strength;
nearEdge = true;
}
// BOTTOM EDGE?
if (mousePos.y <= edgeThreshold)
4 months ago
{
float strength = 1f - (mousePos.y / edgeThreshold);
panDirection.z = -strength;
nearEdge = true;
4 months ago
}
// TOP EDGE?
else if (mousePos.y >= Screen.height - edgeThreshold)
4 months ago
{
float strength = 1f - ((Screen.height - mousePos.y) / edgeThreshold);
panDirection.z = strength;
nearEdge = true;
}
if (nearEdge)
{
// We are actively panning
isPanning = true;
isReturning = false;
timeSincePanStopped = 0f;
// Compute a world-space direction on the XZ plane relative to cameras facing
Vector3 forward = virtualCamera.transform.forward;
forward.y = 0;
forward.Normalize();
Vector3 right = virtualCamera.transform.right;
right.y = 0;
right.Normalize();
Vector3 worldPanDir = (right * panDirection.x + forward * panDirection.z).normalized;
// Move cameraTarget along that direction (scaled by panSpeed and deltaTime)
Vector3 newPos = cameraTarget.position + worldPanDir * panSpeed * Time.deltaTime;
// Clamp so cameraTarget never goes further than maxPanDistance from the hero
Vector3 offsetFromHero = newPos - targetCharacter.position;
if (offsetFromHero.magnitude > maxPanDistance)
{
offsetFromHero = offsetFromHero.normalized * maxPanDistance;
newPos = targetCharacter.position + offsetFromHero;
}
cameraTarget.position = newPos;
}
else
{
// No edge-pan input. Start the return-to-hero timer if we were panning.
if (isPanning)
4 months ago
{
isPanning = false;
timeSincePanStopped = 0f;
}
timeSincePanStopped += Time.deltaTime;
// After returnDelay, smoothly move cameraTarget back toward hero
if (timeSincePanStopped >= returnDelay && !isReturning)
{
isReturning = true;
}
if (isReturning)
{
// Smoothly interpolate cameraTarget back to the heros position
Vector3 targetPos = targetCharacter.position;
cameraTarget.position = Vector3.SmoothDamp(
cameraTarget.position,
targetPos,
ref currentVelocity,
smoothTime,
returnSpeed
);
// If close enough, stop returning
if (Vector3.Distance(cameraTarget.position, targetPos) < 0.1f)
{
cameraTarget.position = targetPos;
isReturning = false;
currentVelocity = Vector3.zero;
}
4 months ago
}
}
// Double-click to instantly center on hero
if (Input.GetMouseButtonDown(0) && Input.GetMouseButtonDown(0))
4 months ago
{
CenterOnHero();
}
// Space bar to instantly center on hero
if (Input.GetKeyDown(KeyCode.Space))
{
CenterOnHero();
4 months ago
}
}
private void CenterOnHero()
4 months ago
{
if (targetCharacter == null || cameraTarget == null)
return;
cameraTarget.position = targetCharacter.position;
isPanning = false;
isReturning = false;
timeSincePanStopped = returnDelay; // So it wont start returning immediately
currentVelocity = Vector3.zero;
}
private void ToggleFreeRoamMode()
{
isFreeRoamMode = !isFreeRoamMode;
if (isFreeRoamMode)
4 months ago
{
// Detach camera from any Follow target
virtualCamera.Follow = null;
virtualCamera.LookAt = null;
}
else
{
// Reattach to our cameraTarget
if (cameraTarget != null)
{
virtualCamera.Follow = cameraTarget;
virtualCamera.LookAt = cameraTarget;
}
CenterOnHero();
4 months ago
}
}
private void HandleFreeRoam()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float upDown = 0f;
if (Input.GetKey(KeyCode.E)) upDown = 1f;
else if (Input.GetKey(KeyCode.Q)) upDown = -1f;
Vector3 move = new Vector3(h, upDown, v);
virtualCamera.transform.position += virtualCamera.transform.rotation * move * freeRoamSpeed * Time.deltaTime;
}
// Optional: If you have camera shake functionality, you'd need to re-implement it differently,
// because we no longer use CinemachineCameraOffset for panning. Left out here for brevity.
}