---
title: "벡터는 위치가 아니라 화살표다"
description: "Vector3 하나에 위치도 방향도 담기지만 둘은 다른 것입니다. 벡터는 시작점 없이 방향과 길이만 가진 화살표이고, 두 위치 사이의 방향은 도착 − 출발로 구합니다."
author: "유니얼"
pubDate: 2026-11-05
category: "game-dev/math"
tags: ["Unity", "기초"]
canonical: https://blog.unialgames.com/posts/math-vector/
---
적을 향해 총알을 쏘려고 총알 속도에 적의 위치를 그대로 넣으면, 총알이 엉뚱한 쪽으로 날아갑니다.
적이 왼쪽에 있는데 오른쪽 위로 날아가기도 합니다.
속도는 1초에 어느 쪽으로 얼마나 가는지라서 방향이 들어 있습니다. `enemy.position` 도 `Vector3` 이고 총알 속도도 `Vector3` 라서 컴파일은 아무 문제 없이 됩니다.

같은 `Vector3` 타입에 **위치**와 **방향**이라는 서로 다른 것이 담기기 때문입니다.
위치는 "어디에 있나" 이고, 방향은 "어디로 가나" 입니다.

> **벡터는 시작점 없이 방향과 길이만 가진 화살표입니다.
> 위치는 원점에서 그 자리까지 그린 화살표로 읽은 것이고,
> 나에서 적으로 가는 방향은 `적의 위치 − 나의 위치` 로 구합니다.**

## 자리는 숫자 두 개로 부른다

가로줄 하나와 세로줄 하나를 직각으로 그으면 자리를 숫자로 부를 수 있습니다.
가로줄을 **x 축**, 세로줄을 **y 축**, 둘이 만나는 기준 자리를 **원점**이라고 부르고 원점은 (0, 0) 으로 씁니다.
**좌표** (x, y) 는 원점에서 오른쪽으로 x, 위로 y 만큼 간 자리입니다. 음수면 왼쪽, 아래쪽입니다.

<x-vec>
<script type="application/json">
{
  "label": "점 (5, 1) 과 (−3, 4)",
  "view": [-4, -2, 7, 6],
  "steps": [
    {
      "caption": "가로줄이 x 축, 세로줄이 y 축입니다. 둘이 만나는 곳이 원점 (0, 0) 입니다.",
      "items": [
        { "id": "o", "type": "point", "at": [0, 0], "color": "text", "label": "원점 (0, 0)", "labelAt": [1.2, -0.6] }
      ]
    },
    {
      "caption": "(5, 1) 의 첫 숫자 5 는 원점에서 오른쪽으로 5 칸입니다.",
      "items": [
        { "id": "o", "type": "point", "at": [0, 0], "color": "text", "label": "원점 (0, 0)", "labelAt": [1.2, -0.6] },
        { "id": "h", "type": "line", "from": [0, 0], "to": [5, 0], "color": "accent2", "label": "x = 5", "labelAt": [3, -0.6] }
      ]
    },
    {
      "caption": "둘째 숫자 1 은 거기서 위로 1 칸입니다. 닿은 자리가 점 (5, 1) 입니다.",
      "items": [
        { "id": "o", "type": "point", "at": [0, 0], "color": "text", "label": "원점 (0, 0)", "labelAt": [1.2, -0.6] },
        { "id": "h", "type": "line", "from": [0, 0], "to": [5, 0], "color": "accent2", "label": "x = 5", "labelAt": [3, -0.6] },
        { "id": "u", "type": "line", "from": [5, 0], "to": [5, 1], "color": "warn", "label": "y = 1", "labelAt": [5.9, 0.5] },
        { "id": "p", "type": "point", "at": [5, 1], "color": "accent", "label": "(5, 1)", "labelAt": [5, 1.6] }
      ]
    },
    {
      "caption": "음수는 반대쪽입니다. (−3, 4) 는 왼쪽으로 3 칸, 위로 4 칸 간 자리입니다.",
      "items": [
        { "id": "o", "type": "point", "at": [0, 0], "color": "text", "label": "원점 (0, 0)", "labelAt": [1.2, -0.6] },
        { "id": "p", "type": "point", "at": [5, 1], "color": "accent", "label": "(5, 1)", "labelAt": [5, 1.6] },
        { "id": "h2", "type": "line", "from": [0, 0], "to": [-3, 0], "color": "accent2", "label": "x = −3", "labelAt": [-1.5, -0.6] },
        { "id": "u2", "type": "line", "from": [-3, 0], "to": [-3, 4], "color": "warn", "label": "y = 4", "labelAt": [-2.2, 2] },
        { "id": "q", "type": "point", "at": [-3, 4], "color": "accent", "label": "(−3, 4)", "labelAt": [-3, 4.6] }
      ]
    }
  ]
}
</script>
</x-vec>

