
무기 궤적 및 트레일 연출과 프레임 기반 궤적 히트박스 연산
근접 공격의 시각적 궤적 연출 원리와 프레임 저하 환경에서도 정밀한 판정을 유지하는 궤적 히트박스 연산 기법을 다룹니다.
무기 궤적(Trail) 연출의 동작 원리
검기 및 무기 궤적 효과는 빠른 근접 공격 모션에서 시각적 타격감과 궤도를 명확하게 보여주는 핵심 연출 요소입니다. 단순히 고정된 마법 이펙트를 생성하는 방식과 달리 무기의 실제 움직임에 실시간으로 동기화되어 잔상을 남겨야 자연스럽습니다.
궤적 연출은 크게 파티클 리본(Ribbon Particle) 방식과 동적 메시 생성(Dynamic Mesh Generation) 방식으로 나뉩니다. 이 중 정밀한 조절이 가능한 동적 메시 방식은 무기 상단(Tip)과 하단(Base)에 위치 추적용 소켓(Socket)을 배치하고 매 프레임 해당 좌표를 기록하여 띠 형태의 트라이앵글 메시를 실시간 구축합니다.

UV 파닝과 셰이더를 통한 검기 표현
동적으로 생성된 메시에 텍스처를 씌울 때 핵심은 텍스처 좌표(UV) 배치입니다. 메시의 시작 지점을 0, 끝 지점을 1로 매핑한 후 셰이더에서 UV Panning 기법과 노이즈 텍스처를 조합하면 잔상이 흐르듯 빠져나가는 검기 효과를 얻을 수 있습니다.
시간 흐름에 맞춰 알파(Alpha) 값을 감소시키거나 발광(Emission) 강도를 낮추는 곡선(Curve)을 적용하면 검기가 공중에서 부드럽게 소멸하는 연출이 완성됩니다.
프레임 기반 궤적 히트박스(Hitbox) 연산
액션 게임에서 단순 콜라이더(Collider)나 단일 프레임 레이캐스트(Raycast)를 사용하면 고속 공격 시 뚫림 현상(Tunneling Problem)이 발생합니다. 프레임과 프레임 사이에 위치한 적을 무기가 지나쳐 버려 판정이 누락되는 것입니다.
이 문제를 해결하려면 이전 프레임의 무기 위치와 현재 프레임의 무기 위치가 이루는 궤적 면적(Swept Volume)을 히트박스로 계산해야 합니다.
궤적 면적 보간 수식
이전 프레임 의 무기 위치 와 현재 프레임 의 무기 위치 사이의 궤적 사각형 영역은 매개변수 를 이용해 다음과 같이 표현됩니다.
매 프레임 형성되는 이 사각형 영역을 2개의 삼각형으로 나누어 연속 레이캐스트(Multi-segment Raycast)나 OBB(Oriented Bounding Box) 충돌 검사를 수행하면 프레임 드랍 환경에서도 누락 없는 정밀한 피격 판정이 가능해집니다.
flowchart TD
A[공격 상태 시작] --> B[무기 Top/Bottom 소켓 위치 획득]
B --> C[이전 프레임 위치와 조합하여 Sweep 영역 생성]
C --> D[Swept Mesh / Multi-Raycast 충돌 검사]
D --> E{타격 대상 검출 여부}
E -- Yes --> F[Unique Hit-List 중복 검사 후 데미지 처리]
E -- No --> G[이전 프레임 위치 갱신]
F --> G
G --> H[공격 애니메이션 종료 시 데이터 초기화]
실무 구현 예제: C# 기반 궤적 충돌 검사
다음은 Unity 환경에서 무기 소켓 위치 변화를 추적하여 프레임 간 궤적 영역을 보간 검사하는 핵심 로직 구현입니다.
using System.Collections.Generic;
using UnityEngine;
public class WeaponTrailHitbox : MonoBehaviour
{
[SerializeField] private Transform tipSocket;
[SerializeField] private Transform baseSocket;
[SerializeField] private LayerMask targetLayer;
[SerializeField] private int raySubdivisions = 4;
private Vector3 _prevTipPos;
private Vector3 _prevBasePos;
private bool _isAttacking;
private readonly HashSet<Collider> _hitTargets = new HashSet<Collider>();
public void BeginAttack()
{ _isAttacking = true;
_hitTargets.Clear();
_prevTipPos = tipSocket.position;
_prevBasePos = baseSocket.position;
}
public void EndAttack()
{
_isAttacking = false;
}
private void Update()
{
if (!_isAttacking) return;
Vector3 currTipPos = tipSocket.position;
Vector3 currBasePos = baseSocket.position;
// 이전 프레임과 현재 프레임 사이 궤적 면적을 분할 레이캐스트로 검사
for (int i = 0; i <= raySubdivisions; i++)
{
float t = (float)i / raySubdivisions;
Vector3 startPoint = Vector3.Lerp(_prevBasePos, _prevTipPos, t);
Vector3 endPoint = Vector3.Lerp(currBasePos, currTipPos, t);
Vector3 direction = endPoint - startPoint;
float distance = direction.magnitude;
if (distance > 0.001f && Physics.Raycast(startPoint, direction.normalized, out RaycastHit hit, distance, targetLayer))
{
if (_hitTargets.Add(hit.collider))
{
OnHitTarget(hit);
}
}
}
_prevTipPos = currTipPos;
_prevBasePos = currBasePos;
}
private void OnHitTarget(RaycastHit hit)
{
Debug.Log($"Target Hit: {hit.collider.name}");
}
}

궤적 연산 성능 최적화 및 예외 처리
- 서브스텝(Sub-stepping) 보간: 모바일 기기 등에서 프레임 레이트가 순간적으로 떨어지면 궤적이 꺾여 보일 수 있습니다. Catmull-Rom Spline 보간을 도입해 정점을 보완하면 궤적의 곡선미와 충돌 판정 정밀도를 모두 유지할 수 있습니다.
- 중복 타격 방지(Hit De-duplication): 하나의 공격 모션 동안 동일한 타겟이 매 프레임 연속으로 피격되는 판정 오류를 막아야 합니다. 공격 판정이 켜져 있는 동안
HashSet이나 고유 ID 기반으로 이미 타격한 대상 목록을 관리하여 1회만 데미지가 적용되도록 제어합니다. - 메모리 할당 최적화: 궤적 메시 정점 데이터를 매 프레임 새로 할당하면 가비지 컬렉터(GC) 부하가 커집니다. 정점 배열 버퍼를 미리 확보하고 재사용하는 오브젝트 풀링 방식을 적용해야 쾌적한 프레임을 유지할 수 있습니다.


