
AI×Unity로 2D 격투 게임을 만들 때 직면한 스프라이트 시트 문제와 해결책
요약
Claude Code와 Unity를 활용해 2D 격투 게임을 개발하며 겪은 AI 생성 스프라이트 시트의 배치 및 잘림 문제를 다룹니다. AI의 불규칙한 프레임 생성을 제어하기 위한 프롬프트 전략과 Unity 에디터 확장 툴을 통한 자동 중앙 배치 해결책을 제시합니다.
핵심 포인트
- 프롬프트에 프레임 구성을 명시하여 AI의 임의 포즈 생성을 방지
- 캐릭터가 그리드를 벗어나는 문제를 해결하기 위한 Unity 에디터 툴 개발
- GetContentBounds를 활용해 알파 값을 스캔하고 캐릭터를 중앙에 재배치
- AI 이미지 생성의 불확실성을 개발 도구로 보완하는 워크플로우 구축
서론
AI (Claude Code)를 사용하여 Unity로 2D 격투 게임을 개인 개발했습니다. "격투 게임은 프레임 단위의 제어가 필요해서 개인은 무리겠지"라고 생각했지만, 의외로 형태를 갖추게 되었습니다.
다만, 가장 고생했던 것은 코드가 아니라 스프라이트 시트 (Sprite Sheet)의 생성과 분할이었습니다.
본 기사에서는 AI 이미지 생성으로 스프라이트 시트를 만들 때 부딪혔던 문제와, 이를 해결하기 위해 만든 Unity 에디터 툴에 대해 쓰겠습니다.
환경
- Unity 6 (6000.3.x)
- 이미지 생성 AI (스프라이트 시트 생성용)
- Claude Code (코딩 지원)
문제 1: AI가 멋대로 센스를 발휘함
격투 게임의 스프라이트 시트는 Idle · Walk · Attack · Jump · Damage 등, 정해진 포즈를 정해진 순서대로 나열해야 합니다.
그런데 AI에게 "정면의 준비 자세 포즈를 그려줘"라고 지시해도, 요청하지 않은 멋진 각도의 돌려차기가 나오기도 합니다. AI는 "이쪽이 더 보기 좋겠지"라며 센스를 발휘하는 것이지만, 스프라이트 시트에는 정해진 포즈가 필요하기 때문에 이는 곤란합니다.
대처법
프롬프트 (Prompt)로 프레임의 배치를 엄격하게 지정했습니다. 최종적으로 안착한 구성은 6열×3행의 18프레임 구성입니다.
Row 0: Idle, Walk1, Walk2, Attack1, Attack2, Damage
Row 1: Jump, JumpAtk1, JumpAtk2, JumpAtk3, JumpAtk4, JumpAtk5
Row 2: Crouch, CrouchAtk, Victory, KO, Sweep, Guard
이를 프롬프트에 명시한 뒤, "이 외의 포즈는 불필요"라고 재차 강조함으로써, 안정적으로 의도한 대로의 시트를 얻을 수 있게 되었습니다.
문제 2: 잘림 문제
이것이 가장 까다로웠습니다.
AI는 스프라이트 시트 위에 캐릭터를 등간격으로 배치하지 않을 때가 있습니다. 캐릭터끼리 미묘하게 붙어서 배치되기 때문에:
- 머리카락이 옆 칸으로 삐져나감
- 발이 잘림
- 주먹이 다음 프레임으로 뚫고 나감
균등한 그리드 (Grid)로 잘라내면, 이러한 "삐져나옴"이 그대로 게임 화면에 반영되어 버립니다.
해결책: 스프라이트 시트 분할 에디터 툴을 만들었다
수동으로 자르는 위치를 조정하는 것이 현실적이었기에, Unity의 에디터 확장 (Editor Extension)으로서 "스프라이트 시트 분할 & 중앙 배치" 툴을 만들었습니다.
[MenuItem("Tools/스프라이트 시트 분할 & 중앙 배치")]
static void Open()
{
var w = GetWindow("시트 분할");
w.minSize = new Vector2(500, 450);
}
주요 기능:
- 프리뷰 상에서 분할선을 드래그 조작으로 조정 가능
- 균등 분할 버튼으로 2×1~8×4까지 한 번에 배치
- 각 칸의 불투명 영역을 자동 검출하여, 출력 이미지의 중앙에 재배치
- 우클릭으로 분할선을 개별 삭제
포인트는 GetContentBounds() 메서드입니다. 각 칸의 알파 값 (Alpha value)을 스캔하여, 실제로 픽셀이 존재하는 직사각형 영역을 검출합니다:
Rect GetContentBounds(Texture2D tex)
{
int w = tex.width, h = tex.height;
Color[] px = tex.GetPixels();
int minX = w, minY = h, maxX = 0, maxY = 0;
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
if (px[y * w + x].a > 0.01f)
...
}
검출한 영역을 지정된 크기 (512×512 등)의 캔버스 (Canvas)에 중앙 배치하여 출력함으로써, AI가 아무리 배치를 어긋나게 하더라도 통일된 프레임 이미지를 얻을 수 있습니다.
문제 3: 피벗 (Pivot) 위치의 어긋남
스프라이트 시트의 프레임을 잘라내더라도, 각 프레임의 캐릭터 발밑 위치가 제각각이면 애니메이션 재생 시 캐릭터가 상하로 흔들거립니다.
해결책: 알파 값 기반의 자동 피벗 검출
로드 시 Idle 프레임을 스캔하여, 최하단의 불투명 픽셀을 피벗 Y 좌표로 채택하고 있습니다:
// 아이들 프레임의 최하단 불투명 픽셀을 검출
for (int y = idleY; y < idleY + cellH; y++)
{
int solidCount = 0;
for (int x = 0; x < cellW; x++)
if (tex.GetPixel(x, y).a > 0.25f) solidCount++;
if (solidCount >= 3)
{
pivotY = (float)(y - idleY) / cellH;
break;
}
}
X 방향은 알파(Alpha) 값의 가중 평균으로 무게 중심을 구하여, 모든 프레임에 공통된 피벗(Pivot)으로 적용합니다. 이를 통해 발밑이 안정적인 애니메이션을 구현할 수 있었습니다.
프레임 관리: 상수로 정리하기
18개 프레임의 관리는 상수로 명확하게 매핑되어 있습니다:
public const int F_IDLE = 0;
public const int F_WALK1 = 1;
public const int F_WALK2 = 2;
public const int F_ATTACK1 = 3;
public const int F_ATTACK2 = 4;
public const int F_DAMAGE = 5;
public const int F_JUMP = 6;
// ... 이하 생략
public const int F_GUARD = 17;
18개 프레임은 격투 게임으로서는 최소한이지만, Idle(대기)·걷기 2프레임·공격 2단·점프 공격 5단·앉아 공격·가드·승리·KO까지 커버할 수 있습니다. AI에게 새로운 캐릭터를 추가해달라고 요청할 때도, "이 18프레임 구성으로"라고 지정하면 동일한 코드로 작동합니다.
벨트스크롤 액션으로의 응용
이 지식은 그대로 다른 게임(벨트스크롤 액션)에도 응용할 수 있었습니다. 그쪽에서는 동일한 SpriteSheetSplitter를 프로젝트에 복사하여, 콤보·점프 공격·잡기 던지기까지 구현했습니다. 한 번 메커니즘을 만들어 두면 캐릭터를 추가하는 비용이 대폭 낮아집니다.
요약
┌──────────────────┬──────────────────────────┬────────────────────────────────────────┐
│ 문제 │ 원인 │ 해결책 │
├──────────────────┼──────────────────────────┼────────────────────────────────────────┤
│ 의도하지 않은 포즈 │ AI의 "센스 발휘" │ 프레임 구성을 엄격하게 프롬프트로 지정 │
├──────────────────┼──────────────────────────┼────────────────────────────────────────┤
│ 프레임의 끊김 │ 불균등한 배치 │ 에디터 툴로 수동 분할 + 자동 중앙 배치 │
├──────────────────┼──────────────────────────┼────────────────────────────────────────┤
│ 피벗의 어긋남 │ 프레임별 위치 불일치 │ 알파 값 스캔으로 자동 피벗 검출 │
└──────────────────┴──────────────────────────┴────────────────────────────────────────┘
AI 이미지 생성 × Unity로 2D 액션 게임을 만드는 것 자체는 충분히 가능합니다. 다만, AI가 생성한 이미지를 그대로 사용할 수 있는 경우는 거의 없으며, 중간에 "정제하는 파이프라인 (Pipeline)"을 끼워 넣는 것이 현실적입니다.
개인적으로는, 이 정제 파이프라인을 한 번 만들어 두었더니 캐릭터를 추가할 때마다 매번 같은 고생을 하지 않아도 되게 된 것이 가장 큰 성과였습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기