using UnityEngine; using UnityEngine.Events; namespace OctoCore.Components { public class OctoPlayerDriver : MonoBehaviour { [System.Serializable] public class State { public bool ForcePlayerToFollowTarget; [Range(0, 1)] public float MoveInfluence; [Range(0, 1)] public float LookInfluence; [Range(0, 180)] public float YawRange = 180; [Range(0, 90)] public float PitchRange = 90; } [System.Serializable] public class References { public Transform Target; public Transform LookAt; } [System.Serializable] public class Settings { [Min(.1f)] public float DriveStrength = 1; [Range(0, 1)] public float LookAtStrength = 1; [Range(.1f, 3)] public float LookAtSmooth = 1; [Range(0, 1)] public float LookAtPoint = .5f; public AnimationCurve DriveCurve = AnimationCurve.EaseInOut(0, 0, 1 , 1); public AnimationCurve LookCurve = AnimationCurve.EaseInOut(0, 0, 1 , 1); } [System.Serializable] public class Events { public UnityEvent OnDrive; public UnityEvent OnFullInfluence; public UnityEvent OnRelease; } [SerializeField, OctoReadOnly] private State _state; [SerializeField] private References _references; [SerializeField] private Settings _settings; [SerializeField] private Events _events; public References _References => _references; public State _State => _state; private bool _fullInfluenceReached; void OnDrawGizmos() { UnityEditor.Handles.color = Color.cyan; const float size = .3f; if (_references.Target) { UnityEditor.Handles.matrix = _references.Target.localToWorldMatrix; UnityEditor.Handles.DrawLine(Vector3.forward * size, Vector3.back * size); UnityEditor.Handles.DrawLine(Vector3.left * size, Vector3.right * size); } if (_references.LookAt) { UnityEditor.Handles.matrix = _references.LookAt.localToWorldMatrix; UnityEditor.Handles.DrawWireCube(Vector3.zero, Vector3.one * size * .75f); } } void Start() { } void Update() { } public void DrivePlayer() { _fullInfluenceReached = false; _state.YawRange = 180; _state.PitchRange = 90; OctoPlayer.Instance.Drive(this); _events.OnDrive?.Invoke(); } public void ForcePlayerToFollowTarget(bool force) { _state.ForcePlayerToFollowTarget = force; } public void ReleasePlayer() { OctoPlayer.Instance.ReleaseDrive(); _state.YawRange = 180; _state.PitchRange = 90; _events.OnRelease?.Invoke(); } public void ApplyMoveInfluence(Vector3 inMove, float delta, out Vector3 outMove) { if (!OctoPlayer.Instance || !OctoPlayer.Instance._FirstPerson.Camera || !_references.Target) { outMove = inMove; return; } _state.MoveInfluence = Mathf.Clamp01(_state.MoveInfluence + delta * (_state.ForcePlayerToFollowTarget ? 1 : inMove.magnitude) * _settings.DriveStrength); float moveInfluence = _settings.DriveCurve.Evaluate(_state.MoveInfluence); if (!_fullInfluenceReached && _state.MoveInfluence >= 1) { _events.OnFullInfluence?.Invoke(); _fullInfluenceReached = true; } Vector3 offset = _references.Target.position - OctoPlayer.Instance.transform.position; Vector3 offset2D = offset; offset2D.y = 0; float driveAtten = Mathf.InverseLerp(1, .1f, offset2D.magnitude); Vector3 driveMove = offset; driveMove.y = 0; driveMove = driveMove.normalized * (_state.ForcePlayerToFollowTarget ? 1 : inMove.magnitude); driveMove = Vector3.Lerp(driveMove, Vector3.zero, driveAtten); outMove = Vector3.Lerp(inMove, driveMove, moveInfluence); } public void ApplyLookInfluence(float inYaw, float inPitch, float deltaTime, out float outYaw, out float outPitch) { if (!OctoPlayer.Instance || !OctoPlayer.Instance._FirstPerson.Camera || !_references.LookAt) { outYaw = inYaw; outPitch = inPitch; return; } Vector3 lookAt = _references.LookAt.position - OctoPlayer.Instance._FirstPerson.Camera.transform.position; lookAt = lookAt.normalized; Vector3 offset = _references.Target.position - OctoPlayer.Instance.transform.position; Vector3 offset2D = offset; offset2D.y = 0; float lookAtYaw = Mathf.Atan2(lookAt.x, lookAt.z) * Mathf.Rad2Deg; float lookAtPitch = Mathf.Asin(-lookAt.y) * Mathf.Rad2Deg; _state.LookInfluence = Mathf.InverseLerp(_settings.LookAtPoint, 1, _state.MoveInfluence) * _settings.LookAtStrength; float lookInfluence = _settings.LookCurve.Evaluate(_state.LookInfluence); float t = deltaTime * _settings.LookAtSmooth; _state.YawRange = Mathf.Lerp(_state.YawRange, Mathf.Lerp(180, 0, lookInfluence), t); _state.PitchRange = Mathf.Lerp(_state.PitchRange, Mathf.Lerp(90, 0, lookInfluence), t); outYaw = lookAtYaw + Mathf.Clamp(Mathf.DeltaAngle(lookAtYaw, inYaw), -_state.YawRange, _state.YawRange); outPitch = lookAtPitch + Mathf.Clamp(Mathf.DeltaAngle(lookAtPitch, inPitch), -_state.PitchRange, _state.PitchRange); } } }