🧠 오늘의 핵심 정리
- 피격 이펙트 대체 : 3D VFX 대신 2D 스프라이트를 Player 자식으로 붙여 재생
- 죽음 애니메이션 멈춤 해결 : 바로
enabled=false하지 않고 코루틴으로 지연 처리 - 거대 로봇(추격자) 연출 : 피격 시 서서히 다가오고, 사망 시 스매시 애니메이션
- 재피격 버그 방지 :
health <= 0이면 즉시 return
🎯 본캠프 36일차 : 피격 연출 + 거대 로봇(추격자) 붙이기
오늘은 “피격 연출”을 제대로 붙이는 날이었습니다. 근데… 무료 + 저작권 괜찮은 3D 피격 VFX 찾기가 생각보다 너무 빡세더라고요. 그래서 그냥 깔끔하게 방향을 바꿔서 2D 스프라이트 이펙트를 Player 자식으로 넣고, Damaged() 실행될 때마다 켜졌다 꺼지게 구현했습니다.
💥 피격 이펙트 : 2D 스프라이트를 코루틴으로 잠깐만 출력
3D 이펙트 대신 2D 스프라이트를 최대한 자연스럽게 보이게 Player 자식으로 배치하고, 애니메이션 트리거가 실행될 때 이펙트 오브젝트를 잠깐 켰다가 꺼주는 방식으로 처리했습니다.
AnimationHandler : 피격/사망 시 이펙트 출력
// AnimationHandler.cs
public GameObject _gameObject;
void Start()
{
// ...
_gameObject.SetActive(false);
}
public void DamagedAnimation()
{
anim.SetTrigger("Damaged");
ShowEffect();
}
public void DieAnimation()
{
_gameObject.SetActive(false);
ShowEffect();
anim.SetTrigger("IsDie");
}
private IEnumerator EffectdCoroutine()
{
_gameObject.SetActive(true);
yield return new WaitForSeconds(2);
_gameObject.SetActive(false);
}
그리고 점프 착지 애니메이션도 “트리거” 대신 bool로 쓰다 보니, 점프 시점에 Landed를 false로 만들고 일정 시간 뒤 true로 복구하는 코루틴을 추가했습니다. (점프가 붕 뜨는 느낌 보완하면서 같이 손 본 느낌)
점프 시 Landed false → 일정 시간 후 true
// AnimationHandler.cs
public void LandedFalseToTrue() { StartCoroutine(LandedCoroutine()); }
private IEnumerator LandedCoroutine() {
anim.SetBool("Landed", false);
yield return new WaitForSeconds(0.9f);
anim.SetBool("Landed", true); }
☠️ Die Animation 멈춤 해결 : enabled 비활성화를 “지연”
처음에는 죽었을 때 바로 PlayerController.enabled = false;를 해버렸는데, 그러니까 죽는 애니메이션이 나오다가 중간에 멈추더라고요. (아마 Update/이동/상태 변화가 끊기면서 애니메이션 연출 타이밍이 깨진 느낌…)
그래서 애니메이션이 재생될 시간을 확보하기 위해 코루틴으로 일정 시간 기다렸다가 enabled를 꺼주도록 수정했습니다.
PlayerCondition : 죽음 처리 코루틴
// PlayerCondition.cs
public void Die() { StartCoroutine(DieCoroutine()); }
private IEnumerator DieCoroutine()
{
animationHandler.DieAnimation();
yield return new WaitForSeconds(1f);
playerController.enabled = false;
}
이렇게 바꾸니까 “죽는 모션 → 조작 불가” 흐름이 자연스럽게 이어져서 결과적으로 훨씬 보기 좋아졌습니다.
🤖 뒤에서 쫓아오는 거대 로봇 연출
우리 게임 스토리가 “공장에서 탈출하는 로봇이 거대 로봇에게 쫓기는 이야기”라서, 플레이어 뒤에 계속 달려오는 거대 로봇(추격자)을 구현해야 했습니다.
방식은 단순하게 잡았습니다. 거대 로봇을 플레이어 자식으로 두고 기본적으로는 뒤에서 달리는 애니메이션만 계속 켜두고, 피격 시에는 로컬 포지션을 조금씩 앞으로 당겨서 “서서히 다가오는” 느낌을 만들었습니다.
피격 시 : 거대 로봇이 서서히 앞으로 이동
// PlayerCondition.cs
public GameObject monster;
public void Damaged()
{
health -= 1;
if (health <= 0)
{
Die();
return;
}
animationHandler.DamagedAnimation();
StartCoroutine(MoveMonsterForward(new Vector3(0, 0, -5.5f), 1.5f));
}
private IEnumerator MoveMonsterForward(Vector3 targetLocalPos, float duration)
{
Vector3 startPos = monster.transform.localPosition;
float _elapsed = 0f;
while (_elapsed < duration)
{
_elapsed += Time.deltaTime;
float t = _elapsed / duration;
monster.transform.localPosition = Vector3.Lerp(startPos, targetLocalPos, t);
yield return null;
}
}
그리고 사망(health=0)일 때는 거대 로봇이 더 가까이 와서 방향까지 틀고, 마지막에 공격 애니메이션(Smash)을 트리거로 실행하도록 만들었습니다.
사망 시 : 거대 로봇 접근 + 스매시 + 게임오버
// PlayerCondition.cs
public Animator monsterAnimator;
void Start()
{
monsterAnimator = monster.GetComponent();
}
public void Die()
{
StartCoroutine(DieCoroutine(new Vector3(1.46f, 0, -2.32f), 1.5f));
}
private IEnumerator DieCoroutine(Vector3 targetLocalPos, float duration)
{
animationHandler.DieAnimation();
Vector3 startPos = monster.transform.localPosition;
Quaternion startRot = monster.transform.localRotation;
Quaternion targetRot = Quaternion.Euler(0f, -28f, 0f);
float _elapsed = 0f;
while (_elapsed < duration)
{
_elapsed += Time.deltaTime;
float t = _elapsed / duration;
monster.transform.localPosition = Vector3.Lerp(startPos, targetLocalPos, t);
monster.transform.localRotation = Quaternion.Lerp(startRot, targetRot, t);
yield return null;
}
monsterAnimator.SetTrigger("Smash");
yield return new WaitForSeconds(0.4f);
playerController.enabled = false;
yield return new WaitForSeconds(3f);
GameManager.Instance.GameOver();
}
🧨 문제점 : 죽고 쓰러지면서 장애물에 닿으면 “또” 죽는 문제
오늘 제일 거슬렸던 버그는 이거였습니다. 플레이어가 죽어서 쓰러지는 도중에 장애물과 닿으면 Damaged()가 다시 불려서 죽는 애니메이션이 또 실행되는 문제가 있었어요.
해결은 간단하게 체력이 0 이하이면 바로 return 하도록 가드를 추가했습니다. (이거 하나만 넣어도 재피격이 싹 정리됨)
재피격 방지 가드
// PlayerCondition.cs
public void InstantDeath() { if (health <= 0) return; health = 0; Die(); }
public void Damaged()
{
if (health <= 0) return;
health -= 1;
if (health <= 0)
{
Die();
return;
}
// ...
}
📌 오늘의 회고
오늘은 “연출이 게임을 살린다”를 제대로 느꼈습니다. 3D 피격 이펙트를 못 구해서 잠깐 멘붕했는데, 2D 스프라이트를 붙이는 방식으로도 충분히 자연스럽게 만들 수 있었고, 오히려 구현은 더 단순해져서 좋았습니다.
그리고 거대 로봇 연출은… 진짜 기대 이상으로 재미있었어요. 단순히 뒤에서 달리는 NPC가 아니라, 피격할수록 가까워지는 압박감이 생기니까 러너 게임 느낌이 확 살아나더라고요.
🔜 내일 할 일
- 피격 이펙트가 2초 고정인데 상황별로 더 자연스럽게 튜닝 (짧게/강하게)
- 거대 로봇 접근 연출(피격 1회/2회/사망) 단계별로 더 드라마틱하게 조정
- 죽음 이후 입력/충돌 처리 완전 차단(콜라이더/트리거 이벤트 정리)
'내일배움캠프 본캠프' 카테고리의 다른 글
| [내일배움캠프 38일차 TIL] 펫 시스템 (0) | 2025.11.20 |
|---|---|
| [내일배움캠프 37일차 TIL] 애니메이션 문제 (0) | 2025.11.19 |
| [내일배움캠프 35일차 TIL] 플레이어 움직임 (0) | 2025.11.17 |
| [내일배움캠프 34일차 TIL] 3D팀 프로젝트 (0) | 2025.11.14 |
| [내일배움캠프 33일차 TIL] 개인 프로젝트 제출날 (0) | 2025.11.13 |