[Unity 강의] 뱀서라이크 강의 - 스킬(투사체)

업데이트:

카테고리:

태그: , ,




스킬 코드

SkillController

✔ 모든 스킬은 삭제되어야 된다. -> SkillController로
✔ 스킬의 삭제 -> 코루틴으로 Pool로 다시 반환
✔ 모든 스킬 생성 후 delaySeconds로 일정 시간 후 Despawn()

SkillController
using System.Collections;
using UnityEngine;

// EgoSword : 평타
// FireProjectile : 투사체
// PoisonField : 바닥
public class SkillController : BaseController
{
    public SkillType SkillType {get; set;}
    public Data.SkillData SkillData { get; protected set; }

    #region Destroy
    Coroutine _coDestroy;

    public void StartDestroy(float delaySeconds) 
    {
        StopDestroy();
        _coDestroy = StartCoroutine(CoDestroy(delaySeconds));
    }

    public void StopDestroy() 
    {
        if (_coDestroy!=null)
        {
            StopCoroutine(_coDestroy);
            _coDestroy = null;
        }
    }

    IEnumerator CoDestroy(float delaySecond) 
    {
        yield return new WaitForSeconds(delaySecond);
        if (this.IsValid())
        {
            Managers.Object.Despawn(this);
        }
    }
    #endregion
}



ProjectileController

투사체 스킬 구성
🔹 투사체를 발사한 객체 : _owner
🔹 투사체의 방향 : _moveDir
🔹 투사체 속도 : _speed
🔹 투사체 지속시간 : _lifeTime
✅ 초기화하는 코드 Init()
✅ SET 코드 (정보를 세팅하는) (🔹위 4개를 세팅)
✅ OnTriggerEnter2D 몬스터 Trigger 시 대미지, Despawn

ProjectileController
using UnityEngine;

public class ProjectileController : SkillController
{
    CreatureController _owner;
    Vector3 _moveDir;
    float _speed = 10.0f;
    float _lifeTime = 10.0f;

    //✅ 초기화하는 코드 Init()
    public override bool Init()
    {
        base.Init();

        StartDestroy(_lifeTime);

        return true;
    }

    //✅ SET 코드 (정보를 세팅하는)
    public void SetInfo(int templateID, CreatureController owner, Vector3 moveDir) 
    {
        if (Managers.Data.SkillDic.TryGetValue(templateID, out Data.SkillData data) == false) 
        {
            Debug.Log($" ID : {templateID} ProjecteController SetInfo Failed ");
            return;
        }

        _owner = owner;
        _moveDir = moveDir;
        SkillData = data;
        //TODO : DATA Parsing

    }

    public override void UpdateController()
    {
        base.UpdateController();

        transform.position += _moveDir * _speed * Time.deltaTime;
    }


    //✅ OnTriggerEnter2D 몬스터 Trigger 시 대미지, Despawn  
    void OnTriggerEnter2D(Collider2D collision)
    {
        MonsterController mc = collision.gameObject.GetComponent<MonsterController>();
        if (mc.IsValid() == false)
            return;
        if (this.IsValid() == false)
            return;

        mc.OnDamaged(_owner, SkillData.damage);

        StopDestroy();
        Managers.Object.Despawn(this);
    }
}



ObjectManager

✔ 투사체의 스폰, 디스폰 관리

ObjectManager
public class ObjectManager 
{
    public HashSet<ProjectileController> Projectiles { get; } = new HashSet<ProjectileController>();

    public T Spawn<T>(Vector3 position, int  templateID =0) where T : BaseController 
    {
        System.Type type = typeof(T);

        else if (type == typeof(ProjectileController))
        {
            GameObject go = Managers.Resource.Instantiate(SkillPrefabsName.FireProjectile, pooling: true);
            go.transform.position = position;

            ProjectileController pc = go.GetOrAddComponent<ProjectileController>();
            Projectiles.Add(pc);
            pc.Init();

            return pc as T;
        }
        return null;
    }

    public void Despawn<T>(T obj) where T : BaseController 
    {
        if (obj.IsValid()==false)
        {
            // 디버깅코드
            Debug.Log($"Object Pool Error Debuging");
        }
        System.Type type = typeof(T);

        else if (type == typeof(ProjectileController))
        {
            Projectiles.Remove(obj as ProjectileController);
            Managers.Resource.Destroy(obj.gameObject);
        }
}



PlayerController

✔ _indicator, _fireSocket로 발사체의 시작 지점, Player 정지 시 발사체 정지 문제 해결.
✔ 플레이어 생성 시 - StartProjectile() : 일정 시간 투사체 생성, 투사체의 정보 SET

PlayerController
public class PlayerController : CreatureController
{
    Vector2 _moverDir = Vector2.zero;

    float EnvCollectDist { get; set; } = 1.0f;

    [SerializeField]
    Transform _indicator;
    [SerializeField]
    Transform _fireSocket;

    public Vector2 MoveDir 
    {
        get { return _moverDir; }
        set { _moverDir = value.normalized; }
    }


    public override bool Init()
    {
        if (base.Init() == false)
            return false;
        _speed = 5.0f;

        Managers.Game.OnMoveDirChanged += HandleOnMoveDirChanged;

        StartProjectile();

        return true;
    }

    //Temp
    #region FireProjectile

    Coroutine _coFireProjectile;

    void StartProjectile() 
    {
        if (_coFireProjectile != null)
            StopCoroutine(_coFireProjectile);
        _coFireProjectile = StartCoroutine(CoFireProjectile());
    }

    IEnumerator CoFireProjectile() 
    {
        WaitForSeconds wait = new WaitForSeconds(2f);
        while (true)
        {
            ProjectileController pc = Managers.Object.Spawn<ProjectileController>(_fireSocket.position,1);
            pc.SetInfo(1, this, (_fireSocket.position-_indicator.position).normalized);
            yield return wait;
        }
    }
    #endregion
}





이것저것 메모

스킬 데이터,프리팹, 계층구조 확인

스킬 프리팹, 데이터 어드레서블에 추가
프리팹을 사용해 스킬이 발동된다.
스킬 계층구조 만들기(SkillController -> ProjectileController)

아이템, 인벤토리, 스킬의 monobehaviour상속?

아이템, 인벤토리는 monobehaviour이 필요 없이 메모리에만 들고 있으면 된다.
스킬은 화면에 표시하기 때문에 monobehaviour 필요

오브젝트 풀 오류 체크

풀링 오류 체크 Extension - IsValid로 체크하기
✔ 이미 죽은 target이 destroy 가 아닌 비활성화이기 때문에
✔ 아직 target으로 설정돼 코드가 실행되면 에러가 발생할 수 있다.

Extension
using UnityEngine;

public static class Extension
{
	public static bool IsValid(this GameObject go)
	{
		return go != null && go.activeSelf;
	}

	public static bool IsValid(this BaseController bc)
	{
		return bc != null && bc.isActiveAndEnabled;
	}
}





잡담, 일기?

스킬 만들때 고민
데이터 설계 정하고,
스킬들(버프, 패시브, 발동)을 스킬 매니저로 따로 관리할지, PlayerController에서 할지
=>? 몬스터가 스킬을 쓰면?
버프 중첩은 어떻게 할까? 상위 버프만 하나 적용할 경우도 있고, 중첩해야 될 경우도 있다.
투사체 바라보는 방향 말고 제일 가까운 적으로 수정해 보기.




📔

댓글남기기