using System; using System.Collections; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Rendering.Universal; // ReSharper disable once CheckNamespace namespace BlueWaterProject { public enum EIndicatorType { NONE, RADIUS, AREA, CONE, LINE } [Serializable] public class ActiveSkill : MonoBehaviour { #region Properties and variables // So [Title("DataSo")] [Required("So를 추가해주세요.")] [SerializeField] private SkillIndicatorData skillIndicatorDataSo; [Required("So를 추가해주세요.")] [SerializeField] private ActiveSkillData activeSkillDataSo; // Data [Title("Indicator Data")] [SerializeField] private DecalProjector indicator; [OnValueChanged("ChangeIndicatorType")] [SerializeField] private EIndicatorType indicatorType; [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(); InitData(); } private void Update() { if (followMouse) { FollowMouse(); } } #endregion #region Custorm methods private void InitComponent() { indicator = GetComponentInChildren(); if (indicator == null) { print("하위 오브젝트로 DecalProjector 컴포넌트를 찾을 수 없습니다."); } mainCam = Camera.main; } private void InitData() { ChangeIndicatorType(); BasicSetting(); HideIndicator(); hitColliders = new Collider[activeSkillDataSo.MaxAttackTargets]; } private void BasicSetting() { transform.localPosition = Vector3.zero; indicator.transform.localScale = new Vector3(activeSkillDataSo.Range, activeSkillDataSo.Range, 1); indicator.scaleMode = DecalScaleMode.InheritFromHierarchy; indicator.material.SetFloat(FillHash, 0f); } private void ChangeIndicatorType() { if (activeSkillDataSo.Indicator != null) { indicator.material = activeSkillDataSo.Indicator; return; } switch (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; } private void InterruptIndicator() { HideIndicator(); } public void Execute(LayerMask targetLayer, Vector3 targetPos) { switch (indicatorType) { case EIndicatorType.NONE: indicator.material = null; break; case EIndicatorType.RADIUS: StartCoroutine(RadiusSkill(targetLayer, targetPos)); break; case EIndicatorType.AREA: break; case EIndicatorType.CONE: break; case EIndicatorType.LINE: break; default: throw new ArgumentOutOfRangeException(); } } private IEnumerator RadiusSkill(LayerMask targetLayer, Vector3 targetPos) { transform.position = targetPos; indicator.enabled = true; if (activeSkillDataSo.CastingTime > 0) { IsCasting = true; var castingTime = 1 / activeSkillDataSo.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 (activeSkillDataSo.CastingTime == 0) { } // TODO : 터지는 효과 추가하기 HideIndicator(); Array.Clear(hitColliders, 0,activeSkillDataSo.MaxAttackTargets); var maxSize = Physics.OverlapSphereNonAlloc(transform.position, activeSkillDataSo.Range, hitColliders, targetLayer); for (var i = 0; i < maxSize; i++) { var iDamageable = hitColliders[i].GetComponent(); iDamageable.TakeDamage(activeSkillDataSo.Damage); } } private void CastingMove() { switch (activeSkillDataSo.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), activeSkillDataSo.Range); indicator.transform.position = userPos + distance; } } public ActiveSkillData GetActiveSkillData() => activeSkillDataSo; public void SetUser(Transform value) => user = value; #endregion } }