mirror of
https://github.com/BotChain-Robots/ui.git
synced 2026-07-08 15:07:22 +02:00
252 lines
7.0 KiB
C#
252 lines
7.0 KiB
C#
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using System.Collections;
|
|
|
|
public class UserCameraControl : MonoBehaviour
|
|
{
|
|
[Header("References")]
|
|
public Camera mainCamera;
|
|
|
|
[Header("Cursors")]
|
|
public Texture2D handCursor;
|
|
public Texture2D eyeCursor;
|
|
public Vector2 cursorHotspot = Vector2.zero;
|
|
|
|
[Header("Move")]
|
|
public float panSpeed = 3.5f; // units/sec
|
|
public float zoomSpeed = 6f; // scroll multiplier
|
|
public float moveSmoothTime = 0.12f; // higher = snappier, lower = floatier
|
|
|
|
[Header("Orbit")]
|
|
public float orbitSpeed = 180f; // degrees/sec per pixel-ish delta
|
|
public float minPitch = -20f;
|
|
public float maxPitch = 80f;
|
|
public float orbitSmoothTime = 0.08f;
|
|
|
|
[Header("Look / Home Smooth")]
|
|
public float lookAtDuration = 0.25f;
|
|
public float homeDuration = 0.35f;
|
|
|
|
// internal angles
|
|
float yaw;
|
|
float pitch;
|
|
|
|
// rotation smoothing
|
|
Vector2 lastMouse;
|
|
bool orbiting;
|
|
float yawDeltaVel, pitchDeltaVel;
|
|
float yawDeltaSmoothed, pitchDeltaSmoothed;
|
|
|
|
// movement smoothing
|
|
Vector3 targetPosition;
|
|
Vector3 positionVel;
|
|
|
|
Coroutine lookRoutine;
|
|
Coroutine homeRoutine;
|
|
|
|
void Awake()
|
|
{
|
|
if (!mainCamera) mainCamera = Camera.main;
|
|
|
|
targetPosition = transform.position;
|
|
SyncAnglesFromTransform();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (EventSystem.current && EventSystem.current.IsPointerOverGameObject())
|
|
{
|
|
SetCursor(null);
|
|
return;
|
|
}
|
|
|
|
HandleKeyboardPanAndZoom();
|
|
HandleOrbit();
|
|
|
|
// smooth position every frame
|
|
transform.position = Vector3.SmoothDamp(
|
|
transform.position,
|
|
targetPosition,
|
|
ref positionVel,
|
|
moveSmoothTime,
|
|
Mathf.Infinity,
|
|
Time.unscaledDeltaTime
|
|
);
|
|
|
|
if (!Input.GetMouseButton(0) && !Input.GetMouseButton(1))
|
|
SetCursor(null);
|
|
}
|
|
|
|
void HandleOrbit()
|
|
{
|
|
if (Input.GetMouseButtonDown(1))
|
|
{
|
|
orbiting = true;
|
|
SetCursor(eyeCursor);
|
|
|
|
// stop any scripted rotation so user has control
|
|
StopLookRoutine();
|
|
|
|
SyncAnglesFromTransform();
|
|
lastMouse = (Vector2)Input.mousePosition;
|
|
|
|
yawDeltaSmoothed = pitchDeltaSmoothed = 0f;
|
|
yawDeltaVel = pitchDeltaVel = 0f;
|
|
}
|
|
|
|
if (Input.GetMouseButtonUp(1))
|
|
orbiting = false;
|
|
|
|
if (!orbiting) return;
|
|
|
|
float dt = Time.unscaledDeltaTime;
|
|
|
|
Vector2 mouse = (Vector2)Input.mousePosition;
|
|
Vector2 delta = mouse - lastMouse;
|
|
lastMouse = mouse;
|
|
|
|
float targetYawDelta = delta.x * orbitSpeed * dt;
|
|
float targetPitchDelta = -delta.y * orbitSpeed * dt;
|
|
|
|
yawDeltaSmoothed = Mathf.SmoothDamp(yawDeltaSmoothed, targetYawDelta, ref yawDeltaVel, orbitSmoothTime);
|
|
pitchDeltaSmoothed = Mathf.SmoothDamp(pitchDeltaSmoothed, targetPitchDelta, ref pitchDeltaVel, orbitSmoothTime);
|
|
|
|
yaw += yawDeltaSmoothed;
|
|
pitch += pitchDeltaSmoothed;
|
|
pitch = Mathf.Clamp(pitch, minPitch, maxPitch);
|
|
|
|
transform.rotation = Quaternion.Euler(pitch, yaw, 0f);
|
|
}
|
|
|
|
void HandleKeyboardPanAndZoom()
|
|
{
|
|
float dt = Time.unscaledDeltaTime;
|
|
|
|
Vector3 right = transform.right;
|
|
Vector3 up = transform.up;
|
|
|
|
Vector3 move = Vector3.zero;
|
|
if (Input.GetKey(KeyCode.W)) move += up;
|
|
if (Input.GetKey(KeyCode.S)) move -= up;
|
|
if (Input.GetKey(KeyCode.D)) move += right;
|
|
if (Input.GetKey(KeyCode.A)) move -= right;
|
|
|
|
float scroll = Input.mouseScrollDelta.y;
|
|
if (Mathf.Abs(scroll) > 0.001f)
|
|
move += transform.forward * (scroll * zoomSpeed);
|
|
|
|
if (move.sqrMagnitude < 0.0000001f) return;
|
|
|
|
// write into targetPosition instead of snapping transform.position
|
|
targetPosition += move * panSpeed * dt;
|
|
}
|
|
|
|
// -------- Public API used by ModuleSelector / UI --------
|
|
|
|
public void LookAtTarget(Transform target)
|
|
{
|
|
if (target == null) return;
|
|
|
|
StopLookRoutine();
|
|
lookRoutine = StartCoroutine(SmoothLookAt(target.position, lookAtDuration));
|
|
}
|
|
|
|
public void FindModuleStructure()
|
|
{
|
|
GameObject topologyRoot = GameObject.Find("GeneratedTopology");
|
|
if (topologyRoot == null) return;
|
|
|
|
Vector3 focus = topologyRoot.transform.position;
|
|
|
|
float defaultYaw = 0f;
|
|
float defaultPitch = 20f;
|
|
float defaultDistance = 10f;
|
|
|
|
float clampedPitch = Mathf.Clamp(defaultPitch, minPitch, maxPitch);
|
|
Quaternion rot = Quaternion.Euler(clampedPitch, defaultYaw, 0f);
|
|
Vector3 homePos = focus - (rot * Vector3.forward) * defaultDistance;
|
|
|
|
StopLookRoutine();
|
|
if (homeRoutine != null) StopCoroutine(homeRoutine);
|
|
homeRoutine = StartCoroutine(SmoothMoveAndRotate(homePos, rot, homeDuration));
|
|
}
|
|
|
|
// -------- Smooth routines --------
|
|
|
|
IEnumerator SmoothLookAt(Vector3 targetPoint, float duration)
|
|
{
|
|
Quaternion start = transform.rotation;
|
|
Quaternion end = Quaternion.LookRotation((targetPoint - transform.position).normalized, Vector3.up);
|
|
|
|
float t = 0f;
|
|
while (t < 1f)
|
|
{
|
|
t += Time.unscaledDeltaTime / Mathf.Max(0.0001f, duration);
|
|
transform.rotation = Quaternion.Slerp(start, end, t);
|
|
yield return null;
|
|
}
|
|
|
|
SyncAnglesFromTransform();
|
|
lookRoutine = null;
|
|
}
|
|
|
|
IEnumerator SmoothMoveAndRotate(Vector3 endPos, Quaternion endRot, float duration)
|
|
{
|
|
Vector3 startPos = transform.position;
|
|
Quaternion startRot = transform.rotation;
|
|
|
|
float t = 0f;
|
|
while (t < 1f)
|
|
{
|
|
t += Time.unscaledDeltaTime / Mathf.Max(0.0001f, duration);
|
|
|
|
// position
|
|
Vector3 pos = Vector3.Lerp(startPos, endPos, t);
|
|
transform.position = pos;
|
|
|
|
// rotation
|
|
transform.rotation = Quaternion.Slerp(startRot, endRot, t);
|
|
|
|
yield return null;
|
|
}
|
|
|
|
// keep move smoothing target aligned so it doesn't “fight” after home
|
|
targetPosition = transform.position;
|
|
positionVel = Vector3.zero;
|
|
|
|
SyncAnglesFromTransform();
|
|
homeRoutine = null;
|
|
}
|
|
|
|
void StopLookRoutine()
|
|
{
|
|
if (lookRoutine != null)
|
|
{
|
|
StopCoroutine(lookRoutine);
|
|
lookRoutine = null;
|
|
}
|
|
}
|
|
|
|
// -------- Helpers --------
|
|
|
|
void SyncAnglesFromTransform()
|
|
{
|
|
Vector3 e = transform.eulerAngles;
|
|
yaw = NormalizeAngle(e.y);
|
|
pitch = NormalizeAngle(e.x);
|
|
pitch = Mathf.Clamp(pitch, minPitch, maxPitch);
|
|
transform.rotation = Quaternion.Euler(pitch, yaw, 0f);
|
|
}
|
|
|
|
static float NormalizeAngle(float angle)
|
|
{
|
|
angle %= 360f;
|
|
if (angle > 180f) angle -= 360f;
|
|
return angle;
|
|
}
|
|
|
|
void SetCursor(Texture2D tex)
|
|
{
|
|
Cursor.SetCursor(tex, cursorHotspot, CursorMode.Auto);
|
|
}
|
|
} |