[Unity 강의] 뱀서라이크 강의 - 스킬(투사체)
카테고리: Class VamSurLike
태그: C#, Unity, VamSurLike
스킬 코드
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에서 할지
=>? 몬스터가 스킬을 쓰면?
버프 중첩은 어떻게 할까? 상위 버프만 하나 적용할 경우도 있고, 중첩해야 될 경우도 있다.
투사체 바라보는 방향 말고 제일 가까운 적으로 수정해 보기.
댓글남기기