using System; using System.Collections; using BlueWater.Interfaces; using BlueWater.Utility; using Sirenix.OdinInspector; using UnityEngine; namespace BlueWater.Enemies.Bosses.Rhinoceros.Skills { public class BullCharge : BaseSkill { [Title("추가 옵션")] [SerializeField] private bool _isDrawingGizmo = true; private BullChargeData _bullChargeData; private Rhinoceros _rhinoceros; private AnimationController _animationController; private Rigidbody _userRigidbody; private CapsuleCollider _userCollider; private Collider _targetCollider; private float _colliderRadius; private float _attackRadius; private void OnDrawGizmos() { if (!_isDrawingGizmo || !IsUsingSkill) return; Gizmos.color = Color.red; Gizmos.DrawWireSphere(SkillUser.transform.position, _attackRadius); } protected override void BasicSetting() { if (!_rhinoceros) { _rhinoceros = SkillUser.GetComponent(); _animationController = _rhinoceros.AnimationController; _userRigidbody = _rhinoceros.Rigidbody; _userCollider = _rhinoceros.CharacterCollider; _targetCollider = _rhinoceros.Target; _colliderRadius = _userCollider.radius * _rhinoceros.transform.localScale.x; _attackRadius = _colliderRadius * 0.5f; } _bullChargeData = (BullChargeData)SkillData; RaycastHits = new RaycastHit[5]; base.BasicSetting(); } public override void ActivateSkill(params Action[] actions) { Utils.StartUniqueCoroutine(this, ref SkillCoroutineInstance, SkillCoroutine(actions)); } private IEnumerator SkillCoroutine(params Action[] actions) { EnableSkill = false; _rhinoceros.StopMove(); _animationController.SetAnimationParameter("skillIndex", (int)RhinocerosSkill.BullCharge); var animationStarted = false; yield return StartCoroutine(_animationController.WaitForAnimationToRun("BullCharge", success => animationStarted = success)); if (!animationStarted) { EndSkill(0, actions[0]); yield break; } _animationController.ResetAnimationSpeed(); IsUsingSkill = true; var isAttacked = false; var startPosition = SkillUser.transform.position; var targetVector = _targetCollider.transform.position - startPosition; targetVector.y = 0f; var targetDirection = targetVector.normalized; var targetDistance = targetVector.magnitude + _bullChargeData.ChargeOffset; transform.position = startPosition + Vector3.up * 3f; transform.localScale = new Vector3(_colliderRadius, 6f, targetDistance * 2); var angle = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg; transform.rotation = Quaternion.Euler(0, angle, 0); _rhinoceros.CurrentDirection = targetDirection; ShowIndicator(); var elapsedTime = 0f; var fill = 1 / SkillData.CastingTime; while (elapsedTime <= SkillData.CastingTime) { elapsedTime += Time.deltaTime; if (IsUsingIndicator && Indicator) { var fillValue = Indicator.material.GetFloat(_fillHash) + Time.deltaTime * fill; Indicator.material.SetFloat(_fillHash, fillValue); } yield return null; } HideIndicator(); var totalDistanceCovered = 0f; while (totalDistanceCovered < targetDistance) { var moveDistance = _bullChargeData.ChargeSpeed * Time.fixedDeltaTime; var skillUserPosition = SkillUser.transform.position; var hitCount = Physics.SphereCastNonAlloc(skillUserPosition, _attackRadius, targetDirection, RaycastHits, 0f, _bullChargeData.TargetLayer, QueryTriggerInteraction.Collide); _userRigidbody.MovePosition(skillUserPosition + targetDirection * moveDistance); for (var i = 0; i < hitCount; i++) { if (isAttacked) continue; var raycastHit = RaycastHits[i]; var iDamageable = raycastHit.transform.GetComponentInParent(); if (iDamageable == null || !iDamageable.CanDamage()) continue; iDamageable.TakeDamage(SkillData.Damage); isAttacked = true; var iStunnable = raycastHit.transform.GetComponentInParent(); iStunnable?.Stun(_bullChargeData.StunDuration); var iPhysicMovable = raycastHit.transform.GetComponentInParent(); if (iPhysicMovable == null) continue; var hitVector = raycastHit.transform.position - SkillUser.transform.position; hitVector.y = 0f; var hitDirection = hitVector.normalized; var cross = Vector3.Cross(hitDirection, transform.forward); var addForceDirection = cross.y >= 0f ? Quaternion.Euler(0, -90, 0) * transform.forward : Quaternion.Euler(0, 90, 0) * transform.forward; iPhysicMovable.AddForce(addForceDirection * _bullChargeData.PushPower, ForceMode.Impulse); } totalDistanceCovered += moveDistance; yield return new WaitForFixedUpdate(); } EndSkill(SkillData.Cooldown, actions[0]); } private void EndSkill(float cooldown, Action action) { Utils.EndUniqueCoroutine(this, ref SkillCoroutineInstance); _animationController.SetAnimationParameter("skillIndex", (int)RhinocerosSkill.None); action?.Invoke(); IsUsingSkill = false; Utils.StartUniqueCoroutine(this, ref CooldownCoroutineInstance,Utils.CoolDownCoroutine(cooldown, EndCooldown)); } } }