288 lines
9.4 KiB
C#
288 lines
9.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using Sirenix.OdinInspector;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.Serialization;
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
namespace BlueWaterProject
|
|
{
|
|
[Serializable]
|
|
public class ActiveSkill : MonoBehaviour
|
|
{
|
|
#region Properties and variables
|
|
|
|
// So
|
|
[Title("DataSo")]
|
|
[Required("So를 추가해주세요.")]
|
|
[SerializeField] private SkillIndicatorDataSo skillIndicatorDataSo;
|
|
|
|
[field: SerializeField] public ActiveSkillData ActiveSkillData { get; set; }
|
|
|
|
// Data
|
|
[Title("Indicator Data")]
|
|
[SerializeField] private DecalProjector indicator;
|
|
|
|
[field: DisableIf("@true")]
|
|
[field: SerializeField] public bool IsCasting { get; set; }
|
|
|
|
[DisableIf("@true")]
|
|
[SerializeField] private bool followMouse;
|
|
|
|
private Camera mainCam;
|
|
private Transform user;
|
|
|
|
private Collider[] hitColliders;
|
|
|
|
// Hash
|
|
private static readonly int FillHash = Shader.PropertyToID("_Fill");
|
|
|
|
#endregion
|
|
|
|
#region Unity built-in methods
|
|
|
|
private void Awake()
|
|
{
|
|
InitComponent();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (followMouse)
|
|
{
|
|
FollowMouse();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Custorm methods
|
|
|
|
private void InitComponent()
|
|
{
|
|
indicator = GetComponentInChildren<DecalProjector>();
|
|
if (indicator == null)
|
|
{
|
|
print("하위 오브젝트로 DecalProjector 컴포넌트를 찾을 수 없습니다.");
|
|
}
|
|
|
|
mainCam = Camera.main;
|
|
}
|
|
|
|
private void BasicSetting()
|
|
{
|
|
transform.localPosition = Vector3.zero;
|
|
indicator.transform.localScale = new Vector3(ActiveSkillData.Range, ActiveSkillData.Range, 1);
|
|
indicator.scaleMode = DecalScaleMode.InheritFromHierarchy;
|
|
indicator.material.SetFloat(FillHash, 0f);
|
|
}
|
|
|
|
public void ChangeIndicatorType()
|
|
{
|
|
if (ActiveSkillData == null)
|
|
{
|
|
print("스킬의 대한 정보가 입력되지 않았습니다.");
|
|
return;
|
|
}
|
|
|
|
HideIndicator();
|
|
BasicSetting();
|
|
hitColliders = new Collider[ActiveSkillData.MaxAttackTargets];
|
|
|
|
if (ActiveSkillData.Indicator != null)
|
|
{
|
|
indicator.material = ActiveSkillData.Indicator;
|
|
return;
|
|
}
|
|
|
|
switch (ActiveSkillData.IndicatorType)
|
|
{
|
|
case EIndicatorType.NONE:
|
|
indicator.material = null;
|
|
break;
|
|
case EIndicatorType.RADIUS:
|
|
indicator.material = new Material(skillIndicatorDataSo.RadiusIndicator);
|
|
break;
|
|
case EIndicatorType.AREA:
|
|
indicator.material = new Material(skillIndicatorDataSo.AreaIndicator);
|
|
break;
|
|
case EIndicatorType.CONE:
|
|
indicator.material = new Material(skillIndicatorDataSo.ConeIndicator);
|
|
break;
|
|
case EIndicatorType.LINE:
|
|
indicator.material = new Material(skillIndicatorDataSo.LineIndicator);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private void HideIndicator()
|
|
{
|
|
indicator.enabled = false;
|
|
indicator.material.SetFloat(FillHash, 0);
|
|
IsCasting = false;
|
|
followMouse = false;
|
|
}
|
|
|
|
public IEnumerator ShowIndicator()
|
|
{
|
|
indicator.transform.position = user.position;
|
|
indicator.material.SetFloat(FillHash, 0);
|
|
indicator.enabled = true;
|
|
|
|
while (true)
|
|
{
|
|
indicator.transform.position = user.position;
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
private void InterruptIndicator()
|
|
{
|
|
HideIndicator();
|
|
}
|
|
|
|
public void Execute(LayerMask targetLayer, Vector3 targetPos)
|
|
{
|
|
switch (ActiveSkillData.IndicatorType)
|
|
{
|
|
case EIndicatorType.NONE:
|
|
indicator.material = null;
|
|
break;
|
|
case EIndicatorType.RADIUS:
|
|
StartCoroutine(RadiusSkill(targetLayer, targetPos));
|
|
break;
|
|
case EIndicatorType.AREA:
|
|
StartCoroutine(AreaSkill(targetLayer, targetPos));
|
|
break;
|
|
case EIndicatorType.CONE:
|
|
|
|
break;
|
|
case EIndicatorType.LINE:
|
|
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
private IEnumerator RadiusSkill(LayerMask targetLayer, Vector3 targetPos)
|
|
{
|
|
indicator.transform.position = targetPos;
|
|
indicator.enabled = true;
|
|
|
|
if (ActiveSkillData.CastingTime > 0)
|
|
{
|
|
IsCasting = true;
|
|
var castingTime = 1 / ActiveSkillData.CastingTime;
|
|
|
|
while (IsCasting && indicator.material.GetFloat(FillHash) < 1f)
|
|
{
|
|
CastingMove();
|
|
var fillValue = indicator.material.GetFloat(FillHash) + Time.deltaTime * castingTime;
|
|
indicator.material.SetFloat(FillHash, fillValue);
|
|
yield return null;
|
|
}
|
|
}
|
|
else if (ActiveSkillData.CastingTime == 0)
|
|
{
|
|
|
|
}
|
|
|
|
// TODO : 터지는 효과 추가하기
|
|
|
|
HideIndicator();
|
|
if (ActiveSkillData.SkillEffect != null)
|
|
{
|
|
var skillEffect = Instantiate(ActiveSkillData.SkillEffect, indicator.transform.position, ActiveSkillData.SkillEffect.transform.rotation);
|
|
skillEffect.Clear();
|
|
skillEffect.Play();
|
|
}
|
|
|
|
Array.Clear(hitColliders, 0,ActiveSkillData.MaxAttackTargets);
|
|
var maxSize = Physics.OverlapSphereNonAlloc(indicator.transform.position, ActiveSkillData.Range, hitColliders, targetLayer);
|
|
|
|
for (var i = 0; i < maxSize; i++)
|
|
{
|
|
var iDamageable = hitColliders[i].GetComponent<IDamageable>();
|
|
iDamageable.TakeDamage(ActiveSkillData.Damage);
|
|
}
|
|
}
|
|
|
|
private IEnumerator AreaSkill(LayerMask targetLayer, Vector3 targetPos)
|
|
{
|
|
followMouse = true;
|
|
indicator.enabled = true;
|
|
|
|
if (ActiveSkillData.CastingTime > 0)
|
|
{
|
|
IsCasting = true;
|
|
var castingTime = 1 / ActiveSkillData.CastingTime;
|
|
|
|
while (IsCasting && indicator.material.GetFloat(FillHash) < 1f)
|
|
{
|
|
CastingMove();
|
|
var fillValue = indicator.material.GetFloat(FillHash) + Time.deltaTime * castingTime;
|
|
indicator.material.SetFloat(FillHash, fillValue);
|
|
yield return null;
|
|
}
|
|
}
|
|
else if (ActiveSkillData.CastingTime == 0)
|
|
{
|
|
|
|
}
|
|
|
|
// TODO : 터지는 효과 추가하기
|
|
|
|
HideIndicator();
|
|
if (ActiveSkillData.SkillEffect != null)
|
|
{
|
|
var skillEffect = Instantiate(ActiveSkillData.SkillEffect, indicator.transform.position, ActiveSkillData.SkillEffect.transform.rotation);
|
|
skillEffect.Clear();
|
|
skillEffect.Play();
|
|
}
|
|
|
|
Array.Clear(hitColliders, 0,ActiveSkillData.MaxAttackTargets);
|
|
var maxSize = Physics.OverlapSphereNonAlloc(indicator.transform.position, ActiveSkillData.Range, hitColliders, targetLayer);
|
|
|
|
for (var i = 0; i < maxSize; i++)
|
|
{
|
|
var iDamageable = hitColliders[i].GetComponent<IDamageable>();
|
|
iDamageable.TakeDamage(ActiveSkillData.Damage);
|
|
}
|
|
}
|
|
|
|
private void CastingMove()
|
|
{
|
|
switch (ActiveSkillData.CastingType)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
transform.position = user.position;
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected void FollowMouse()
|
|
{
|
|
var ray = mainCam.ScreenPointToRay(Input.mousePosition);
|
|
if (Physics.Raycast(ray, out var raycastHit, 2000))
|
|
{
|
|
var userPos = user.position;
|
|
var targetPos = (userPos + raycastHit.point) / 2;
|
|
var distance = targetPos - userPos;
|
|
distance = Vector3.ClampMagnitude((distance * 2), ActiveSkillData.Range);
|
|
indicator.transform.position = userPos + distance;
|
|
}
|
|
}
|
|
|
|
public void SetUser(Transform value) => user = value;
|
|
|
|
#endregion
|
|
}
|
|
} |