## Vector3 는 숫자 세 개다

`Vector3` 를 열어 보면 `float` 세 개뿐입니다.

```csharp
public struct Vector3
{
    public float x;
    public float y;
    public float z;
}
```

숫자 세 개 자체에는 뜻이 없습니다. 이 셋을 **어떻게 읽느냐**에 따라 둘 중 하나가 됩니다.

| 읽는 법 | 뜻 | 유니티에서 |
| --- | --- | --- |
| 점 | 공간의 한 자리 | `transform.position` |
| 벡터 | 방향과 길이 | `transform.forward`(오브젝트의 앞쪽), `rb.linearVelocity`(Rigidbody 의 속도) |

이 글에서는 그림을 그리기 쉽게 z 를 빼고 `Vector2` 처럼 (x, y) 두 개로 봅니다. 셋이 되어도 계산은 똑같습니다.

## 벡터에는 시작점이 없다

벡터 (3, 4) 는 **"오른쪽으로 3, 위로 4"** 라는 뜻입니다. 어디서 출발하는지는 들어 있지 않습니다.
그래서 화살표를 어디에 그려도, 방향과 길이만 같으면 같은 벡터입니다.

<x-vec>
<script type="application/json">
{
  "label": "(3, 4) 를 여기저기 옮겨 그리기",
  "view": [-4, -4, 9, 7],
  "steps": [
    {
      "caption": "원점에서 오른쪽으로 3, 위로 4 를 그렸습니다. 이것이 벡터 (3, 4) 입니다.",
      "items": [
        { "id": "v", "from": [0, 0], "to": [3, 4], "label": "(3, 4)" },
        { "id": "h", "type": "line", "from": [0, 0], "to": [3, 0], "color": "muted", "label": "3", "labelAt": [1.5, -0.6] },
        { "id": "u", "type": "line", "from": [3, 0], "to": [3, 4], "color": "muted", "label": "4", "labelAt": [3.6, 2] }
      ]
    },
    {
      "caption": "같은 화살표를 오른쪽 아래로 옮겼습니다. 여전히 오른쪽으로 3, 위로 4 입니다. 같은 벡터입니다.",
      "items": [
        { "id": "v", "from": [4, -3], "to": [7, 1], "label": "(3, 4)" },
        { "id": "h", "type": "line", "from": [4, -3], "to": [7, -3], "color": "muted", "label": "3", "labelAt": [5.5, -3.6] },
        { "id": "u", "type": "line", "from": [7, -3], "to": [7, 1], "color": "muted", "label": "4", "labelAt": [7.6, -1] }
      ]
    },
    {
      "caption": "왼쪽 위로 옮겨도 마찬가지입니다. 벡터에 들어 있는 것은 방향과 길이뿐이라서, 시작점을 바꿔도 값은 그대로 (3, 4) 입니다.",
      "items": [
        { "id": "v", "from": [-3, 1], "to": [0, 5], "label": "(3, 4)" },
        { "id": "h", "type": "line", "from": [-3, 1], "to": [0, 1], "color": "muted", "label": "3", "labelAt": [-1.5, 0.4] },
        { "id": "u", "type": "line", "from": [0, 1], "to": [0, 5], "color": "muted", "label": "4", "labelAt": [0.6, 3] }
      ]
    }
  ],
  "note": "점선 두 개가 가로로 간 양과 세로로 간 양입니다. 화살표가 어디 있든 두 점선의 길이는 3 과 4 로 같습니다."
}
</script>
</x-vec>

