mirror of
https://github.com/BotChain-Robots/ui.git
synced 2026-07-08 15:07:22 +02:00
Added camera movement and home button to bring user back to module structure
This commit is contained in:
252
Assets/UserCameraControl.cs
Normal file
252
Assets/UserCameraControl.cs
Normal file
@@ -0,0 +1,252 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user