CapersProject/Assets/02.Scripts/Skill/Enemy/Boss/SandMole/SingleRoll.cs

222 lines
9.5 KiB
C#

using System;
using System.Collections;
using BlueWater.Audios;
using BlueWater.Interfaces;
using BlueWater.Maps;
using BlueWater.Players;
using BlueWater.Utility;
using Sirenix.OdinInspector;
using UnityEngine;
using Random = UnityEngine.Random;
namespace BlueWater.Enemies.Bosses.SandMole.Skills
{
public class SingleRoll : BaseSkill
{
[Title("추가 옵션")]
[SerializeField]
private bool _isDrawingGizmo = true;
private SingleRollData _singleRollData;
private SpineController _spineController;
private Rigidbody _userRigidbody;
private CapsuleCollider _userCollider;
private Collider _targetCollider;
private ICurrentDirection _iCurrentDirection;
private Transform _particleInstantiateLocation;
private float _colliderRadius;
private float _attackRadius;
private void OnDrawGizmos()
{
if (!_isDrawingGizmo || !IsUsingSkill || !SkillUser) return;
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(SkillUser.transform.position, _attackRadius);
}
protected override void BasicSetting()
{
_singleRollData = (SingleRollData)SkillData;
_spineController = SkillUser.GetComponent<SpineController>();
_userRigidbody = SkillUser.GetComponent<Rigidbody>();
_userCollider = SkillUser.GetComponent<CapsuleCollider>();
_targetCollider = SkillUser.GetComponent<ITarget>().Target;
_particleInstantiateLocation = MapManager.Instance.SandMoleMapController.ParticleInstanceLocation;
_iCurrentDirection = SkillUser.GetComponent<ICurrentDirection>();
_colliderRadius = _userCollider.radius * SkillUser.transform.localScale.x;
_attackRadius = _colliderRadius * 0.5f;
HitColliders = new Collider[4];
base.BasicSetting();
}
public override void ActivateSkill(params Action[] actions)
{
Utils.StartUniqueCoroutine(this, ref SkillCoroutineInstance, SkillCoroutine(actions));
}
private IEnumerator SkillCoroutine(params Action[] actions)
{
EnableSkill = false;
_spineController.SetSkin(SandMoleSkin.Idle.ToString());
var spinReady2Track = _spineController.PlayAnimation(SandMoleAnimation.SpinReady2.ToString(), false);
if (spinReady2Track == null)
{
EndSkill(0, actions[0]);
yield break;
}
AudioManager.Instance.PlaySfx("SandMoleRoll");
yield return new WaitUntil(() => spinReady2Track.IsComplete);
_spineController.SetSkin(SandMoleSkin.Spin.ToString());
var spinTrack = _spineController.PlayAnimation(SandMoleAnimation.Spin.ToString(), true);
if (spinTrack == null || !SkillUser)
{
EndSkill(0, actions[0]);
yield break;
}
IsUsingSkill = true;
var startPosition = SkillUser.transform.position;
var targetPosition = _targetCollider.transform.position;
targetPosition.y = startPosition.y;
var targetVector = targetPosition - startPosition;
var targetDirection = targetVector.normalized;
if (!Physics.Raycast(startPosition, targetDirection, out var hit, 100f, _singleRollData.WallLayer))
{
Debug.LogError("벽을 탐지하지 못했습니다.");
EndSkill(0, actions[0]);
yield break;
}
var targetDistance = hit.distance;
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);
_iCurrentDirection.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();
elapsedTime = 0f;
var isCrashedWall = false;
while (!isCrashedWall)
{
elapsedTime += Time.deltaTime;
if (elapsedTime >= 5f || !SkillUser)
{
if (elapsedTime >= 5f)
{
print("무한 루프 버그");
}
EndSkill(SkillData.Cooldown, actions[0]);
yield break;
}
var skillUserPosition = SkillUser.transform.position;
var moveDistance = _singleRollData.RollSpeed * Time.fixedDeltaTime;
var hitCount = Physics.OverlapSphereNonAlloc(skillUserPosition, _attackRadius, HitColliders,
_singleRollData.TargetLayer, QueryTriggerInteraction.Collide);
for (var i = 0; i < hitCount; i++)
{
var hitCollider = HitColliders[i];
if (hitCollider.CompareTag("Wall"))
{
AudioManager.Instance.PlaySfx("JumpSlamDown");
VisualFeedbackManager.Instance.CameraShake(CombatCameraManager.Instance.BaseCombatCamera,
_singleRollData.CameraShakingPower, _singleRollData.CameraShakingDuration);
var forceDirection = -targetDirection + Vector3.up * _singleRollData.AirJumpForce;
_userRigidbody.linearVelocity = Vector3.zero;
_userRigidbody.AddForce(forceDirection * _singleRollData.BounceBackForce, ForceMode.Impulse);
isCrashedWall = true;
break;
}
var iDamageable = hitCollider.transform.GetComponentInParent<IDamageable>();
if (iDamageable == null || !iDamageable.CanDamage()) continue;
iDamageable.TakeDamage(SkillData.Damage);
var iPhysicMovable = hitCollider.transform.GetComponentInParent<IPhysicMovable>();
if (iPhysicMovable == null) continue;
var hitVector = hitCollider.transform.position - SkillUser.transform.position;
hitVector.y = 0f;
var hitDirection = hitVector.normalized;
iPhysicMovable.SetPush(hitDirection, _singleRollData.PushPower);
// 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 * _singleRollData.PushPower, ForceMode.Impulse);
}
_userRigidbody.MovePosition(skillUserPosition + targetDirection * moveDistance);
yield return new WaitForFixedUpdate();
}
if (_singleRollData.RockfallPrefab)
{
var rockfallCount = (int)(targetDistance / _singleRollData.RockfallInterval);
for (var i = 3; i < rockfallCount; i++)
{
if (!SkillUser)
{
EndSkill(SkillData.Cooldown, actions[0]);
yield break;
}
var randomSide = Random.Range(_singleRollData.RandomSide.x, _singleRollData.RandomSide.y);
var spawnPosition = SkillUser.transform.position
+ -targetDirection * _singleRollData.RockfallInterval * i
+ Vector3.up * _singleRollData.RockfallSpawnHeight;
spawnPosition += Vector3.Cross(-targetDirection, Vector3.up).normalized * randomSide;
Instantiate(_singleRollData.RockfallPrefab, spawnPosition, Quaternion.identity, _particleInstantiateLocation);
}
}
elapsedTime = 0f;
while (elapsedTime < 1f)
{
elapsedTime += Time.deltaTime;
yield return null;
}
EndSkill(SkillData.Cooldown, actions[0]);
}
private void EndSkill(float cooldown, Action action)
{
Utils.EndUniqueCoroutine(this, ref SkillCoroutineInstance);
_spineController.SetSkin(SandMoleSkin.Normal.ToString());
_spineController.PlayAnimation(SandMoleAnimation.Idle.ToString(), true);
action?.Invoke();
IsUsingSkill = false;
Utils.StartUniqueCoroutine(this, ref CooldownCoroutineInstance,Utils.CoolDownCoroutine(cooldown, EndCooldown));
}
}
}