포스트

TIL 2026-04-16

TIL 2026-04-16

2026-04-16 벡터 연산과 게임 수학 기초

목차


y-up vs y-down 좌표계

좌표계란?

공간에서 위치를 숫자로 표현하는 기준 체계. 같은 좌표값이라도 좌표계에 따라 화면에서의 위치가 달라진다.

y-up 좌표계 (수학/게임 월드)

1
2
3
4
5
6
7
8
       y
       ↑
       |
       |   (3, 4) ← 오른쪽 위
       |
───────┼──────→ x
       |
       |   (3, -2) ← 오른쪽 아래
  • y값이 클수록 위 (수학 그래프와 동일)
  • 사용처: 언리얼 엔진 월드 좌표, Unity 월드 좌표, 물리 엔진, 수학

y-down 좌표계 (화면/스크린 좌표계)

1
2
3
4
5
6
7
───────┼──────→ x
       |
       |   (3, 2) ← 오른쪽 아래
       |
       |   (3, 6) ← 더 아래
       ↓
       y
  • y값이 클수록 아래 (모니터 스캔 방향과 동일)
  • 사용처: UI 좌표 (UMG, HTML Canvas), 텍스처 UV, DirectX 텍스처 좌표, 이미지 픽셀

같은 좌표, 다른 위치

좌표 (3, 4)y-upy-down
화면상 위치오른쪽 위오른쪽 아래
y값 증가 시위로 이동 ↑아래로 이동 ↓

언리얼 엔진에서의 좌표계

1
2
3
4
5
6
// 언리얼은 왼손 좌표계 (Left-Handed)
// X = 앞(Forward), Y = 오른쪽(Right), Z = 위(Up)
// → 월드 공간은 Z-up (y-up의 3D 버전)

// UI (UMG)는 화면 좌표계 사용
// → 왼쪽 상단이 (0, 0), 아래로 갈수록 y 증가 (y-down)

y-down → y-up 변환

1
2
3
4
5
6
// 화면 좌표를 월드 좌표로 변환할 때
// y_world = ScreenHeight - y_screen

// 예시: 화면 해상도 1080, 화면 좌표 (300, 200)
int ScreenY = 200;
int WorldY = 1080 - ScreenY;  // 880 (위쪽)

복기

  • y-up: y가 클수록 위 → 게임 월드, 물리, 수학
  • y-down: y가 클수록 아래 → 화면 UI, 텍스처, 이미지
  • 언리얼: 월드 = Z-up (y-up 계열), UI = y-down
  • 변환: y_world = ScreenHeight - y_screen

문제 1 — 좌표계와 벡터의 이해

조건: 2D 게임에서 캐릭터 A가 (1, 5)에, 적 B가 (4, 1)에 있다.

Q1. A에서 B를 향하는 벡터의 방향

1
2
3
// 방향 벡터 = B - A = (4-1, 1-5) = (3, -4)
// x가 양수(우), y가 음수(하)
// 답: 우하향

Q2. y-up 좌표계에서 B는 A보다 위? 아래?

1
2
3
4
// y-up 좌표계: y값이 클수록 위
// A의 y = 5, B의 y = 1
// B의 y < A의 y → B는 A보다 아래
// 답: 아래

Q3. y-down 좌표계(화면 좌표계)에서 B는 A보다 위? 아래?

1
2
3
4
// y-down 좌표계(화면 좌표계): y값이 클수록 아래
// A의 y = 5, B의 y = 1
// B의 y < A의 y → B는 A보다 위
// 답: 위
좌표계y값 증가 방향사용처
y-up (수학/게임 월드)위로 ↑언리얼, Unity 월드 좌표
y-down (화면 좌표계)아래로 ↓UI, 스크린 좌표, DirectX 텍스처

문제 2 — 벡터 연산과 정규화

조건: 플레이어 위치 P = (2, 3), 목표 위치 T = (6, 6)

Q1. P에서 T를 향하는 방향 벡터 d

1
2
3
4
// 방향 벡터 d = T - P = (6-2, 6-3) = (4, 3)
FVector2D P(2, 3);
FVector2D T(6, 6);
FVector2D d = T - P;  // (4, 3)

Q2. 방향 벡터 d의 크기(길이)

1
2
// |d| = √(x² + y²) = √(4² + 3²) = √(16 + 9) = √25 = 5
float Length = d.Size();  // 5.0

피타고라스 정리: 벡터의 크기 = √(x² + y²)

Q3. 정규화한 단위 벡터

1
2
3
// 단위 벡터 = d / |d| = (4/5, 3/5) = (0.8, 0.6)
// 단위 벡터의 크기는 항상 1
FVector2D UnitDir = d.GetSafeNormal();  // (0.8, 0.6)

정규화(Normalize): 방향은 유지하면서 크기를 1로 만드는 연산

왜 필요? → 방향과 속도를 분리하기 위해. 단위벡터 × 원하는 속도 = 이동량

Q4. 단위 벡터 방향으로 이동 후 새 위치

