이번 포스트부터는 RPG에서 사용가능한 스킬 시스템을 만들어보겠습니다.
스킬 시스템은 크게 2가지로 동작하는데,
스킬에 필요한 애니메이션과 각 스킬의 스크립트의 2가지로 구성되어 동작하게 됩니다.
이때 스킬 시스템은 캐릭터에 종속적이지 않고
싱글톤으로 동작하는 SkillSystemManager에 의해 동작할 예정입니다.
1) 기존의 문제를 수정
기존에 사용하던 몬스터가 전투를 수행하기 위한 전투 상태 돌입의 코드에서
FindObject 함수를 통해 플레이어를 탐색하고 있었습니다.
유니티의 FindObject는 언리얼 엔진과는 다르게 매우 비효율적이므로
Player를 담당하는 PlayerManager를 생성해 이를 해결하도록 하겠습니다.
1 - 1) PlayerManager
public class PlayerManager : MonoBehaviour
{
public static PlayerManager _playerManagerInstance;
public PlayerController _playerController;
private void Awake()
{
// _playerManagerInstance가 이미 존재하다면, 해당 컴포넌트를 지닌 게임 오브젝트 파괴
if (_playerManagerInstance != null)
Destroy(_playerManagerInstance.gameObject);
// _playerManagerInstance를 재설정
_playerManagerInstance = this;
}
}
1 - 2) SkeletonStateEngage
public class SkeletonStateEngage : EnemyState
{
.
.
.
public override void Enter()
{
base.Enter();
// 존재하는 PlayerManager를 가져와서 해당 PlayerManager에 설정된 PlayerController를 가져옴
_player = PlayerManager._playerManagerInstance._playerController.transform;
}
.
.
.
}
1 - 3) SkeletonStateGrounded
public class SkeletonStateGrounded : EnemyState
{
.
.
.
public override void Enter()
{
base.Enter();
// 마찬가지로, PlayerManager로부터 PlayerController를 가져옴
_player = PlayerManager._playerManagerInstance._playerController.transform;
}
.
.
.
}
2) 스킬 시스템을 위한 구성
기존의 문제를 수정하였으므로 이제 본론으로 들어가 스킬 시스템을 위한 구성을 보겠습니다.
스킬 시스템은 스킬을 수행하는 주체인 SkillManager와 각 스킬의 스크립트들로 구성되어 있습니다.
이번에는 간단하게 대쉬 스킬을 구현하고 기존의 PlayerController에서 사용하던
대쉬와 관련된 불필요해진 멤버 변수들을 삭제하겠습니다.
2 - 1) SkillManager
public class SkillManager : MonoBehaviour
{
public static SkillManager _skillManagerInstance;
// SkillManager는 스킬을 수행하는 주체이므로, 각 스킬에 대해 알고 있어야 함
public SkillDash _skillDash { get; private set; }
private void Awake()
{
// 기존에 SkillManager가 존재한다면, SkillManager를 컴포넌트로 가진 게임 오브젝트 파괴
if(_skillManagerInstance != null)
Destroy(_skillManagerInstance.gameObject);
_skillManagerInstance = this;
}
// 스킬을 가져와서 설정
private void Start()
{
_skillDash = GetComponent<SkillDash>();
}
}
2 - 2) SkillTemplate
public class SkillTemplate : MonoBehaviour
{
// 모든 스킬들의 원형인 SkillTemplate에서는 스킬들의 공통적인 프로퍼티를 갖고 있음 - 쿨타임
[SerializeField]
protected float _cooldown;
protected float _cooldownTimer;
// 주기적으로 _cooldownTimer를 감소
protected virtual void Update()
{
_cooldownTimer -= Time.deltaTime;
}
// 스킬 사용 가능 여부를 판단하는 함수
public virtual bool DoDefineCanUseSkill()
{
// _cooldownTimer가 0보다 작으면 스킬 사용 가능
if (_cooldownTimer < 0)
{
DoUseSkill();
_cooldownTimer = _cooldown;
return true;
}
Debug.Log("Skill is on cooldown");
return false;
}
// 오버라이드한 자손 스킬들이 자신의 로직을 수행할 때 사용하는 함수
public virtual void DoUseSkill()
{
// 스킬 함수의 로직 수행
}
}
2 - 3) SkillDash
public class SkillDash : SkillTemplate
{
public override void DoUseSkill()
{
base.DoUseSkill();
Debug.Log("Use Skill");
}
}
2 - 4) PlayerController
public class PlayerController : BaseCharacterController
{
.
.
.
// Dash Info
public float _dashSpeed;
public float _dashDuration;
public float _dashDir { get; private set; }
.
.
.
void DoDash(InputAction.CallbackContext value)
{
if (DoDetectIsFacingWall())
return;
if (value.ReadValueAsButton() && SkillManager._skillManagerInstance._skillDash.DoDefineCanUseSkill())
{
_dashDir = _moveAction.ReadValue<Vector2>().x;
if (_dashDir == 0)
_dashDir = _facingDir;
_stateMachine.ChangeState(_dashState);
}
}
.
.
.
}
최종적으로 PlayerController에서 따로 Dash에 필요한 쿨타임을 측정할 변수가 필요없어졌습니다.
3) 결과확인
마지막으로 유니티 에디터의 설정과 최종 결과를 확인해보겠습니다.
SkillManager의 오브젝트 설정입니다.
다음으로 PlayerManager의 오브젝트 설정입니다.
기존의 Player에서 설정하던 대쉬 관련 쿨타임 변수들을 설정하지 않아도 됩니다.
최종 실행 결과는 다음과 같습니다.
쿨타임동안에는 대쉬를 할 수 없지만,
쿨타임이 끝난 직후에는 문제없이 대쉬를 수행하고 있는 것을 확인할 수 있습니다.
'유니티 > 게임 프로젝트' 카테고리의 다른 글
2D RPG - (15 - 1) 단검 투척 스킬 구현_01 (0) | 2025.01.27 |
---|---|
2D RPG - (14) 분신술 스킬 구현 (0) | 2025.01.07 |
2D RPG - (12 - 2) 카운터 어택 구현하기 (0) | 2024.12.31 |
2D RPG - (12 - 1) 카운터 어택 구현하기 (0) | 2024.12.31 |
2D RPG - (11) 피격에 따른 효과 구현하기 (0) | 2024.12.30 |