using System; using System.Collections; using BlueWater.Interfaces; using BlueWater.Maps; using BlueWater.Utility; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Rendering.Universal; namespace BlueWater.Enemies.Bosses.Rhinoceros.Skills { public class MeteorSwing : BaseSkill { [Title("추가 옵션")] [SerializeField] private bool _isDrawingGizmo = true; private MeteorSwingData _meteorSwingData; private Rhinoceros _rhinoceros; private AnimationController _animationController; private Collider _targetCollider; private LayerMask _targetLayer; private Transform _particleInstantiateLocation; private static readonly int _angleHash = Shader.PropertyToID("_Angle"); private void OnDrawGizmos() { if (!_isDrawingGizmo || !IsUsingSkill) return; var startPosition = SkillUser.transform.position; var targetDirection = transform.forward; var leftBoundary = Quaternion.Euler(0, -_meteorSwingData.AttackAngle / 2, 0) * targetDirection; var rightBoundary = Quaternion.Euler(0, _meteorSwingData.AttackAngle / 2, 0) * targetDirection; Gizmos.color = Color.red; Gizmos.DrawWireSphere(startPosition, SkillData.Radius); Gizmos.color = Color.yellow; Gizmos.DrawLine(startPosition, startPosition + leftBoundary * SkillData.Radius); Gizmos.DrawLine(startPosition, startPosition + rightBoundary * SkillData.Radius); } protected override void BasicSetting() { if (!_rhinoceros) { _rhinoceros = SkillUser.GetComponent(); _animationController = _rhinoceros.AnimationController; _targetCollider = _rhinoceros.Target; _targetLayer = _rhinoceros.TargetLayer; _particleInstantiateLocation = _rhinoceros.BossMapController.ParticleInstantiateLocation; } _meteorSwingData = (MeteorSwingData)SkillData; HitColliders = new Collider[4]; if (IsUsingIndicator && Indicator) { Indicator.scaleMode = DecalScaleMode.InheritFromHierarchy; Indicator.material = new Material(Indicator.material); Indicator.material.SetFloat(_fillHash, 0f); Indicator.material.SetFloat(_angleHash, _meteorSwingData.AttackAngle); } } 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.MeteorSwing); var animationStarted = false; yield return StartCoroutine(_animationController.WaitForAnimationToRun("MeteorSwing", success => animationStarted = success)); if (!animationStarted) { EndSkill(0, actions[0]); yield break; } IsUsingSkill = true; var startPosition = SkillUser.transform.position; var targetPosition = _targetCollider.transform.position; var targetVector = targetPosition - startPosition; targetVector.y = 0f; var targetDirection = targetVector.normalized; transform.position = startPosition + Vector3.up * SkillData.Radius; var yAngle = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg; transform.rotation = Quaternion.Euler(0, yAngle, 0); transform.localScale = Vector3.one * (SkillData.Radius * 2f); _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; } var hitCount = Physics.OverlapSphereNonAlloc(transform.position, SkillData.Radius, HitColliders, _targetLayer, QueryTriggerInteraction.Collide); for (var i = 0; i < hitCount; i++) { var hitCollider = HitColliders[i]; var hitVector = hitCollider.transform.position - SkillUser.transform.position; hitVector.y = 0f; var attackDirection = hitVector.normalized; var targetAngle = Vector3.Angle(attackDirection, targetDirection); if (targetAngle > _meteorSwingData.AttackAngle * 0.5f) continue; var iDamageable = hitCollider.GetComponentInParent(); if (iDamageable == null || !iDamageable.CanDamage()) continue; iDamageable.TakeDamage(SkillData.Damage); var iStunnable = hitCollider.transform.GetComponentInParent(); iStunnable?.Stun(_meteorSwingData.StunDuration); var iPhysicMovable = hitCollider.GetComponentInParent(); iPhysicMovable?.AddForce(attackDirection * _meteorSwingData.PushPower, ForceMode.Impulse); } HideIndicator(); var startAngle = yAngle - _meteorSwingData.ProjectileAngle * 0.5f; var angleStep = _meteorSwingData.ProjectileAngle / (_meteorSwingData.ProjectileCount - 1); for (var i = 0; i < _meteorSwingData.ProjectileCount; i++) { var currentAngle = startAngle + angleStep * i; var rotation = Quaternion.Euler(0, currentAngle, 0); var projectile = Instantiate(_meteorSwingData.ProjectilePrefab, startPosition + Vector3.up, rotation, _particleInstantiateLocation).GetComponent(); projectile.Initialize(_meteorSwingData.ProjectileDamage, _targetLayer); projectile.AddForce(projectile.transform.forward * _meteorSwingData.ProjectileSpeed, ForceMode.Impulse); } 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)); } } }