145 lines
4.9 KiB
C#
145 lines
4.9 KiB
C#
using Cysharp.Threading.Tasks;
|
|
using Unity.Cinemachine;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
namespace DanieleMarotta.RiversongCodeShowcase
|
|
{
|
|
[Service(typeof(ICameraProperties))]
|
|
public class CameraSystem : GameSystem, IInitializable, IUpdatable, ICameraProperties
|
|
{
|
|
[InjectService]
|
|
private GameConfig _gameConfig;
|
|
|
|
[InjectService]
|
|
private IScene _scene;
|
|
|
|
private GameConfig.CameraConfig _cameraConfig;
|
|
|
|
private CinemachineBrain _cinemachineBrain;
|
|
|
|
private CinemachineFollow _cinemachineFollow;
|
|
|
|
private Transform _target;
|
|
|
|
private float _targetZoom;
|
|
|
|
private Vector3? _terrainDragAnchor;
|
|
|
|
public CameraSystem(IServiceLocator serviceLocator) : base(serviceLocator)
|
|
{
|
|
}
|
|
|
|
public float Zoom { get; private set; }
|
|
|
|
public UniTask InitializeAsync()
|
|
{
|
|
_cameraConfig = _gameConfig.Camera;
|
|
|
|
_cinemachineBrain = _scene.MainCamera.GetComponent<CinemachineBrain>();
|
|
|
|
_cinemachineFollow = (CinemachineFollow)_scene.CinemachineCamera.GetCinemachineComponent(CinemachineCore.Stage.Body);
|
|
_target = _cinemachineFollow.FollowTarget;
|
|
|
|
Zoom = _targetZoom = _cinemachineFollow.FollowOffset.magnitude;
|
|
|
|
return UniTask.CompletedTask;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
var dt = Time.unscaledDeltaTime;
|
|
|
|
UpdateZoom(dt);
|
|
UpdatePosition(dt);
|
|
UpdateRotation(dt);
|
|
|
|
_cinemachineBrain.ManualUpdate();
|
|
}
|
|
|
|
private void UpdateZoom(float dt)
|
|
{
|
|
var zoomInput = -1 * Mouse.current.scroll.y.ReadValue();
|
|
|
|
_targetZoom += zoomInput * _cameraConfig.ZoomSensitivity;
|
|
_targetZoom = Mathf.Clamp(_targetZoom, _cameraConfig.ZoomRange.x, _cameraConfig.ZoomRange.y);
|
|
|
|
Zoom = Mathf.Lerp(Zoom, _targetZoom, _cameraConfig.ZoomSpeed * dt);
|
|
|
|
_cinemachineFollow.FollowOffset = _cinemachineFollow.FollowOffset.normalized * Zoom;
|
|
}
|
|
|
|
private void UpdatePosition(float dt)
|
|
{
|
|
var moveInput = Vector3.zero;
|
|
|
|
moveInput.x += Keyboard.current.dKey.isPressed ? 1 : 0;
|
|
moveInput.x += Keyboard.current.aKey.isPressed ? -1 : 0;
|
|
moveInput.z += Keyboard.current.wKey.isPressed ? 1 : 0;
|
|
moveInput.z += Keyboard.current.sKey.isPressed ? -1 : 0;
|
|
|
|
var right = _target.right;
|
|
var forward = _target.forward;
|
|
forward.y = 0;
|
|
forward.Normalize();
|
|
|
|
var normalizedZoom = Mathf.InverseLerp(_cameraConfig.ZoomRange.x, _cameraConfig.ZoomRange.y, Zoom);
|
|
var moveSpeed = Mathf.Lerp(_cameraConfig.MoveSpeed.x, _cameraConfig.MoveSpeed.y, normalizedZoom);
|
|
var delta = moveSpeed * dt;
|
|
|
|
_target.position += right * (moveInput.x * delta);
|
|
_target.position += forward * (moveInput.z * delta);
|
|
|
|
UpdateDraggingTerrain();
|
|
}
|
|
|
|
private void UpdateDraggingTerrain()
|
|
{
|
|
if (!Mouse.current.middleButton.isPressed)
|
|
{
|
|
_terrainDragAnchor = null;
|
|
return;
|
|
}
|
|
|
|
var plane = new Plane(Vector3.up, new Vector3(0, _gameConfig.GeneralSettings.BaseElevation, 0));
|
|
var ray = _scene.MainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
|
|
if (!plane.Raycast(ray, out var enter)) return;
|
|
|
|
var hit = ray.GetPoint(enter);
|
|
if (_terrainDragAnchor == null)
|
|
{
|
|
_terrainDragAnchor = hit;
|
|
return;
|
|
}
|
|
|
|
_target.position += _terrainDragAnchor.Value - hit;
|
|
}
|
|
|
|
private void UpdateRotation(float dt)
|
|
{
|
|
var keyboard = Keyboard.current;
|
|
var rotation = _target.rotation.eulerAngles;
|
|
var keyboardRotationDelta = Vector2.zero;
|
|
|
|
keyboardRotationDelta.x += keyboard.eKey.isPressed ? 1 : 0;
|
|
keyboardRotationDelta.x += keyboard.qKey.isPressed ? -1 : 0;
|
|
keyboardRotationDelta.y += keyboard.rKey.isPressed ? 1 : 0;
|
|
keyboardRotationDelta.y += keyboard.fKey.isPressed ? -1 : 0;
|
|
|
|
rotation.y += keyboardRotationDelta.x * _cameraConfig.KeyboardRotationSpeed.x * dt;
|
|
rotation.x -= keyboardRotationDelta.y * _cameraConfig.KeyboardRotationSpeed.y * dt;
|
|
|
|
if (keyboard.leftAltKey.isPressed)
|
|
{
|
|
var mouseDelta = Mouse.current.delta;
|
|
|
|
rotation.x += mouseDelta.y.ReadValue() * _cameraConfig.MouseRotationSpeed.y * dt;
|
|
rotation.y += mouseDelta.x.ReadValue() * _cameraConfig.MouseRotationSpeed.x * dt;
|
|
}
|
|
|
|
rotation.x = Mathf.Clamp(rotation.x, _cameraConfig.PitchRange.x, _cameraConfig.PitchRange.y);
|
|
|
|
_target.forward = Quaternion.Euler(rotation) * Vector3.forward;
|
|
}
|
|
}
|
|
} |