로그인게임하기
현장 강의록

Unity 벡터·내적·외적은 어디에 쓸까? 캐릭터 이동과 몬스터 시야 계산

2026.10.11

현장 강의록 · 애니메이션고 2022 · 9편

Unity에서 캐릭터를 목표 방향으로 움직이고 몬스터 앞쪽의 플레이어를 판별하려면 어떤 계산이 필요할까요? 방향 벡터의 정규화와 Time.deltaTime을 이용한 이동, 내적을 이용한 시야 판정, 외적을 이용한 좌우 방향 계산을 예제로 살펴봅니다. 행렬이 크기·회전·이동을 표현하는 방식까지 연결한 현장 강의록입니다.

수업 정보

2022년 1학기 한국애니메이션고등학교 2학년 「3D 게임 프로그래밍」 2강 「게임 개발에 필요한 기초 수학 지식」에서 가르친 내용입니다.

BASIS

점과 벡터

공간

2D · 3D 공간

게임의 사물은 2차원이나 3차원 공간에 놓이고, 위치와 움직임은 벡터와 행렬 계산으로 표현합니다.

위치

점 (Point)

좌표계 안의 위치입니다.

방향 + 크기

벡터 (Vector)

방향과 크기를 함께 가집니다. 게임 엔진은 점과 벡터를 같은 Vector 클래스로 다룹니다.

스칼라는 크기만 있는 값(속력 5)이고, 벡터는 방향까지 있는 값(오른쪽으로 5)입니다. 게임에서 "얼마나" 와 "어느 쪽으로" 를 함께 말해야 하는 곳에는 모두 벡터가 쓰입니다.

MOVE

두 점 사이의 방향과 거리

두 점 사이의 방향 벡터와 단위 벡터P1 (지금 위치)P2 (목표)DV = P2 − P1 (방향 + 거리)NV = DV / |DV| (크기 1)다음 위치 = P1 + NV × 속도 × 시간
빨간 화살표 DV 는 방향과 거리를, 파란 화살표 NV 는 크기가 1 인 방향을 나타냅니다.
구하는 것식Unity
방향과 거리를 함께DV = P2 − P1target - current
거리|DV| = √[(P2x − P1x)² + (P2y − P1y)² + (P2z − P1z)²]Vector3.Distance(P1, P2)
방향 (단위 벡터)NV = DV / |DV|(target - current).normalized
이동 (Translation)새 위치 = 지금 위치 + NV × 거리pos += dir * distance

정규화(Normalizing)는 방향은 그대로 두고 크기를 1 로 맞추는 계산입니다. 크기를 지우고 방향만 남기는 셈입니다. 방향만 남겨 두면 "이 방향으로 초당 3m" 처럼 속도를 따로 곱할 수 있습니다.

격자가 그려진 훈련장에서 에드윈의 발밑 점에서 슬라임의 점까지 빨간 화살표가 이어지고, 에드윈 옆에 짧은 파란 단위 화살표와 발자국이 찍힌 그림
에드윈은 매 프레임 파란 화살표 방향으로 조금씩 걸어 슬라임에 닿습니다.
SPEED

속도와 가속도

말식
거리거리 = 속도 × 시간
지금 속도지금 속도 = 처음 속도 + 가속도 × 시간
가속할 때의 거리거리 = (속도 + 가속도 × 시간) × 시간

게임은 프레임마다 움직이므로 시간은 Time.deltaTime(지난 프레임에서 흐른 시간)입니다. 속도에 deltaTime 을 곱해야 컴퓨터가 빠르든 느리든 1초에 같은 거리를 갑니다.

실습: 캐릭터 이동
  1. 목적지를 정합니다: targetPosition = new Vector3(Random.Range(-600, 600), Random.Range(-400, 400), 0);
  2. 출발할 때 목적지 방향을 저장합니다.
  3. 지금 위치와 목적지의 거리가 10 이하가 될 때까지 캐릭터를 움직입니다.
  4. myCharacter.localPosition = myCharacter.localPosition + (currentDir * Time.deltaTime * velocity);
Mover.cs설명용 예시 — 위 실습을 이어 붙인 답
Vector3 targetPosition;
Vector3 currentDir;
public float velocity = 300f;

