Files
OCTOPUS_TWIN-Demo/Assets/Scripts/Camera/OrbitalController.cs
2026-02-10 09:34:30 +09:00

424 lines
13 KiB
C#
Raw Blame History

using RTGLite;
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using DG.Tweening;
using System.Collections.Generic;
namespace OCTOPUS_TWIN
{
public enum ViewMode
{
PerspectiveView,
TopView
}
public struct OrbitState
{
public float elevation;
public float distance;
public float azimuth;
public Vector3 pivotPosition;
public Quaternion pivotRotation;
}
//TODO::Something... Util Functions
public class OrbitalController : MonoBehaviour
{
public ViewMode viewMode;
private Vector3 originValue;
private Vector3 originTargetPos;
private OrbitState perspectiveState;
private OrbitState orthoState;
private new Camera camera;
public Camera Camera { get { return camera; } }
public float moveSpeed;
public float rotateSpeed;
public float zoomSpeed;
public float maxElevation;
public float minElevation;
public float minDistance;
public float maxDistance;
public float currentElevation;
public float currentDistance;
public float currentAzimuth;
private Vector3 cameraPosition;
private Vector3 nextPosition;
private Quaternion originRotation;
public OrbitalControllerTarget cameraPivot;
private UserInput input;
public Action<ViewMode> onChangeViewMode;
public bool IsCameraOperating { get; private set; }
private bool isMoveOperation;
private bool isRotateOperation;
private bool isZoomOperation;
public bool Enable;
public bool IsRouteActive => routeSequence != null && routeSequence.IsActive();
private Sequence routeSequence;
public bool IsClickUI
{
get
{
bool result = false;
if (Input.GetMouseButtonDown(0))
{
result = EventSystem.current.IsPointerOverGameObject();
}
return result;
}
}
public bool IsOnTheUI
{
get
{
if (IsPointerOverExcludedUI())
{
return false;
}
else
{
var result = EventSystem.current.IsPointerOverGameObject();
return result;
}
}
}
bool IsPointerOverExcludedUI()
{
PointerEventData pointerData = new PointerEventData(EventSystem.current);
pointerData.position = Input.mousePosition;
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, raycastResults);
if (raycastResults.Count > 0)
{
if ((LayerMask.GetMask("Default") & (1 << raycastResults[0].gameObject.layer)) != 0)
{
return true;
}
}
return false;
}
public void Awake()
{
camera = Camera.main;
cameraPivot = transform.GetComponentInChildren<OrbitalControllerTarget>();
}
void Start()
{
originValue.x = currentElevation;
originValue.y = currentDistance;
originValue.z = currentAzimuth;
nextPosition = cameraPivot.transform.position;
originTargetPos = cameraPivot.transform.position;
originRotation = cameraPivot.transform.rotation;
perspectiveState.elevation = originValue.x;
perspectiveState.distance = originValue.y;
perspectiveState.azimuth = originValue.z;
perspectiveState.pivotPosition = originTargetPos;
perspectiveState.pivotRotation = originRotation;
orthoState.elevation = 90f;
orthoState.distance = originValue.y;
orthoState.azimuth = 0f;
orthoState.pivotPosition = Vector3.zero;
orthoState.pivotRotation = originRotation;
SetViewMode(ViewMode.PerspectiveView);
}
public void SetEnable(bool isDrag)
{
Enable = !isDrag;
}
private void LateUpdate()
{
//UI <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ī<>޶<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
if (IsClickUI || IsOnTheUI)
return;
//<2F><><EFBFBD>̺귯<CCBA><EAB7AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ <20><>ġ<EFBFBD><C4A1> ī<>޶<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
if (!Enable)
{
return;
}
if (RTGizmos.get !=null )
{
if (RTGizmos.get.draggedGizmo != null)
return;
if (RTGizmos.get.hoveredGizmo != null)
return;
}
input.GetInput();
Movement();
}
public void Movement()
{
Zoom();
Rotate();
Move();
UpdateOperationState();
LastPositioning();
}
private void Move()
{
if (!input.leftClick)
{
isMoveOperation = false;
return;
}
var delta = new Vector2(input.mouseX, input.mouseY);
var x = delta.x;
var y = delta.y * ((maxElevation - minElevation) / currentElevation);
var z = delta.y * ((minElevation - currentElevation) / maxElevation);
var moveVector = camera.transform.TransformDirection(x, y, -z);
moveVector.y = 0;
//moveVector *= moveSpeed * (currentDistance / maxDistance);
nextPosition = cameraPivot.transform.position - moveVector;
isMoveOperation = true;
}
private void Zoom()
{
if (Mathf.Abs(input.mouseWheel) > 0.0001f)
{
isZoomOperation = true;
}
else
{
isZoomOperation = false;
return;
}
var nextDistance = currentDistance - input.mouseWheel * zoomSpeed;
currentDistance = Mathf.Lerp(currentDistance, nextDistance, zoomSpeed * Time.deltaTime);
currentDistance = Mathf.Clamp(currentDistance, minDistance, maxDistance);
camera.orthographicSize = currentDistance;
}
protected void Rotate()
{
if (!input.rightClick)
{
isRotateOperation = false;
return;
}
currentAzimuth += input.mouseX * rotateSpeed;
currentAzimuth %= 360;
if(viewMode == ViewMode.PerspectiveView)
{
currentElevation -= input.mouseY * rotateSpeed;
currentElevation = Mathf.Clamp(currentElevation, minElevation, maxElevation);
}
isRotateOperation = true;
}
private void UpdateOperationState()
{
IsCameraOperating = isMoveOperation || isRotateOperation || isZoomOperation;
}
public void LastPositioning()
{
cameraPivot.transform.position = nextPosition;
var dist = new Vector3(0, 0, -currentDistance);
var distPos = Quaternion.Euler(currentElevation, currentAzimuth, 0f) * dist;
cameraPosition = nextPosition + distPos;
camera.transform.position = cameraPosition;
if (currentElevation <= 90f)
{
camera.transform.rotation = Quaternion.Euler(currentElevation, currentAzimuth, 0f);
}
else
{
camera.transform.LookAt(cameraPivot.transform);
}
}
public void Rewind()
{
SetViewMode(ViewMode.PerspectiveView);
nextPosition = originTargetPos;
currentDistance = originValue.x;
currentElevation = originValue.y;
currentAzimuth = originValue.z;
LastPositioning();
}
public void SetViewMode(ViewMode mode)
{
if (viewMode == mode)
return;
SaveViewMode(viewMode);
viewMode = mode;
switch (mode)
{
case ViewMode.PerspectiveView:
SetPerspectiveView();
break;
case ViewMode.TopView:
SetOrthographicView();
break;
}
LastPositioning();
onChangeViewMode?.Invoke(viewMode);
}
private void SetPerspectiveView()
{
camera.orthographic = false;
currentElevation = perspectiveState.elevation; //90 <20><> <20><><EFBFBD><EFBFBD>
currentDistance = perspectiveState.distance;
currentAzimuth = perspectiveState.azimuth;
nextPosition = perspectiveState.pivotPosition;
}
private void SetOrthographicView()
{
camera.orthographic = true;
currentElevation = orthoState.elevation;
currentDistance = orthoState.distance;
currentAzimuth = orthoState.azimuth;
camera.orthographicSize = orthoState.distance;
nextPosition = orthoState.pivotPosition;
}
public void SetTargetPos(Vector3 pos)
{
nextPosition = pos;
LastPositioning();
}
public void SetTargetRotation(Quaternion rotation)
{
originRotation = rotation;
}
private void SaveViewMode(ViewMode mode)
{
switch (mode)
{
case ViewMode.PerspectiveView:
perspectiveState.elevation = currentElevation;
perspectiveState.distance = currentDistance;
perspectiveState.azimuth = currentAzimuth;
perspectiveState.pivotPosition = cameraPivot.transform.position;
break;
case ViewMode.TopView:
orthoState.elevation = 90f; // 90 or <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
orthoState.distance = 60f;
orthoState.azimuth = 0f;
orthoState.pivotPosition = Vector3.zero;
break;
}
}
internal void SetControllOptionValue()
{
throw new NotImplementedException();
}
public void SetRoute(CameraRoute route)
{
StopRoute();
Enable = false;
routeSequence = DOTween.Sequence();
for (int i = 0; i < route.PointCount; i++)
{
var (position, point) = route.GetWaypoint(i);
float elev = point != null ? point.elevation : currentElevation;
float azi = point != null ? point.azimuth : currentAzimuth;
float dist = point != null ? point.distance : currentDistance;
float dur = point != null ? point.duration : 0.5f;
float wait = point != null ? point.waitTime : 0f;
routeSequence.Append(
DOTween.To(() => nextPosition, x => nextPosition = x, position, dur));
routeSequence.Join(
DOTween.To(() => currentElevation, x => currentElevation = x, elev, dur));
routeSequence.Join(
DOTween.To(() => currentAzimuth, x => currentAzimuth = x, azi, dur));
routeSequence.Join(
DOTween.To(() => currentDistance, x => currentDistance = x, dist, dur));
if (wait > 0f)
routeSequence.AppendInterval(wait);
}
if (route.loop)
routeSequence.SetLoops(-1, LoopType.Restart);
routeSequence.OnUpdate(LastPositioning);
routeSequence.OnKill(() => Enable = true);
}
public void StopRoute()
{
if (routeSequence != null && routeSequence.IsActive())
{
routeSequence.Kill();
routeSequence = null;
}
}
public void AnimateToState(Vector3 pivotPosition, Vector3 eulerAngles, float distance, float duration = 0.4f)
{
// <20>ִϸ<D6B4><CFB8>̼<EFBFBD> <20>߿<EFBFBD><DFBF><EFBFBD> <20><><EFBFBD><20>Է<EFBFBD> <20><>Ȱ<EFBFBD><C8B0>ȭ
Enable = false;
// DoTween<65><6E> <20><><EFBFBD><EFBFBD>Ͽ<EFBFBD> <20><>Ʈ<EFBFBD>ѷ<EFBFBD><D1B7><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ε巴<CEB5><E5B7B4> <20><><EFBFBD><EFBFBD>
DOTween.To(() => nextPosition, x => nextPosition = x, pivotPosition, duration);
DOTween.To(() => currentElevation, x => currentElevation = x, eulerAngles.x, duration);
DOTween.To(() => currentAzimuth, x => currentAzimuth = x, eulerAngles.y, duration);
DOTween.To(() => currentDistance, x => currentDistance = x, distance, duration)
.OnComplete(() => {
// <20>ִϸ<D6B4><CFB8>̼<EFBFBD><CCBC><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><20>Է<EFBFBD><D4B7><EFBFBD> <20>ٽ<EFBFBD> Ȱ<><C8B0>ȭ
Enable = true;
});
}
//public bool IsOperation()
//{
// if(is)
//}
}
}