using System; using KitsuneCafe.Extension; using KitsuneCafe.Input; using KitsuneCafe.ItemSystem; using KitsuneCafe.SOAP; using R3; using UnityEngine; namespace KitsuneCafe.Entity { public class AimFeature : MonoBehaviour { [SerializeField] private new Camera camera; [SerializeField] private EquipmentInstance equipment; [SerializeField] private Motor motor; [SerializeField] private ControlSchemeValue controlScheme; [SerializeField] private Vector2Value lookValue; private void OnValidate() { if (camera == null) { camera = Camera.main; } if (equipment == null) { equipment = GetComponent(); } if (motor == null) { motor = GetComponent(); } } private void Start() { var d = Disposable.CreateBuilder(); var readied = Observable.FromEventHandler( e => equipment.Readied += e, e => equipment.Readied -= e ) .Select(static eh => eh.e); readied .Subscribe(isReady => { motor.enabled = !isReady; }) .AddTo(ref d); readied .WhereTrue() .SelectMany(_ => controlScheme.AsObservable() .CombineLatest( Observable.IntervalFrame(1), static (scheme, _) => scheme ).TakeUntil(readied.WhereFalse()) ) .Subscribe(Aim) .AddTo(ref d); d.RegisterTo(destroyCancellationToken); } private void Aim(ControlScheme scheme) { switch (scheme) { case ControlScheme.Gamepad: LookInDirection(lookValue.Value); break; default: LookAtPosition(lookValue.Value); break; } } private void LookInDirection(Vector2 value) { transform.LookAt(transform.position + new Vector3(value.x, 0, value.y)); } private void LookAtPosition(Vector2 value) { var screenPosition = camera.WorldToViewportPoint(transform.position); var mouseOnScreen = camera.ScreenToViewportPoint(value); float angle = AngleBetween(screenPosition, mouseOnScreen); transform.rotation = Quaternion.Euler(new Vector3(0, -angle + 90, 0)); } static float AngleBetween(Vector3 a, Vector3 b) { return Mathf.Atan2(b.y - a.y, b.x - a.x) * Mathf.Rad2Deg; } } }