using System; using System.Collections; using BlueWater.Audios; using BlueWater.Interfaces; using BlueWater.Utility; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Rendering.Universal; namespace BlueWater.Enemies.Bosses.Rhinoceros.Skills { public class SkyFallSmash : BaseSkill { [Title("추가 옵션")] [SerializeField] private DecalProjector _stunIndicator; private SkyFallSmashData _skyFallSmashData; private Rhinoceros _rhinoceros; private AnimationController _animationController; private Collider _targetCollider; private static readonly int _colorHash = Shader.PropertyToID("_Color"); protected override void BasicSetting() { if (!_rhinoceros) { _rhinoceros = SkillUser.GetComponent(); _animationController = _rhinoceros.AnimationController; _targetCollider = _rhinoceros.Target; } _skyFallSmashData = (SkyFallSmashData)SkillData; HitColliders = new Collider[4]; if (IsUsingIndicator) { if (Indicator) { Indicator.scaleMode = DecalScaleMode.InheritFromHierarchy; Indicator.material = new Material(Indicator.material); Indicator.material.SetFloat(_fillHash, 0f); } if (_stunIndicator) { _stunIndicator.scaleMode = DecalScaleMode.InheritFromHierarchy; _stunIndicator.material = new Material(_stunIndicator.material); _stunIndicator.material.SetColor(_colorHash, _skyFallSmashData.StunColor); _stunIndicator.material.SetFloat(_fillHash, 0f); } } } protected override void ShowIndicator() { if (IsUsingIndicator) { if (Indicator) { Indicator.material.SetFloat(_fillHash, 0); Indicator.enabled = true; } if (_stunIndicator) { _stunIndicator.material.SetFloat(_fillHash, 0); _stunIndicator.enabled = true; } } } protected override void HideIndicator() { if (IsUsingIndicator) { if (Indicator) { Indicator.enabled = false; Indicator.material.SetFloat(_fillHash, 0); } if (_stunIndicator) { _stunIndicator.enabled = false; _stunIndicator.material.SetFloat(_fillHash, 0); } } } 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.SkyFallSmash); var animationStarted = false; yield return StartCoroutine(_animationController.WaitForAnimationToRun("SkyFallJump", success => animationStarted = success)); if (!animationStarted) { EndSkill(0, actions[0]); yield break; } _rhinoceros.Rigidbody.isKinematic = true; while (_animationController.IsComparingCurrentAnimation("SkyFallJump") && _animationController.GetCurrentAnimationNormalizedTime() <= 1f) { yield return null; } var elapsedTime = 0f; var startPosition = SkillUser.transform.position; var endPosition = startPosition + Vector3.up * _skyFallSmashData.JumpHeight; while (elapsedTime <= _skyFallSmashData.JumpTime) { elapsedTime += Time.deltaTime; SkillUser.transform.position = Vector3.Lerp(startPosition, endPosition, elapsedTime / _skyFallSmashData.JumpTime); yield return null; } SkillUser.transform.position = endPosition; yield return new WaitForSeconds(_skyFallSmashData.WaitTime); var targetPosition = _targetCollider.transform.position; transform.position = targetPosition + Vector3.up * SkillData.Radius; transform.localScale = Vector3.one * (SkillData.Radius * 2f); _stunIndicator.transform.localScale = Vector3.one * (_skyFallSmashData.StunRadiusCoefficient * 2f); startPosition = targetPosition + Vector3.up * _skyFallSmashData.JumpHeight; endPosition = targetPosition; ShowIndicator(); elapsedTime = 0f; var fill = 1 / SkillData.CastingTime; while (elapsedTime <= SkillData.CastingTime) { elapsedTime += Time.deltaTime; if (IsUsingIndicator) { var fillValue = Indicator.material.GetFloat(_fillHash) + Time.deltaTime * fill; if (Indicator) { Indicator.material.SetFloat(_fillHash, fillValue); } if (_stunIndicator) { _stunIndicator.material.SetFloat(_fillHash, fillValue); } } yield return null; } elapsedTime = 0f; while (elapsedTime <= _skyFallSmashData.FallTime) { elapsedTime += Time.deltaTime; SkillUser.transform.position = Vector3.Lerp(startPosition, endPosition, elapsedTime / _skyFallSmashData.FallTime); yield return null; } HideIndicator(); SkillUser.transform.position = endPosition; _rhinoceros.Rigidbody.isKinematic = false; AudioManager.Instance.PlaySfx("SkyFallSmash"); VisualFeedbackManager.Instance.CameraShake(CombatCameraManager.Instance.BaseCombatCamera, _skyFallSmashData.CameraShakingPower, _skyFallSmashData.CameraShakingDuration); var centerPosition = transform.position; var hitCount = Physics.OverlapSphereNonAlloc(centerPosition, SkillData.Radius, HitColliders, _skyFallSmashData.TargetLayer, QueryTriggerInteraction.Collide); var stunRange = SkillData.Radius * _skyFallSmashData.StunRadiusCoefficient; var stunHitCount = Physics.OverlapSphereNonAlloc(centerPosition, stunRange, HitColliders, _skyFallSmashData.TargetLayer, QueryTriggerInteraction.Collide); for (var i = 0; i < hitCount; i++) { var iDamageable = HitColliders[i].GetComponentInParent(); if (iDamageable == null || !iDamageable.CanDamage()) continue; iDamageable.TakeDamage(SkillData.Damage); } for (var i = 0; i < stunHitCount; i++) { var hitCollider = HitColliders[i]; var iStunnable = hitCollider.transform.GetComponentInParent(); if (iStunnable != null && iStunnable.CanStun()) { iStunnable.Stun(_skyFallSmashData.StunDuration); var iPhysicMovable = hitCollider.GetComponentInParent(); var hitVector = hitCollider.transform.position - transform.position; hitVector.y = 0f; var hitDirection = hitVector.normalized; hitDirection = hitDirection == Vector3.zero ? Vector3.right : hitDirection; var hitDistance = hitVector.magnitude; var powerCoefficient = stunRange - hitDistance; var addForcePower = powerCoefficient / stunRange * _skyFallSmashData.PushPowerCoefficient; iPhysicMovable.SetPush(hitDirection, addForcePower); } } 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(); Utils.StartUniqueCoroutine(this, ref CooldownCoroutineInstance,Utils.CoolDownCoroutine(cooldown, EndCooldown)); } } }