스킬 시전 조건 검증과 자원·쿨타임 잠금 구조
1. 시스템 요구 사항
스킬 애니메이션의 시간 흐름이 명확해졌다고 해서, 스킬 시스템이 완성되는 것은 아니었다.
스킬은 시전 모션이 재생되는 동안만 유지되는 행위가 아니라, 자원 소모와 쿨타임이라는 장기적인 상태 변화를 동반하는 시스템이다.
이때 가장 위험한 지점은 시전 가능 여부 판단과 실제 자원 변경이 분리되지 않은 구조였다.
입력 단계에서 MP를 검사하고, 애니메이션이 시작된 이후에 MP를 차감하거나 쿨타임을 설정하는 방식은, 입력 연타나 프레임 타이밍에 따라 중복 시전이 발생할 수 있다.
특히 매우 짧은 시간 안에 같은 키 입력이 반복되면, “아직 쿨타임이 시작되지 않은 상태”로 인식되어 스킬이 여러 번 실행되는 레이스 컨디션이 생길 여지가 있다.
따라서 스킬 시스템에서는 시전이 허용되었는가와 시전이 시작되었는가를 명확히 구분하고, 시전이 시작되는 순간 자원과 쿨타임을 즉시 잠가 이후 흐름에서 상태가 흔들리지 않도록 만들 필요가 있었다.
2. 설계 목표
- 스킬 시전 가능 여부 판단과 실제 시전 시작을 명확히 분리할 것
- 자원 소모와 쿨타임을 시전 시작 시점에 즉시 잠글 것
- 입력 연타나 프레임 타이밍에 따른 중복 시전을 구조적으로 차단할 것
- 스킬 실행부가 조건 검증 로직을 알 필요 없도록 책임을 분리할 것
3. 흐름도

이 흐름에서 핵심은,TryStartCast를 통과한 순간부터 해당 스킬은 이미 사용 중 상태로 간주된다는 점이다.
이후 애니메이션 전이, 재생, 종료 과정과 관계없이 자원과 쿨타임 상태는 흔들리지 않는다.
4. 구현
4.1. 스킬 실행 조건의 단일 진입점
public abstract class Skill : MonoBehaviour
{
public abstract void UseSkill();
}
public abstract class PlayerSkill : Skill
{
public abstract bool CanCast(PlayerManager pm);
public abstract bool TryStartCast(PlayerManager pm);
public override abstract void UseSkill();
}
이 프로젝트에서는 모든 스킬이 동일한 실행 흐름을 따르도록 공통 스킬 추상 구조가 설계되어 있었다.
이 구조는 팀 내 다른 개발자가 설계한 공통 베이스 계층으로, 모든 플레이어 스킬이 ‘시전 가능 여부 검사 → 시전 시작 → 실제 효과 실행’ 이라는 동일한 단계를 거치도록 정의되어 있다.
4.2. Explosion 스킬의 시전 조건 및 잠금 처리
public class PlayerSkill_Explosion : PlayerSkill
{
PlayerManager playerManager;
PlayerSkillData skillData;
void Start()
{
playerManager = PlayerManager.instance;
skillData = playerManager.FindSkillData(
Resources.Load<PlayerSkillData>("GameData/Skill/Player/ExplosionData")
);
}
public override bool CanCast(PlayerManager _)
=> !skillData.IsCooldown && playerManager.CurrentMp >= skillData.MpConsumption;
public override bool TryStartCast(PlayerManager _)
{
if (!CanCast(playerManager))
return false;
// 즉시 잠금 (레이스 컨디션 방지)
skillData.IsCooldown = true;
playerManager.CurrentMp -= skillData.MpConsumption;
StartCoroutine(Co_Cooldown(skillData.CooldownTime));
return true;
}
IEnumerator Co_Cooldown(float cd)
{
float t = cd;
while (t > 0f)
{
t -= Time.deltaTime;
yield return null;
}
skillData.IsCooldown = false;
}
}
Explosion 스킬은 팀원이 설계한 PlayerSkill 추상 구조를 상속받아 구현한 플레이어 전용 스킬이다.
나는 이 구조를 그대로 활용하되, CanCast와 TryStartCast를 override하여
시전 가능 여부 판단과 실제 시전 시작을 명확히 분리하는 역할을 담당했다.
CanCast는 현재 쿨타임 상태와 MP만을 기준으로 판단하는 순수 검사 메서드다.
이 단계에서는 어떠한 상태 변경도 일어나지 않으며, 여러 번 호출되더라도 시스템 상태에 영향을 주지 않는다.
반면 TryStartCast는 시전이 시작되는 단 하나의 시점이다.
이 함수가 true를 반환하는 순간, 해당 스킬은 애니메이션과 무관하게 이미 사용 중 상태로 확정된다.
그래서 이 안에서 MP 차감과 쿨타임 플래그 설정을 즉시 처리하도록 설계했다.
이 방식은 입력 연타나 프레임 타이밍에 의한 중복 시전을 구조적으로 차단한다.
애니메이션이 아직 시작되지 않았더라도, 이 스킬은 이미 사용 중이라는 상태가 데이터 레벨에서 먼저 확정되기 때문이다.
쿨타임 해제는 코루틴으로 관리하며, 시간이 지나면 다시 IsCooldown을 false로 돌려 시전 가능 상태로 복귀시킨다.
이 구조에서 중요한 점은, 쿨타임과 MP 차감이 애니메이션 흐름과 완전히 독립되어 있다는 점이다.
애니메이션이 끊기거나 중단되더라도, 스킬의 자원 상태는 항상 일관되게 유지된다.
5. 개발 의도
이 게시글에서 보여주고자 한 핵심은 스킬의 실행 여부가 결정되는 단 하나의 시점에서 어떤 시스템 상태가 즉시 고정되어야 하는가였다.
스킬 시스템은 입력이나 애니메이션보다 먼저, 데이터의 일관성이 무너지지 않도록 설계되어야 한다.
그래서 시전 가능 여부 판단과 실제 상태 변경을 분리하고, 상태 변경은 반드시 하나의 함수에서 한 번만 일어나도록 구성했다.