void PickTarget()
{
    targetPosition = new Vector3(Random.Range(-600, 600), Random.Range(-400, 400), 0);
    currentDir = (targetPosition - myCharacter.localPosition).normalized;
}

void Update()
{
    if (Vector3.Distance(myCharacter.localPosition, targetPosition) <= 10f)
    {
        PickTarget();                       // 도착하면 다음 목적지
        return;
    }
    myCharacter.localPosition += currentDir * Time.deltaTime * velocity;
}
LIGHT VECTOR

빛을 위한 벡터의 결합

더하기

Half Vector

두 벡터를 더해 만듭니다(HV = V1 + V2). 반사광(스펙큘러) 계산에 쓰고, 방향만 남기려고 보통 정규화합니다.

반사

Reflection Vector

들어온 각도와 나가는 각도가 같은 벡터입니다. 부딪힌 면의 법선(Normal) 방향을 기준으로 계산합니다.

벡터는 더하고 빼는 것만으로도 많은 일을 합니다. 두 방향의 가운데가 필요하면 더하고, 한 점에서 다른 점으로 가는 길이 필요하면 뺍니다.

MATRIX

행렬로 크기, 회전, 이동

4×4 행렬과 위치 벡터를 곱하면 변환된 위치가 나옵니다. 행의 원소와 벡터의 원소를 차례로 곱해 더합니다.

벡터와 행렬의 곱2강 10쪽
│ 1, 2, 1, 5 │   │ 1 │   │ 14 │   1·1 + 2·3 + 1·2 + 5·1 = 14 (x)
│ 0, 3, 0, 4 │ × │ 3 │ = │ 13 │   0·1 + 3·3 + 0·2 + 4·1 = 13 (y)
│ 1, 2, 0, 0 │   │ 2 │   │  7 │   1·1 + 2·3 + 0·2 + 0·1 =  7 (z)
│ 0, 0, 0, 1 │   │ 1 │   │  1 │   0·1 + 0·3 + 0·2 + 1·1 =  1 (w)
세 받침대 위 파란 큐브가 각각 커지고, 45도 돌고, 위로 옆으로 옮겨진 모습과 흐린 원래 윤곽
크기(Scaling), 회전(Rotation), 이동(Translation)
변환행렬이 하는 일Unity
Scaling원점에서 각 점까지의 거리를 늘리거나 줄여 사물을 크거나 작게 보이게 합니다. 대각선에 Sx, Sy, Sz 를 둡니다transform.localScale *= 2;
Rotation원점을 중심으로 각 점을 돌립니다. Yaw · Pitch · Roll 행렬을 차례로 적용합니다Quaternion.Euler(0, 0, 45), Quaternion.LookRotation(dirToTarget, new Vector3(0, 0, 1))
Translation마지막 열의 값만큼 점을 옮깁니다. 그래서 위치 벡터의 네 번째 값 w 가 1 입니다transform.localPosition += new Vector3(0, 2, 3);

엔진의 transform 은 이 세 행렬을 대신 곱해 줍니다. 우리가 크기 · 회전 · 위치를 따로 적어도 엔진 안에서는 행렬 하나로 합쳐져 그려집니다.

실습: 물체의 크기, 회전, 이동
  1. 크기는 transform.localScale 을 바꿔 적용합니다.
  2. 이동은 transform.localPosition 을 바꿔 적용합니다.
  3. 회전은 Quaternion.Euler 로 회전값을 얻어 적용합니다.
DOT CROSS

내적과 외적

연산식Unity · HLSL
내적 (Dot)A · B = |A| |B| cos θVector3.Dot(a, b) · dot(a, b)
외적 (Cross)A × B = (aybz − azby, azbx − axbz, axby − aybx)Vector3.Cross(a, b) · cross(a, b)

내적은 숫자 하나를 돌려줍니다. 두 벡터가 모두 크기 1 이면 그 숫자가 곧 cos θ 라서, 두 방향이 얼마나 같은 쪽을 보는지를 알려 줍니다. 같은 쪽이면 1, 직각이면 0, 반대쪽이면 −1 입니다. 외적은 벡터를 돌려줍니다. 두 벡터에 모두 직각인 방향입니다.

