503 lines
17 KiB
C#
503 lines
17 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 event Action<Vector3> onCameraMove;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
onCameraMove?.Invoke(camera.transform.position);
|
|
}
|
|
|
|
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 = 35f;
|
|
|
|
if (saveData == null)
|
|
{
|
|
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 = 150f;
|
|
|
|
if (saveData == null)
|
|
{
|
|
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()
|
|
{
|
|
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;
|
|
|
|
saveTargetPositions[viewMode] = cameraEntity;
|
|
}
|
|
private void SetCameraData(ViewMode currentViewMode)
|
|
{
|
|
var cameraData = saveTargetPositions[currentViewMode];
|
|
|
|
nextPosition = new Vector3(cameraData.x, cameraData.y, cameraData.z);
|
|
Debug.Log(nextPosition);
|
|
option.currentDistance = cameraData.distance;
|
|
option.currentAzimuth = cameraData.azimuth;
|
|
option.currentElevation = cameraData.elevation;
|
|
}
|
|
}
|
|
} |