1
2
3
4
5
6
7
8
9
// 조건: 속도 10, 시간 간격 dt = 0.5
// 새 위치 = P + 단위벡터 × speed × dt
//         = (2, 3) + (0.8, 0.6) × 10 × 0.5
//         = (2, 3) + (4, 3)
//         = (6, 6)

float Speed = 10.0f;
float dt = 0.5f;
FVector2D NewPos = P + UnitDir * Speed * dt;  // (6, 6)

이동 공식: NewPosition = CurrentPosition + Direction × Speed × DeltaTime

이 공식이 게임 루프에서 매 프레임 캐릭터를 이동시키는 핵심 공식


문제 3 — 타워 디펜스 사거리 판정

조건: 타워 위치 (0, 0), 사거리 = 10 / 적 3마리: A(6, 8), B(3, 4), C(8, 7)

Q1. 사거리 안에 들어온 적 판별

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 각 적까지의 거리 = √(x² + y²)
// 적 A: √(6² + 8²) = √(36 + 64) = √100 = 10   → 사거리 이내 ✅
// 적 B: √(3² + 4²) = √(9 + 16)  = √25  = 5    → 사거리 이내 ✅
// 적 C: √(8² + 7²) = √(64 + 49) = √113 ≈ 10.63 → 사거리 밖 ❌

float Range = 10.0f;
for (auto& Enemy : Enemies)
{
    float Dist = FVector2D::Distance(TowerPos, Enemy.Pos);
    if (Dist <= Range)
    {
        // 공격 가능 대상
    }
}

거리 판정 최적화: 실무에서는 √ 연산 비용을 줄이기 위해 제곱 비교를 사용한다.

1
2
3
4
5
6
7
// 최적화된 사거리 판정 (√ 연산 생략)
float RangeSq = Range * Range;  // 100
// 적 A: 6² + 8² = 100 <= 100 ✅
// 적 B: 3² + 4² = 25  <= 100 ✅
// 적 C: 8² + 7² = 113 > 100  ❌

if (Enemy.Pos.SizeSquared() <= RangeSq) { ... }

Q2. 가장 가까운 적 → 공격 대상

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 사거리 안의 적: A(거리 10), B(거리 5)
// 가장 가까운 적: B (거리 5)

float MinDist = MAX_FLT;
AEnemy* Target = nullptr;
for (auto& Enemy : InRangeEnemies)
{
    float Dist = FVector2D::Distance(TowerPos, Enemy->Pos);
    if (Dist < MinDist)
    {
        MinDist = Dist;
        Target = Enemy;
    }
}

Q3. 타워에서 공격 대상까지의 정규화된 방향 벡터

1
2
3
4
5
6
7
// 타워(0,0) → B(3,4)
// 방향 벡터 = (3, 4)
// 크기 = √(9 + 16) = √25 = 5
// 단위 벡터 = (3/5, 4/5) = (0.6, 0.8)

FVector2D Dir = (Target->Pos - TowerPos).GetSafeNormal();  // (0.6, 0.8)
// 이 방향으로 투사체 발사!

핵심 공식 요약

연산공식게임 활용
방향 벡터d = 목표 - 현재적을 향한 방향, AI 추적
벡터 크기|d| = √(x² + y²)거리 계산, 사거리 판정
정규화û = d / |d|방향과 속도 분리
이동P’ = P + û × speed × dt매 프레임 캐릭터/투사체 이동
거리 판정 (최적화)x² + y² ≤ R²사거리/충돌 판정 (√ 생략)

ch3 팀프로젝트 — 04/16 회의 결과

게임 컨셉 확정

항목결정 사항
장르좀비 슈터 + 뱀파이어 서바이벌 융합
한 줄 설명Space Marine 2 느낌에 뱀서 장르를 섞은 TPS 생존 게임
핵심 메카닉근접+원거리 전투 / 웨이브 클리어 후 업그레이드 카드 선택
레퍼런스Space Marine 2, Vampire Survivors, Left 4 Dead 2
카메라 시점TPS (3인칭)

코어 루프

  • 순간 루프 (30초): 이동 + 근접/원거리로 좀비 처치 → 생존
  • 단기 루프 (5-15분): 웨이브 클리어 → 업그레이드 카드 선택 → 다음 웨이브
  • 장기 루프: 강해지는 빌드로 보스까지 클리어 / 다른 업그레이드 조합 시도

게임 필러

  1. 압도: 수백 마리 좀비 대군에 둘러싸이는 스케일감
  2. 성장: 웨이브마다 강해지는 업그레이드 빌딩의 재미
  3. 타격감: 근접+원거리 전투의 묵직한 피드백

MVP 범위

넣는 것 ✅

  • 플레이어 이동 + 원거리 사격 / 근접 전투 (기본 콤보 1~2개)
  • 좀비 웨이브 5라운드 / 좀비 타입 3종 (일반 / 돌진형 / 탱커형)
  • 웨이브 클리어 후 업그레이드 카드 선택 (3장 중 1개)
  • 보스 1마리 / 아레나 맵 1개 / 메인 메뉴 + 기본 HUD

절대 안 넣는 것 ❌

  • 멀티플레이 / 랜덤 맵 생성 / 스토리 컷씬 / 세이브 시스템
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.