2023-06-05 19:57:17 +08:00
|
|
|
using UnityEngine;
|
|
|
|
using UnityEngine.InputSystem;
|
|
|
|
using Cinemachine;
|
|
|
|
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
|
|
|
using BITKit.IO;
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
using System.IO;
|
|
|
|
using Cysharp.Threading.Tasks;
|
2023-08-11 23:57:37 +08:00
|
|
|
using UnityEngine.InputSystem.Controls;
|
|
|
|
|
2023-06-05 19:57:17 +08:00
|
|
|
namespace BITKit
|
|
|
|
{
|
|
|
|
public class SimpleCameraLook : MonoBehaviour
|
|
|
|
{
|
|
|
|
private string fileName => Path.Combine(Utility.Path.persistentDataPath, gameObject.scene.name, $"{gameObject.GetInstanceID()}.bit");
|
|
|
|
public enum State
|
|
|
|
{
|
|
|
|
Mouse,
|
|
|
|
Touchscreen,
|
|
|
|
}
|
|
|
|
[Header(Constant.Header.Gameobjects)]
|
|
|
|
public Transform cameraRoot;
|
|
|
|
public CinemachineVirtualCamera virtualCamera;
|
|
|
|
[Header(Constant.Header.Settings)]
|
|
|
|
public TransformMode touchMode;
|
|
|
|
[Header(Constant.Header.Settings)]
|
|
|
|
public InputActionReference viewAction;
|
|
|
|
public InputActionReference movementAction;
|
|
|
|
public InputActionReference adsAction;
|
|
|
|
public InputActionReference entryAction;
|
|
|
|
public InputActionReference entryMoveAction;
|
|
|
|
public InputActionGroup inputGroup = new();
|
|
|
|
[Header(Constant.Header.Settings)]
|
|
|
|
public float minEntrySqrMagnitude = 1;
|
|
|
|
public LayerMask layerMask;
|
|
|
|
[Header(Constant.Header.Settings)]
|
|
|
|
public AnimationCurve scollCurve = new();
|
|
|
|
public AnimationCurve moveCurve = new();
|
|
|
|
public AnimationCurve touchMoveCurve = new();
|
|
|
|
public Vector2 cameraDistanceLimit = new(1, 64);
|
2023-08-11 23:57:37 +08:00
|
|
|
[Header(Constant.Header.Providers)]
|
|
|
|
[SerializeField,SerializeReference,SubclassSelector] private ICondition allowInput;
|
2023-06-05 19:57:17 +08:00
|
|
|
[Header(Constant.Header.Debug)]
|
|
|
|
public int touchesCount;
|
|
|
|
public bool isParallelVector;
|
|
|
|
[Header(Constant.Header.InternalVariables)]
|
|
|
|
public Vector3 lookInput;
|
|
|
|
public Vector3 moveVector;
|
|
|
|
public ValidHandle freeLooking = new();
|
|
|
|
public ValidHandle moving = new();
|
|
|
|
private Cinemachine3rdPersonFollow tpv;
|
|
|
|
private Location startLocation;
|
|
|
|
private Location savedLocation;
|
|
|
|
private float savedDistance;
|
|
|
|
private float startDistance;
|
|
|
|
private CinemachineBrain _brain;
|
2023-08-11 23:57:37 +08:00
|
|
|
|
|
|
|
public Vector3 Position
|
|
|
|
{
|
|
|
|
get=>cameraRoot.position;
|
|
|
|
set=>cameraRoot.position = value;
|
|
|
|
}
|
2023-06-05 19:57:17 +08:00
|
|
|
public void Reset()
|
|
|
|
{
|
2023-06-29 14:57:11 +08:00
|
|
|
lookInput = MathV.TransientRotationAxis(startLocation.position);
|
2023-06-05 19:57:17 +08:00
|
|
|
cameraRoot.position = startLocation;
|
|
|
|
tpv.CameraDistance = startDistance;
|
|
|
|
}
|
|
|
|
public void DisableInput(bool disable)
|
|
|
|
{
|
|
|
|
inputGroup.allowInput.SetDisableElements(nameof(DisableInput), disable);
|
|
|
|
}
|
|
|
|
public void SetTouchMode(int index)
|
|
|
|
{
|
|
|
|
SetTouchMode((TransformMode)index);
|
|
|
|
}
|
|
|
|
public void SetTouchMode(TransformMode mode)
|
|
|
|
{
|
|
|
|
touchMode = mode;
|
|
|
|
}
|
2023-08-11 23:57:37 +08:00
|
|
|
|
|
|
|
public void SetViewScale(float value)
|
|
|
|
{
|
|
|
|
tpv.CameraDistance = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float GetViewScale() => tpv.CameraDistance;
|
2023-06-05 19:57:17 +08:00
|
|
|
public void Align(Transform target)
|
|
|
|
{
|
|
|
|
if (target.TryGetComponent<SimpleCameraLook>(out var x))
|
|
|
|
{
|
|
|
|
cameraRoot.position = x.cameraRoot.position;
|
|
|
|
//lookInput = x.lookInput;
|
2023-06-29 14:57:11 +08:00
|
|
|
lookInput = MathV.TransientRotationAxis(x.cameraRoot.rotation.eulerAngles);
|
2023-06-05 19:57:17 +08:00
|
|
|
if (x.tpv)
|
|
|
|
tpv.CameraDistance = x.tpv.CameraDistance;
|
|
|
|
}
|
|
|
|
else if (target.TryGetComponent<CinemachineVirtualCamera>(out var vCam))
|
|
|
|
{
|
|
|
|
cameraRoot.position = vCam.Follow.position;
|
2023-06-29 14:57:11 +08:00
|
|
|
lookInput = MathV.TransientRotationAxis(vCam.LookAt.rotation.eulerAngles);
|
2023-06-05 19:57:17 +08:00
|
|
|
var e = vCam.GetCinemachineComponent<Cinemachine3rdPersonFollow>();
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
tpv.CameraDistance = e.CameraDistance;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cameraRoot.position = target.position;
|
2023-06-29 14:57:11 +08:00
|
|
|
lookInput = MathV.TransientRotationAxis(target.eulerAngles);
|
2023-06-05 19:57:17 +08:00
|
|
|
}
|
|
|
|
}
|
2023-08-11 23:57:37 +08:00
|
|
|
public void Align(Vector3 position)=>cameraRoot.position= position;
|
2023-06-05 19:57:17 +08:00
|
|
|
public void SaveLocation()
|
|
|
|
{
|
|
|
|
savedLocation = new(cameraRoot);
|
|
|
|
savedDistance = tpv.CameraDistance;
|
|
|
|
BITAssets.Build(
|
|
|
|
PathHelper.GetFilePath(fileName),
|
|
|
|
new IAsset[]
|
|
|
|
{
|
|
|
|
new BITAsset(nameof(savedLocation),JsonUtility.ToJson(savedLocation)),
|
|
|
|
new BITAsset(nameof(savedDistance),JsonConvert.SerializeObject(savedDistance)),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
public void LoadLocation()
|
|
|
|
{
|
2023-06-29 14:57:11 +08:00
|
|
|
lookInput = MathV.TransientRotationAxis(savedLocation.rotation.eulerAngles);
|
2023-06-05 19:57:17 +08:00
|
|
|
cameraRoot.position = savedLocation;
|
|
|
|
tpv.CameraDistance = savedDistance;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
{
|
|
|
|
freeLooking.AddListener(OnFreeLook);
|
|
|
|
tpv = virtualCamera.GetCinemachineComponent<Cinemachine3rdPersonFollow>();
|
|
|
|
|
|
|
|
savedLocation = startLocation = new(cameraRoot);
|
|
|
|
savedDistance = startDistance = tpv.CameraDistance;
|
|
|
|
|
|
|
|
inputGroup.RegisterCallback(viewAction, OnView);
|
|
|
|
inputGroup.RegisterCallback(movementAction, OnMovement);
|
|
|
|
inputGroup.RegisterCallback(adsAction, OnAds);
|
|
|
|
inputGroup.RegisterCallback(entryAction, OnEntry);
|
|
|
|
inputGroup.RegisterCallback(entryMoveAction, OnEntryMoveAction);
|
|
|
|
|
|
|
|
if (Camera.main != null) _brain = Camera.main.GetComponent<CinemachineBrain>();
|
|
|
|
}
|
|
|
|
|
|
|
|
private async void Start()
|
|
|
|
{
|
2023-06-07 02:02:14 +08:00
|
|
|
var fileName = this.fileName;
|
2023-06-05 19:57:17 +08:00
|
|
|
await UniTask.SwitchToThreadPool();
|
|
|
|
if (File.Exists(fileName))
|
|
|
|
{
|
|
|
|
savedLocation = BITAssets.Read<Location>(fileName, nameof(savedLocation));
|
|
|
|
savedDistance = BITAssets.Read<float>(fileName, nameof(savedDistance));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnEnable()
|
|
|
|
{
|
|
|
|
SetEnabled(true);
|
2023-06-29 14:57:11 +08:00
|
|
|
lookInput = MathV.TransientRotationAxis(cameraRoot.eulerAngles);
|
2023-06-05 19:57:17 +08:00
|
|
|
|
|
|
|
freeLooking.RemoveDisableElements(this);
|
|
|
|
|
2023-08-11 23:57:37 +08:00
|
|
|
if (virtualCamera is not null)
|
|
|
|
virtualCamera.enabled = true;
|
2023-06-05 19:57:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
{
|
|
|
|
SetEnabled(false);
|
|
|
|
freeLooking.AddDisableElements(this);
|
|
|
|
|
2023-08-11 23:57:37 +08:00
|
|
|
if (virtualCamera is not null)
|
|
|
|
virtualCamera.enabled = false;
|
2023-06-05 19:57:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
{
|
|
|
|
inputGroup.Dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void SetEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
//BIT4Log.Log<SimpleCameraLook>($"正在设置输入状态:{enabled}");
|
|
|
|
BITAppForUnity.AllowTouchSupport.SetElements(this, enabled);
|
|
|
|
inputGroup.allowInput.SetElements(this, enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
{
|
|
|
|
//var debuger = DI.Get<IDebuger>();
|
|
|
|
var playerConfig = PlayerConfig.singleton;
|
|
|
|
var sensitivity = playerConfig.touchSensitivity;
|
|
|
|
|
|
|
|
//debuger.Log(nameof(Touch.activeTouches), Touch.activeTouches.Count.ToString());
|
|
|
|
touchesCount = Touch.activeTouches.Count;
|
|
|
|
|
|
|
|
if (Mouse.current.leftButton.wasPressedThisFrame)
|
|
|
|
{
|
|
|
|
var ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
|
|
|
|
if (Physics.Raycast(ray, out var raycast, 256, layerMask))
|
|
|
|
{
|
|
|
|
cameraRoot.position = raycast.point;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_brain)
|
|
|
|
{
|
|
|
|
inputGroup.allowInput.SetDisableElements(nameof(CinemachineBrain),virtualCamera != (CinemachineVirtualCamera)_brain.ActiveVirtualCamera);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void LateUpdate()
|
|
|
|
{
|
|
|
|
lookInput.x = Mathf.Clamp(lookInput.x, -80, 80);
|
|
|
|
var newRotation = Quaternion.Euler(lookInput);
|
|
|
|
cameraRoot.rotation = Quaternion.Lerp(cameraRoot.rotation, newRotation, 48 * Time.deltaTime);
|
|
|
|
var offset = cameraRoot.localRotation * moveVector;
|
|
|
|
cameraRoot.localPosition -= offset * Time.deltaTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnView(InputAction.CallbackContext context)
|
|
|
|
{
|
2023-08-11 23:57:37 +08:00
|
|
|
if (allowInput.OnCheck() is false) return;
|
2023-06-05 19:57:17 +08:00
|
|
|
var playerConfig = PlayerConfig.singleton;
|
|
|
|
var sensitivity = playerConfig.sensitivity * playerConfig.m_yaw;
|
|
|
|
var delta = context.ReadValue<Vector2>();
|
|
|
|
switch (context.control.device)
|
|
|
|
{
|
|
|
|
case Mouse mouse:
|
|
|
|
if (freeLooking && !moving)
|
|
|
|
{
|
|
|
|
lookInput.x -= delta.y * sensitivity;
|
|
|
|
lookInput.y += delta.x * sensitivity;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Touchscreen touchscreen:
|
|
|
|
switch (touchMode)
|
|
|
|
{
|
|
|
|
case TransformMode.Move:
|
|
|
|
break;
|
|
|
|
case TransformMode.Rotate:
|
|
|
|
lookInput.x -= delta.y * sensitivity;
|
|
|
|
lookInput.y += delta.x * sensitivity;
|
|
|
|
moveVector = default;
|
|
|
|
break;
|
|
|
|
case TransformMode.Scale:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (touchMode is TransformMode.Scale)
|
|
|
|
{
|
|
|
|
OnAds(context);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnAds(InputAction.CallbackContext context)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BITAppForUnity.ThrowIfWindowNotFocus();
|
|
|
|
switch (context.control.device)
|
|
|
|
{
|
|
|
|
case Mouse mouse:
|
|
|
|
OnAds(context.ReadValue<Vector2>().y);
|
|
|
|
break;
|
|
|
|
case Touchscreen touchscreen:
|
|
|
|
/* lookInput.x -= delta.y * sensitivity;
|
|
|
|
lookInput.y += delta.x * sensitivity; */
|
|
|
|
switch (touchMode)
|
|
|
|
{
|
|
|
|
case TransformMode.Move:
|
|
|
|
break;
|
|
|
|
case TransformMode.Rotate:
|
|
|
|
moveVector = default;
|
|
|
|
break;
|
|
|
|
case TransformMode.Scale:
|
|
|
|
OnAds(context.ReadValue<Vector2>().y);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (MouseNotOverGameViewException)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnAds(float delta)
|
|
|
|
{
|
|
|
|
var newDistance = tpv.CameraDistance -
|
|
|
|
delta * Time.deltaTime * scollCurve.Evaluate(tpv.CameraDistance);
|
|
|
|
tpv.CameraDistance = Mathf.Clamp(newDistance, cameraDistanceLimit.x, cameraDistanceLimit.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnFreeLook(bool active)
|
|
|
|
{
|
|
|
|
BITAppForUnity.AllowCursor.SetDisableElements(this, active);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnEntry(InputAction.CallbackContext context)
|
|
|
|
{
|
|
|
|
if (context.started)
|
|
|
|
{
|
|
|
|
var delta = viewAction.action.ReadValue<Vector2>();
|
|
|
|
if (delta.sqrMagnitude > minEntrySqrMagnitude)
|
|
|
|
freeLooking.AddElement(this);
|
|
|
|
}
|
|
|
|
else if (context.canceled)
|
|
|
|
{
|
|
|
|
freeLooking.RemoveElement(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnMovement(InputAction.CallbackContext context)
|
|
|
|
{
|
|
|
|
switch (context.control.device)
|
|
|
|
{
|
|
|
|
case Mouse mouse:
|
|
|
|
if (moving && freeLooking)
|
|
|
|
{
|
|
|
|
moveVector = context.ReadValue<Vector2>() * moveCurve.Evaluate(tpv.CameraDistance);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Touchscreen touchscreen:
|
|
|
|
/* lookInput.x -= delta.y * sensitivity;
|
|
|
|
lookInput.y += delta.x * sensitivity; */
|
|
|
|
switch (touchMode)
|
|
|
|
{
|
|
|
|
case TransformMode.Move:
|
|
|
|
moveVector = context.ReadValue<Vector2>() * moveCurve.Evaluate(tpv.CameraDistance);
|
|
|
|
break;
|
|
|
|
case TransformMode.Rotate:
|
|
|
|
break;
|
|
|
|
case TransformMode.Scale:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (context.canceled)
|
|
|
|
{
|
|
|
|
moveVector = default;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void OnEntryMoveAction(InputAction.CallbackContext context)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (context.started)
|
|
|
|
{
|
|
|
|
moving.AddElement(this);
|
|
|
|
}
|
|
|
|
else if (context.canceled)
|
|
|
|
{
|
|
|
|
moving.RemoveElement(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|