화살표의 **길이**는 시작에서 끝까지 곧장 잰 거리입니다. 가로 3 과 세로 4 가 직각으로 만나니, 화살표는 **직각삼각형**(한 각이 90° 인 삼각형)의 비스듬한 변, **빗변**입니다.
빗변의 길이는 **피타고라스의 정리**로 구합니다. "빗변을 제곱한 값 = 가로를 제곱한 값 + 세로를 제곱한 값" 입니다.

- **제곱**은 같은 수를 두 번 곱하는 것입니다. 3² = 3 × 3 = 9, 4² = 4 × 4 = 16
- 그러면 빗변² = 9 + 16 = 25 입니다
- **제곱근(√, 루트)** 은 두 번 곱해서 그 수가 되는 수입니다. 5 × 5 = 25 라서 √25 = 5
- 그래서 (3, 4) 의 길이는 √(3² + 4²) = √25 = **5** 입니다

유니티에서는 `v.magnitude` 가 이 값을 돌려줍니다. 길이는 방향이 없는 숫자 하나입니다. 거리 5, 빠르기 10 처럼 방향 없이 크기만 있는 보통 숫자를 **스칼라**라고 부릅니다.

**그러면 위치는 무엇인가.** 위치 (5, 1) 은 "원점에서 오른쪽으로 5, 위로 1" 입니다.
원점이라는 시작점을 정해 놓고 벡터를 읽은 것이 위치입니다.
유니티의 `transform.position` 은 월드 원점 (0, 0, 0) 에서 그 오브젝트까지의 화살표입니다.

## 나에서 적으로 가는 방향은 뺄셈이다

나는 (5, 1) 에, 적은 (2, 5) 에 서 있습니다. 둘 다 원점에서 잰 위치입니다.
필요한 것은 **나에서 출발해 적에 닿는** 화살표입니다.

같은 자리끼리 빼면 됩니다. **도착점 − 출발점**입니다.

| | x | y |
| --- | --- | --- |
| 적 (도착) | 2 | 5 |
| 나 (출발) | 5 | 1 |
| 적 − 나 | 2 − 5 = **−3** | 5 − 1 = **4** |

(−3, 4) 는 "왼쪽으로 3, 위로 4" 입니다. 나에서 이만큼 가면 적에 닿습니다.

