using System; using System.Collections; 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 Action 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 onPerspectiveView; public Action onFirstPersonViewRay; public event Action onCameraMove; public float targetColliderRadius; public override void AfterAwake() { base.AfterAwake(); targetColliderRadius = option.target.GetComponent().radius; } 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; } else { moveSpeed = option.moveSpeed; } 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() { 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() { option.maxDistance = 35f; option.currentElevation = 90f; option.currentDistance = 35f; option.currentAzimuth = 0f; LastPositioning(true); } public void CameraFirstPersonView() { camera.transform.position = option.target.position; option.currentDistance = 5f; option.currentElevation = 0f; option.currentAzimuth = 0f; LastPositioning(true); } public void CameraPerspectiveView() { option.maxDistance = 150f; option.currentDistance = option.originDistance; option.currentAzimuth = option.originAzimuth; option.currentElevation = option.originElevation; 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); } } } }