게임 개발 공부 기록

63일차 - Abyss_Slayer 최종 팀 프로젝트 13 (메이지 스킬 수정)

00lwt 2025. 4. 22. 21:01

오늘은 기존의 레이캐스트를 사용하는 방식에서 콜라이더를 사용하는 방식으로 메이지의 s스킬을 수정하였다.


RemoteZoneSkill.cs

[CreateAssetMenu(fileName = "RemoteZoneSkill", menuName = "SkillRefactory/Range/RemoteZoneSkill")]
public class RemoteZoneSkill : RangeAttackSkill
{
    [SerializeField] private float sizeX = 1;
    [SerializeField] private float sizeY = 1;
    [SerializeField] private float tickRate = 0.5f; // 몇 초 마다?
    [SerializeField] private float duration = 3f; // 얼마나 유지?

    [Header("플레이어 기준 offset")]
    [SerializeField] private Vector2 spawnOffset = new Vector2( 5f, 0f ); // 플레이어 기준 거리

    [Header("effect 이름")]
    [SerializeField] private string effectName;

    public override void UseSkill()
    {
        Vector2 offset = new Vector2(spawnOffset.x * PlayerFrontXNormalized(), spawnOffset.y);
        Vector3 spawnPos = player.transform.position + (Vector3)offset;

        // 풀에서 ZoneAOE 꺼내기
        var zone = PoolManager.Instance.Get<ZoneAOE>();
        zone.Init(player, spawnPos, sizeX, sizeY, tickRate, duration, Damage, TargetLayer, effectName);
    }
}

RemoteZoneSkill은 RangeAttackSkill을 상속받는 스킬 스크립트로 스킬 콜라이더의 크기와 연속 타격 시 각 데미지 사이의 간격과 해당 효과가 지속되는 시간을 포함하고 있다.

플레이어가 바라보는 방향을 기준으로 전방으로 일정거리에 생성되게 하였고 마찬가지로 성능을 생각하여 생성 파괴가 아닌 오브젝트 풀링을 사용하였다.

ZoneAOE.cs

public class ZoneAOE : BasePoolable
{
    private float duration;
    private float tickInterval;
    private float damage;
    private float range;
    private LayerMask targetLayer;

    private Coroutine tickCoroutine; // 틱뎀 줄 코루틴
    private Coroutine ReturnToPoolCoroutine; // 풀로 돌려보내는 코루틴
    private HashSet<IHasHealth> targetsInRange = new();
    [SerializeField] private GameObject effectPrefab; // 이펙트 프리팹
    private Player player;
    
    public override void Init()
    {

    }
    
    public override void Init(Vector3 spawnPos, float sizeX, float sizeY, float tickRate, float _duration, float damage, LayerMask targetLayer, string effectName)
    {
        // 기본 세팅
        this.duration = _duration;
        this.tickInterval = tickRate;
        this.damage = damage;
        this.targetLayer = targetLayer;
        this.range = Mathf.Max(sizeX, sizeY);

        // 위치 세팅
        transform.position = spawnPos;

        // 애니메이터 세팅
        SetActiveAnimator(effectName);

        // 박스 콜라이더 세팅
        var col = GetComponent<BoxCollider2D>();
        col.isTrigger = true;
        col.size = new Vector2(sizeX, sizeY);

        // meleedamagecheck 세팅
        var meleeCheck = GetComponent<MeleeDamageCheck>();
        System.Type fxType = null;
        meleeCheck.Init(sizeX, sizeY, damage, fxType, _duration);
        meleeCheck.SetRepeatMode(true, tickRate);

        gameObject.SetActive(true);

        // duration 후 풀에 자동 반환
        if (ReturnToPoolCoroutine != null) StopCoroutine(ReturnToPoolCoroutine);
        ReturnToPoolCoroutine = StartCoroutine(ReturnTOPool(_duration, targetLayer));
    }

    public void Init(Player player, Vector3 spawnPos, float sizeX, float sizeY, float tickRate, float _duration, float damage, LayerMask targetLayer, string effectName)
    {
        this.player = player;
        Init(spawnPos, sizeX, sizeY, tickRate, _duration, damage, targetLayer, effectName);
    }

    private IEnumerator ReturnTOPool(float seconds, LayerMask targetLayer)
    {
        yield return new WaitForSeconds(seconds);
        if (effectPrefab != null)
            effectPrefab.SetActive(false);
        ReturnToPool();
    }

    // 애니메이터 활성화
    private void SetActiveAnimator(string effectName){
        // 존 이펙트 활성화
        if (effectPrefab != null)
        {   // 이펙트 길이 맞추기
            effectPrefab.SetActive(true);

            var effectSprite = GetComponentInChildren<SpriteRenderer>();
            bool flip = player.SpriteRenderer.flipX ? true : false;
            effectSprite.flipX = flip;

            var animator = effectPrefab.GetComponentInChildren<Animator>();
            animator.runtimeAnimatorController = ChangeAnimatior(effectName);
            if (animator != null && animator.runtimeAnimatorController != null)
            {
                // 첫 번째 클립 길이 가져오기
                var clips = animator.runtimeAnimatorController.animationClips;
                if (clips.Length > 0)
                {
                    float clipLength = clips[0].length;
                    // clipLength 초짜리 애니메이션을 duration 초에 맞춰 재생
                    animator.speed = clipLength / duration;
                    // 애니메이션 처음부터 재생
                    animator.Play(clips[0].name, 0, 0f);
                }
            }
        }
    }

    // 애니메이터 가져오기 << 나중에 미리 캐싱해두기
    private RuntimeAnimatorController ChangeAnimatior(string effectName)
    {
       return Resources.Load<RuntimeAnimatorController>("Effect/Animator/" + effectName);   
    }

범위 공격에 쓰일 이펙트와 콜라이더에 대한 스크립트인데 내용은 길어보이지만 간단하게 정리하자면
전달받은 데이터, 애니메이터, 콜라이더 등을 세팅하는 메소드와, 풀로 반환하는 역할을 하는 코루틴, 애니메이터를 활성화하는 메소드로 구성되어있다.
이펙트는 스킬에 맞는 애니메이터를 Resources 폴더에서 이름 텍스트를 통해 가져오는 방식이고 나중에 미리 캐싱하도록 수정할 예정이다.


내일은 일반 공격도 이펙트를 두껍게 넣을 생각이라면 마찬가지로 레이캐스트에서 콜라이더로 수정할 예정이고
그 다음엔 메이지의 마지막 스킬인 쇼크웨이브를 마저 구현하고 메이지를 마무리 할 예정이다.