<x-vec>
<script type="application/json">
{
  "label": "두 위치 사이의 방향",
  "view": [-4, -4, 9, 7],
  "cases": [
    {
      "name": "적 − 나",
      "steps": [
        {
          "caption": "나는 (5, 1), 적은 (2, 5). 회색 화살표는 원점에서 각자의 자리까지입니다. 위치는 이렇게 원점에서 잰 벡터입니다.",
          "items": [
            { "id": "pm", "from": [0, 0], "to": [5, 1], "color": "muted" },
            { "id": "pe", "from": [0, 0], "to": [2, 5], "color": "muted" },
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] }
          ]
        },
        {
          "caption": "필요한 것은 나에서 출발해 적에 닿는 화살표입니다. 도착점에서 출발점을 뺍니다.",
          "items": [
            { "id": "pm", "from": [0, 0], "to": [5, 1], "color": "muted" },
            { "id": "pe", "from": [0, 0], "to": [2, 5], "color": "muted" },
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "d", "from": [5, 1], "to": [2, 5], "label": "적 − 나", "labelAt": [4.6, 3.6] }
          ]
        },
        {
          "caption": "가로로 2 − 5 = −3, 세로로 5 − 1 = 4. x 는 x 끼리, y 는 y 끼리 뺍니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "d", "from": [5, 1], "to": [2, 5], "label": "적 − 나", "labelAt": [4.6, 3.6] },
            { "id": "h", "type": "line", "from": [5, 1], "to": [2, 1], "color": "muted", "label": "2 − 5 = −3", "labelAt": [3.5, 0.4] },
            { "id": "u", "type": "line", "from": [2, 1], "to": [2, 5], "color": "muted", "label": "5 − 1 = 4", "labelAt": [0.6, 3] }
          ]
        },
        {
          "caption": "그 화살표를 원점으로 옮기면 (−3, 4) 입니다. 이 값을 나의 위치에 더하면 적의 위치가 나옵니다. (5, 1) + (−3, 4) = (2, 5).",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "d", "from": [0, 0], "to": [-3, 4], "label": "(−3, 4)", "labelAt": [-2.6, 4.6] },
            { "id": "h", "type": "line", "from": [0, 0], "to": [-3, 0], "color": "muted", "label": "−3", "labelAt": [-1.5, -0.6] },
            { "id": "u", "type": "line", "from": [-3, 0], "to": [-3, 4], "color": "muted", "label": "4", "labelAt": [-3.5, 2] }
          ]
        }
      ]
    },
    {
      "name": "나 − 적",
      "steps": [
        {
          "caption": "같은 두 위치에서 빼는 순서만 바꿉니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] }
          ]
        },
        {
          "caption": "나 − 적 = (5 − 2, 1 − 5) = (3, −4). 적에서 출발해 나에 닿는 화살표입니다. 방향이 정반대가 됐습니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "d", "from": [2, 5], "to": [5, 1], "color": "accent2", "label": "나 − 적", "labelAt": [4.6, 3.6] }
          ]
        },
        {
          "caption": "이 화살표를 나에게 붙이면 적에게서 멀어지는 방향입니다. 도망치는 적을 만들 때 이 순서로 뺍니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "d", "from": [5, 1], "to": [8, -3], "color": "accent2", "label": "(3, −4)", "labelAt": [7.4, -3.4] }
          ]
        }
      ]
    },
    {
      "name": "적의 위치를 그대로",
      "steps": [
        {
          "caption": "총알 속도에 적의 위치 (2, 5) 를 그대로 넣었다고 합시다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] }
          ]
        },
        {
          "caption": "총알은 나에서 출발해 오른쪽으로 2, 위로 5 만큼 갑니다. 적은 왼쪽 위에 있는데 오른쪽 위로 날아갑니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "b", "from": [5, 1], "to": [7, 6], "color": "warn", "label": "(2, 5)", "labelAt": [7.8, 6.2] }
          ]
        },
        {
          "caption": "(2, 5) 는 원점에서 적까지의 화살표입니다. 내가 원점에 서 있을 때만 맞는 방향입니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "b", "from": [5, 1], "to": [7, 6], "color": "warn", "label": "(2, 5)", "labelAt": [7.8, 6.2] },
            { "id": "o", "from": [0, 0], "to": [2, 5], "color": "warn", "dash": true, "label": "원점에서 적까지", "labelAt": [-1.6, 3] }
          ]
        },
        {
          "caption": "맞는 방향은 적 − 나 = (−3, 4) 입니다. 위치를 방향 자리에 넣으면 이렇게 원점 기준으로 틀어집니다.",
          "items": [
            { "id": "me", "type": "point", "at": [5, 1], "color": "accent2", "label": "나 (5, 1)", "labelAt": [6.4, 0.4] },
            { "id": "en", "type": "point", "at": [2, 5], "color": "warn", "label": "적 (2, 5)", "labelAt": [2, 5.6] },
            { "id": "b", "from": [5, 1], "to": [7, 6], "color": "warn", "label": "(2, 5)", "labelAt": [7.8, 6.2] },
            { "id": "d", "from": [5, 1], "to": [2, 5], "label": "적 − 나", "labelAt": [4.6, 3.6] }
          ]
        }
      ]
    }
  ]
}
</script>
</x-vec>

