Files
ChunilENG/Assets/Plugins/XRLib/GenericController/Orbital/OrbitalController.cs
2025-03-26 20:10:27 +09:00

502 lines
18 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace WI
{
//TODO::Something... Util Functions
public class OrbitalController : GenericController, ISingle, IOptionable
{
public new OrbitalControllerOption option => base.option as OrbitalControllerOption;
public SDictionary<ViewMode, CameraEntity> saveTargetPositions = new SDictionary<ViewMode, CameraEntity>();
public Action<int> ZoomInOutEvent;
public int maxValue;
public float duration_MoveToCamera;
public float speed_MoveToCamera;
public float process;
public float yUpPos;
public float runSpeed;
float timer;
[OptionSection]
string controllerOption;
[OptionKey]
string MoveSpeed="2";
[OptionKey]
string ZoomSpeed = "30";
[OptionKey]
string RotateSpeed ="5";
[OptionKey]
string FORWARD="W";
[OptionKey]
string BACKWARD="S";
[OptionKey]
string LEFT="A";
[OptionKey]
string RIGHT = "D";
[OptionKey]
string RUN = "LeftShift";
[OptionKey]
string TargetVisualization = "LeftControl";
public KeyCode up;
public KeyCode down;
public KeyCode left;
public KeyCode right;
public KeyCode run;
public KeyCode targetVisualization;
public ViewMode viewMode;
public Action<RaycastHit[], Transform> onPerspectiveView;
public Action<RaycastHit> onFirstPersonViewRay;
public float targetColliderRadius;
public override void AfterAwake()
{
base.AfterAwake();
targetColliderRadius = option.target.GetComponent<SphereCollider>().radius;
foreach(ViewMode mode in Enum.GetValues(typeof(ViewMode)))
{
saveTargetPositions.Add(mode, null);
}
SetViewMode(ViewMode.PerspectiveView);
}
public override void AfterStart()
{
SetControllOptionValue();
}
public void SetControllOptionValue()
{
option.moveSpeed = float.Parse(MoveSpeed);
option.zoomSpeed = float.Parse(ZoomSpeed);
option.rotateSpeed = float.Parse(RotateSpeed);
runSpeed = option.moveSpeed * 1.5f;
up = (KeyCode)Enum.Parse(typeof(KeyCode), FORWARD);
down = (KeyCode)Enum.Parse(typeof(KeyCode), BACKWARD);
left = (KeyCode)Enum.Parse(typeof(KeyCode), LEFT);
right = (KeyCode)Enum.Parse(typeof(KeyCode), RIGHT);
run = (KeyCode)Enum.Parse(typeof(KeyCode), RUN);
targetVisualization = (KeyCode)Enum.Parse(typeof(KeyCode), TargetVisualization);
}
public override void Movement()
{
nextPosition = option.target.position;
Zoom();
Rotate();
Move();
//FindLookAtObject();
}
protected override void Move()
{
if (option.moveLimit)
{
return;
}
if (option.isFirstPersonView)
{
float keyboardX = 0;
float keyboardY = 0;
if (Input.GetKey(up))
{
keyboardY = 1;
}
if (Input.GetKey(down))
{
keyboardY = -1;
}
if (Input.GetKey(left))
{
keyboardX = -1;
}
if (Input.GetKey(right))
{
keyboardX = 1;
}
float moveSpeed;
if (Input.GetKey(run))
{
moveSpeed = runSpeed * 2.5f;
}
else
{
moveSpeed = option.moveSpeed * 2.5f;
}
moveVector = transform.TransformDirection(keyboardX, 0, keyboardY);
moveVector.y = 0;
var t = option.currentDistance / option.maxDistance;
option.moveClamper = Mathf.Min(t, 1f);
moveVector = moveVector.normalized * moveSpeed * Time.unscaledDeltaTime;
nextPosition = CalculateMovePosition(option.target.position, moveVector);
}
else
{
if (!input.leftClick)
{
return;
}
moveVector = Vector3.zero;
var mouseYsen = input.mouseY * option.elevationSensivity;
float y = mouseYsen * ((option.maxElevation - option.minElevation) / option.currentElevation);
float z = mouseYsen * ((option.minElevation - option.currentElevation) / option.maxElevation);
moveVector = transform.TransformDirection(input.mouseX * option.elevationSensivity, y, z);
moveVector.y = 0;
var t = option.currentDistance / option.maxDistance;
option.moveClamper = Mathf.Min(t, 1f);
moveVector *= option.moveClamper * option.moveSpeed * option.moveSensivity;
nextPosition = option.target.position - moveVector;
}
}
Vector3 CalculateMovePosition(Vector3 origPos, Vector3 moveVec)
{
if (moveVec == Vector3.zero)
return origPos;
float moveDist = moveVec.magnitude;
Vector3 destPos = origPos + moveVec;
int wallMask = LayerMask.GetMask("Floor Wall");
Collider[] hitColliders = Physics.OverlapSphere(destPos, targetColliderRadius, wallMask);
if (hitColliders.Length > 0)
{
RaycastHit[] raycastHits = Physics.SphereCastAll(origPos, targetColliderRadius, moveVec, moveDist + 0.11f, wallMask);
if (raycastHits.Length > 0)
{
foreach (RaycastHit hit in raycastHits)
{
moveVec -= hit.normal * Vector3.Dot(hit.normal, moveVec);
}
}
}
return origPos + moveVec;
}
protected override void Zoom()
{
if (option.isFirstPersonView)
return;
camera.orthographicSize = camera.orthographic ? option.currentDistance : 0f;
var nextDistance = option.currentDistance - input.mouseWheel * option.zoomSpeed;
option.currentDistance = Mathf.Lerp(option.currentDistance, nextDistance, option.zoomSpeed * Time.deltaTime);
option.currentDistance = Mathf.Clamp(option.currentDistance, option.minDistance, option.maxDistance);
camera.orthographicSize = Mathf.Clamp(option.currentDistance, option.minDistance, option.maxDistance);
var syncValue = -(maxValue * (option.currentDistance - option.maxDistance) / option.maxDistance);
ZoomInOutEvent?.Invoke(Mathf.RoundToInt(syncValue));
}
//TODO:: Into Member Methods... anywhere
public void SliderZoomInOut(int value)
{
camera.orthographicSize = camera.orthographic ? option.currentDistance : 0f;
var nextDistance = option.maxDistance - (option.maxDistance / maxValue * value);
var lerpDistance = Mathf.Lerp(option.currentDistance, nextDistance, option.zoomSpeed * Time.deltaTime);
option.currentDistance = Mathf.Clamp(lerpDistance, option.minDistance, option.maxDistance);
camera.orthographicSize = Mathf.Clamp(option.currentDistance, option.minDistance, option.maxDistance);
}
protected override void Rotate()
{
if (option.rotateLimit)
return;
if (!input.rightClick)
return;
if (option.isFirstPersonView)
{
option.currentAzimuth += input.mouseX * option.rotateSpeed;
option.currentAzimuth %= 360;
option.currentElevation += input.mouseY * option.rotateSpeed;
option.currentElevation = Mathf.Clamp(option.currentElevation, -35f, 75f);
}
else
{
AzimuthControl();
ElevationControl();
}
}
protected void AzimuthControl()
{
if (option.azimuthRotateLimit)
return;
option.currentAzimuth += input.mouseX * option.rotateSpeed;
option.currentAzimuth %= 360;
}
protected void ElevationControl()
{
if (option.orthographic)
return;
if (option.elevationRotateLimit)
return;
option.currentElevation -= input.mouseY * option.rotateSpeed;
option.currentElevation = Mathf.Clamp(option.currentElevation, option.minElevation, option.maxElevation);
}
public override void LastPositioning(bool limit)
{
if (!limit)
return;
if (option.isFirstPersonView)
{
option.target.position = nextPosition;
cameraPosition = nextPosition;
camera.transform.position = cameraPosition;
transform.eulerAngles = new Vector3(-option.currentElevation, option.currentAzimuth, 0);
}
else
{
option.target.position = nextPosition;
var dist = new Vector3(0, 0, -option.currentDistance);
var distPos = Quaternion.Euler(option.currentElevation, option.currentAzimuth, 0f) * dist;
cameraPosition = nextPosition + distPos;
camera.transform.position = cameraPosition;
camera.orthographicSize = Mathf.Clamp(option.currentDistance, option.minDistance, option.maxDistance);
if (option.currentElevation <= 90f)
{
camera.transform.rotation = Quaternion.Euler(option.currentElevation, option.currentAzimuth, 0f);
}
else
{
camera.transform.LookAt(option.target);
}
}
}
public override void Rewind()
{
option.target.position = option.originTargetPos;
option.target.eulerAngles = option.originTargetRot;
option.currentDistance = option.originDistance;
option.currentElevation = option.originElevation;
option.currentAzimuth = option.originAzimuth;
var dist = new Vector3(0, 0, -option.currentDistance);
var distPos = Quaternion.Euler(option.currentElevation, option.currentAzimuth, 0f) * dist;
cameraPosition = option.target.position + distPos;
camera.transform.position = cameraPosition;
camera.transform.LookAt(option.target);
}
void ProcessWinding()
{
if (process > 0f)
{
process = 1f - process;
}
}
public void SmoothMove(Vector3 pos, float distance, float elevation, float azimuth)
{
StopAllCoroutines();
StartCoroutine(SmoothMoving(pos, distance, elevation, azimuth));
}
IEnumerator SmoothMoving(Vector3 pos, float distance, float elevation, float azimuth)
{
ProcessWinding();
while (process < 1f)
{
timer += speed_MoveToCamera * Time.deltaTime;
process += timer / duration_MoveToCamera;
MoveToCamera(pos, distance, elevation, azimuth);
yield return null;
}
timer = 0f;
}
void MoveToCamera(Vector3 pos, float distance, float elevation, float azimuth)
{
option.target.position = Vector3.Lerp(option.target.position, pos, process);
option.currentDistance = Mathf.Lerp(option.currentDistance, distance, process);
option.currentElevation = Mathf.LerpAngle(option.currentElevation, elevation, process);
option.currentAzimuth = Mathf.LerpAngle(option.currentAzimuth, azimuth, process);
CameraFix();
}
public void CameraFix()
{
//option.target.position = nextPostion;
var dist = new Vector3(0, 0, -option.currentDistance);
//option.outlineCamera.orthographicSize = option.currentDistance;
cameraPosition = option.target.position + Quaternion.Euler(option.currentElevation, option.currentAzimuth, 0f) * dist;
camera.transform.position = cameraPosition;
camera.transform.LookAt(option.target);
}
public void SetViewMode(ViewMode mode)
{
viewMode = mode;
switch (mode)
{
case ViewMode.None:
break;
case ViewMode.TopView:
camera.orthographic = true;
option.orthographic = true;
option.isFirstPersonView = false;
CameraTopView();
break;
case ViewMode.PerspectiveView:
camera.orthographic = false;
option.orthographic = false;
option.isFirstPersonView = false;
CameraPerspectiveView();
break;
case ViewMode.FirstPersonView:
camera.orthographic = false;
option.orthographic = false;
option.isFirstPersonView = true;
CameraFirstPersonView();
break;
}
}
public void CameraTopView()
{
var saveData = saveTargetPositions[ViewMode.TopView];
option.maxDistance = 50f;
if (saveData == null)
{
nextPosition = new Vector3(4f, 21.9f, 1f);
option.currentElevation = 90f;
option.currentDistance = 35f;
option.currentAzimuth = 0f;
}
else
{
SetCameraData(viewMode);
}
LastPositioning(true);
}
public void CameraFirstPersonView()
{
var saveData = saveTargetPositions[ViewMode.FirstPersonView];
if (saveData == null)
{
camera.transform.position = option.target.position;
option.currentDistance = 5f;
option.currentElevation = 0f;
option.currentAzimuth = 0f;
}
else
{
SetCameraData(viewMode);
}
LastPositioning(true);
}
public void CameraPerspectiveView()
{
var saveData = saveTargetPositions[ViewMode.PerspectiveView];
option.maxDistance = 60f;
if (saveData == null)
{
nextPosition = option.originTargetPos;
option.currentDistance = option.originDistance;
option.currentAzimuth = option.originAzimuth;
option.currentElevation = option.originElevation;
}
else
{
SetCameraData(viewMode);
}
LastPositioning(true);
}
public void SetTargetPos(Vector3 pos)
{
nextPosition = pos;
LastPositioning(true);
}
private void FindLookAtObject()
{
switch(viewMode)
{
case ViewMode.PerspectiveView:
PerspectiveViewCenterRay();
break;
case ViewMode.FirstPersonView:
FirstPersonViewRay();
break;
}
}
private void PerspectiveViewCenterRay()
{
var dir = option.target.position - camera.transform.localPosition;
var distance = Vector3.Distance(option.target.position, camera.transform.localPosition);
var hits = Physics.RaycastAll(camera.transform.position, dir, distance);
//Debug.DrawRay(camera.transform.position, dir * distance, Color.blue);
onPerspectiveView?.Invoke(hits, option.target);
}
private void FirstPersonViewRay()
{
if (Physics.Raycast(camera.transform.position, transform.forward, out RaycastHit hit, Mathf.Infinity))
{
onFirstPersonViewRay?.Invoke(hit);
}
}
public void SaveTargetPosition(int floorIndex)
{
var cameraEntity = new CameraEntity();
cameraEntity.x = option.target.position.x;
cameraEntity.y = option.target.position.y;
cameraEntity.z = option.target.position.z;
cameraEntity.distance = option.currentDistance;
cameraEntity.azimuth = option.currentAzimuth;
cameraEntity.elevation = option.currentElevation;
cameraEntity.floorIndex = floorIndex;
saveTargetPositions[viewMode] = cameraEntity;
}
private void SetCameraData(ViewMode currentViewMode)
{
var cameraData = saveTargetPositions[currentViewMode];
nextPosition = new Vector3(cameraData.x, cameraData.y, cameraData.z);
option.currentDistance = cameraData.distance;
option.currentAzimuth = cameraData.azimuth;
option.currentElevation = cameraData.elevation;
}
}
}