using System.Collections; using UnityEngine; using UnityEngine.Pool; using Random = UnityEngine.Random; // ReSharper disable once CheckNamespace namespace BlueWaterProject { public class Arrow : MonoBehaviour { #region Property and variable [Tooltip("화살 발사 시작할 때의 속도")] [SerializeField] private float initialVelocity; [Tooltip("화살이 타겟에 도달하는 오차 범위(부정확함)")] [Range(0f, 1f)] [SerializeField] private float inaccuracy; [Tooltip("발사 이후 자동으로 사라지는데 까지 걸리는 시간")] [Range(0f, 10f)] [SerializeField] private float autoDestroyTime; private Vector3 targetPos; private AiStat attackerStat; private LayerMask targetLayer; private IObjectPool managedArrowPool; private Rigidbody arrowRigidbody; #endregion #region Unity built-in function private void Awake() { arrowRigidbody = Utils.GetComponentAndAssert(transform); } private void OnTriggerEnter(Collider other) { if (other.gameObject.layer != targetLayer) return; var iDamageable = other.GetComponent(); iDamageable.TakeDamage(attackerStat, iDamageable.AiStat); } #endregion #region Custom function public IEnumerator Shoot() { // TODO : 화살 발사 기능 구현 var time = 0f; while (time < autoDestroyTime) { time += Time.deltaTime; var toTarget = targetPos - transform.position; var angle = CalcLaunchAngle(toTarget); angle += Random.Range(-inaccuracy, inaccuracy); var velocity = Quaternion.Euler(0, 0, angle) * Vector3.right * initialVelocity; arrowRigidbody.velocity = velocity; yield return null; } DestroyObject(); } private float CalcLaunchAngle(Vector3 toTarget) { var distance = Vector3.Distance(toTarget, Vector3.zero); var heightDifference = toTarget.y; var gravity = Physics.gravity.magnitude; var velocitySqr = initialVelocity * initialVelocity; var underSqrt = (velocitySqr * velocitySqr) - (gravity * ((gravity * distance * distance) + (2 * heightDifference * velocitySqr))); if (underSqrt >= 0) { var angle1 = Mathf.Atan((velocitySqr + Mathf.Sqrt(underSqrt)) / (gravity * distance)); var angle2 = Mathf.Atan((velocitySqr - Mathf.Sqrt(underSqrt)) / (gravity * distance)); return Mathf.Min(angle1, angle2) * Mathf.Rad2Deg; } else { return 45f; } } public void SetShootingArrow(Vector3 targetPosition, AiStat attacker, int targetLayerMask) { targetPos = targetPosition; attackerStat = attacker; targetLayer = targetLayerMask; } //public void SetAiStat(AiStat attacker) => attackerStat = attacker; //public void SetTargetLayer(int targetLayerMask) => targetLayer = targetLayerMask; #endregion #region ObjectPool function private void DestroyObject() => managedArrowPool.Release(this); public void SetManagedPool(IObjectPool pool) => managedArrowPool = pool; #endregion } }