코드로 쓰면 이렇습니다.

```csharp
// 나에서 적으로 가는 화살표. 도착점 − 출발점
Vector3 toEnemy = enemy.position - transform.position;

// 적까지의 거리는 그 화살표의 길이
float distance = toEnemy.magnitude;
```

**빼는 순서가 곧 방향입니다.** 순서를 바꾸면 화살표가 정반대를 가리킵니다.

| 식 | 화살표 | 쓰는 곳 |
| --- | --- | --- |
| `target - me` | 나 → 목표 | 쫓아가기, 조준, 바라보기 |
| `me - target` | 목표 → 나 | 도망가기, 밀려나기(넉백) |

헷갈리면 **"도착 − 출발"** 만 기억하면 됩니다.
(−3, 4) 의 길이는 √(9 + 16) = 5 라서, 나와 적 사이의 거리도 5 입니다. `Vector3.Distance(a, b)` 가 바로 `(b - a).magnitude` 입니다.

## 점과 벡터로 할 수 있는 계산

같은 `Vector3` 라도 점과 벡터를 섞으면 **어떤 계산은 뜻이 있고 어떤 계산은 뜻이 없습니다.**

| 계산 | 결과 | 뜻 |
| --- | --- | --- |
| 점 − 점 | 벡터 | 한 자리에서 다른 자리로 가는 화살표 |
| 점 + 벡터 | 점 | 그 자리에서 화살표만큼 간 자리. 이동 |
| 벡터 + 벡터 | 벡터 | 두 화살표를 이어 붙인 것 |
| 점 + 점 | 뜻 없음 | (5, 1) + (2, 5) = (7, 6) 은 아무 자리도 아닙니다 |

`transform.position += velocity` 가 **점 + 벡터** 입니다. 그래서 결과가 다시 위치가 됩니다.
총알 속도에 적의 위치를 넣는 실수는 **점을 벡터 자리에 넣은** 것입니다. 타입이 같아서 컴파일러는 잡아 주지 못합니다.

**그런데 왜 유니티는 둘을 한 타입에 담았을까요.** 점도 벡터도 숫자 세 개이고, 더하기와 빼기를 하는 방법이 똑같기 때문입니다.
타입이 하나면 연산자와 함수를 한 벌만 두면 되고, 점 − 점 처럼 둘이 섞이는 계산도 형 변환 없이 바로 씁니다.
대신 치르는 값이 위의 실수입니다. 어느 쪽으로 읽을지는 타입이 아니라 **변수 이름과 쓰는 사람**이 기억해야 합니다.
그래서 `targetPos`, `moveDir` 처럼 이름에 위치인지 방향인지를 드러내 두는 편이 안전합니다.

## 정리

- `Vector3` 는 숫자 세 개입니다. 위치로 읽으면 점, 방향과 길이로 읽으면 벡터입니다
- 벡터는 시작점이 없는 화살표입니다. 어디에 그려도 방향과 길이가 같으면 같은 벡터입니다
- 위치는 원점에서 그 자리까지의 화살표입니다
- 두 위치 사이의 방향은 **도착 − 출발** 입니다. 순서를 바꾸면 반대 방향입니다
- 그 화살표의 길이가 두 위치 사이의 거리입니다
- 점 − 점 = 벡터, 점 + 벡터 = 점. 점 + 점은 뜻이 없습니다
- 위치를 방향 자리에 넣으면 원점 기준의 엉뚱한 방향이 됩니다. 타입이 같아서 컴파일러가 못 잡습니다
- 길이는 피타고라스로 √(x² + y²) 이고, `magnitude` 가 돌려줍니다