164 lines
7.1 KiB
C#
164 lines
7.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using BlueWater.Interfaces;
|
|
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 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<Rhinoceros>();
|
|
_animationController = _rhinoceros.AnimationController;
|
|
_targetCollider = _rhinoceros.Target;
|
|
_particleInstantiateLocation = _rhinoceros.BossMapController.ParticleInstanceLocation;
|
|
}
|
|
_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,
|
|
_meteorSwingData.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<IDamageable>();
|
|
if (iDamageable == null || !iDamageable.CanDamage()) continue;
|
|
|
|
iDamageable.TakeDamage(SkillData.Damage);
|
|
|
|
var iStunnable = hitCollider.transform.GetComponentInParent<IStunnable>();
|
|
iStunnable?.TryStun(_meteorSwingData.StunDuration);
|
|
|
|
var iPhysicMovable = hitCollider.GetComponentInParent<IPhysicMovable>();
|
|
iPhysicMovable?.SetPush(attackDirection, _meteorSwingData.PushPower);
|
|
}
|
|
|
|
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<ProjectileController>();
|
|
projectile.Initialize(_meteorSwingData.ProjectileDamage, _meteorSwingData.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));
|
|
}
|
|
}
|
|
} |