SIGHT

게임에서: 몬스터의 시야와 옆걸음

내적으로 몬스터 시야를 판단하는 그림forward (바라보는 방향)플레이어 A: θ < 90°, 발견플레이어 B: θ > 90°, 못 봄θ몬스터cos θ = dot(forward, 플레이어 쪽 방향) · 두 벡터 모두 크기 1
몬스터가 보는 방향과 플레이어 쪽 방향의 내적으로 θ 를 구하고, 90° 보다 작으면 앞쪽에 있다고 판단합니다.

몬스터가 좌우 90° 안의 플레이어에게 반응한다고 해 봅시다. 몬스터가 보는 방향(forward)과 몬스터에서 플레이어로 가는 방향을 둘 다 정규화해 내적하면 cos θ 가 나옵니다. θ = acos(dot), 각도 = θ × (180 / π) 입니다. 각도가 90° 보다 작으면, 곧 내적이 0 보다 크면 앞쪽에 있는 것입니다.

슬라임 앞쪽으로 반원 모양 노란 시야가 펼쳐져 그 안의 로라는 들키고, 뒤쪽의 에드윈은 시야 밖에서 살금살금 지나가는 그림
로라는 시야 안이라 들키고, 에드윈은 뒤쪽이라 들키지 않습니다.
몬스터 시야설명용 예시 — 2강 18쪽 실습
Vector3 toPlayer = (player.position - transform.position).normalized;
float cos = Vector3.Dot(transform.forward, toPlayer);
float angle = Mathf.Acos(cos) * Mathf.Rad2Deg;

if (angle < 90f)
{
    Debug.Log("플레이어 발견");
    // 플레이어 쪽으로 이동
}
외적으로 좌우 방향을 구하는 그림forwardleft = up × forwardright = forward × upbackwardup (화면 밖 · z)
위쪽(up)이 화면 밖을 향할 때, 앞(forward)과 외적해 왼쪽과 오른쪽을 구합니다.

Unity 로 2D 처럼 만들 때는 위쪽(up)을 z 로 두는 경우가 많습니다. 그러면 앞쪽(forward)만 알아도 외적으로 좌우를 구해 옆걸음을 걸을 수 있습니다: left = up × forward, right = forward × up, backward = up × left. 외적은 곱하는 순서를 바꾸면 방향이 반대가 됩니다.

GRAPHICS

그래픽스에서: 조명

내적

Lambert Light

빛의 방향과 표면의 방향(법선)을 내적하면 cos θ 가 나옵니다. 1 에 가까울수록 밝게, 0 에 가까울수록 어둡게 칠하면 램버트 조명이 됩니다.

외적

Cross Light

카메라가 보는 방향을 forward, (0, 0, 1) 을 up 으로 두면 외적으로 left 와 right 를 구합니다. 네 방향으로 빛을 번지게 하면 카메라 방향에 따라 모양이 바뀌는 빛 효과가 됩니다.

몬스터의 시야와 표면의 밝기가 같은 식에서 나온다는 것이 이 수업의 마지막 메시지였습니다. 게임 수학은 장면이 달라도 같은 도구를 계속 다시 씁니다.

정리

  1. 방향은 빼고, 크기는 정규화로 지웁니다. 목표 − 현재 위치가 방향과 거리입니다.
  2. 크기 · 회전 · 이동은 행렬 곱입니다. 엔진의 transform 이 그 행렬을 대신 다룹니다.
  3. 내적은 얼마나 같은 쪽을 보는지, 외적은 두 방향에 직각인 방향. 시야 판단과 조명과 옆걸음이 같은 식에서 나옵니다.

현장 강의록은 수업 자료를 정리하는 대로 이어서 올립니다.

함께 읽으면 좋은 글

AI가 만든 Unity 코드를 직접 검증해 보고 싶다면

이 글에서 살펴본 구조를 바탕으로 AI에게 작업을 요청하고 결과를 읽는 연습을 이어가세요. 「AI 코드를 읽는 게임 개발자」 무료 세션 1에서 시작하거나, 전체 커리큘럼과 수강 안내를 확인할 수 있습니다.

← 개발 노트 목록