오픈월드 게임의 AI 활용 — 현실에서 진짜 가능한 수준은?

게시일: 2026년 1월 23일 · 16분 읽기

몇 달 전 한 게임 개발사의 마케팅 발표를 봤다. "AI로 100% 절차적으로 생성된 오픈월드"라고 했다. 무한한 도시, 무한한 퀘스트, 무한한 NPC. 마치 현실처럼 살아있는 세계. 흥미로웠다. 그래서 기술적 세부사항을 물어봤다. 그 답변은... 예상대로였다. 실제로는 절차적 생성이 맞지만, 제약이 크다. NPC의 행동은 상태 머신이다. 퀘스트는 템플릿 기반이다. 절차적으로 생성되지만, 매개변수를 조정하는 수준이다. 완전히 새로운 콘텐츠가 생성되는 게 아니다. 마케팅 표현과 기술 현실의 거리가 얼마나 큰지 보여준 사례였다.

절차적 생성의 실제 방식

오픈월드 게임에서 절차적 생성이 무엇인지 제대로 이해하려면, 실제로 어떻게 구현되는지 봐야 한다.

레벨 디자인의 절차적 생성

게임의 오픈월드 맵을 만든다고 치자. 손으로 일일이 그리는 건 너무 오래 걸린다. 그래서 절차적 생성을 쓴다. 하지만 "완전히 랜덤하게 생성"하는 게 아니다.

// 오픈월드 맵의 절차적 생성
class ProceduralMapGenerator {
  private PerlinNoise heightNoise;
  private PerlinNoise biomeNoise;
  private Random seededRandom;

  Map GenerateWorld(int seed) {
    seededRandom = new Random(seed);
    Map world = new Map();

    for(int x = 0; x < WORLD_WIDTH; x++) {
      for(int y = 0; y < WORLD_HEIGHT; y++) {
        // 1단계: 높이맵 생성 (지형 만들기)
        float height = heightNoise.GetValue(x, y);
        Terrain terrain = GetTerrainType(height);

        // 2단계: 바이옴 결정 (생태계 타입)
        float biomeValue = biomeNoise.GetValue(x, y);
        Biome biome = GetBiome(biomeValue);

        // 3단계: 자연 객체 배치
        if(ShouldSpawnTree(x, y, terrain)) {
          world.PlaceObject(x, y, new Tree(biome));
        }

        // 4단계: 광물 배치
        if(height > MOUNTAIN_THRESHOLD && seededRandom.Next(100) < ORE_SPAWN_RATE) {
          OreType oreType = GetOreTypeForBiome(biome);
          world.PlaceMineral(x, y, oreType);
        }

        world.SetTile(x, y, terrain, biome);
      }
    }

    // 5단계: 던전과 구조물 배치
    PlaceDungeons(world, seed);
    PlaceVillages(world, seed);
    PlacePointsOfInterest(world, seed);

    return world;
  }

  void PlaceDungeons(Map world, int seed) {
    // 마찬가지로 알고리즘으로 배치
    // 하지만 다음을 고려해야 함:
    // - 접근 가능해야 함 (길을 찾을 수 있어야 함)
    // - 난이도 분포가 균형잡혀야 함
    // - 플레이어가 막혀있지 않아야 함

    int dungeonCount = CalculateDungeonCountForWorld(world);
    for(int i = 0; i < dungeonCount; i++) {
      Vector2Int dungeonPos = FindValidDungeonLocation(world, seed + i);
      if(dungeonPos != Vector2Int.zero) {
        Dungeon dungeon = GenerateDungeon(dungeonPos, seed + i);
        ValidateDungeon(dungeon); // 검증!
        world.PlaceDungeon(dungeonPos, dungeon);
      }
    }
  }
}

핵심은 "검증"이다. 절차적으로 생성했지만, 그 결과가 게임으로서 플레이 가능한지 확인해야 한다. 이게 간단해 보이지만 매우 복잡하다.

절차적 생성의 주요 한계들

현재의 절차적 생성은 다음과 같은 한계를 가진다:

  1. 다양성의 한계: 같은 알고리즘으로 생성된 맵들은 결국 비슷해 보인다. 플레이어들은 패턴을 금방 알아챈다. "또 이 구조네"라고 생각한다.
  2. 퀄리티 불균일: 손으로 디자인한 레벨은 플레이어의 감정을 고려한다. 어디서 플레이어가 놀라게 할지, 어디서 쉬게 할지 계획한다. 절차적 생성은 이걸 못 한다. 모든 곳이 평등하게 기계적이다.
  3. 스토리 부재: 절차적으로 생성된 던전에는 이야기가 없다. 왜 이 던전이 여기 있는지, 누가 만들었는지 아무도 모른다. 그냥 "몬스터가 있는 곳"이다.
  4. 접근성 문제: 플레이어가 갇힐 수 있다. 생성된 맵의 일부가 고립되어 접근 불가능할 수 있다. 이를 100% 방지하는 알고리즘은 만들기 어렵다.

결과적으로, 현재의 대부분의 "절차적 오픈월드"는 핵심 구조는 손으로 만들고, 세부사항(풀의 위치, 작은 돌의 위치, 적의 정확한 개수 등)만 절차적으로 생성한다. 완전히 새로운 세계가 아니라, "변수를 바꾼 같은 세계"다.

AI NPC의 현실

오픈월드 게임의 생명력은 NPC에서 나온다. NPC가 자연스러워야 세계가 살아있는 것처럼 느껴진다.

마케팅 기대: "AI NPC는 정말로 생각한다"

요즘 게임사들의 마케팅을 보면, "우리 NPC는 AI가 제어한다"고 자랑한다. 마치 진짜 지능이 있는 것처럼. 하지만 실제로는?

현실: 복잡한 상태 머신

// 현실의 AI NPC (상태 머신 기반)
public enum NPCState {
  Idle,
  Patrol,
  Work,
  Sleep,
  Combat,
  Flee
}

class NPC {
  private NPCState currentState = NPCState.Idle;
  private float timeInState = 0;
  private Vector3 currentTarget;
  private AIMemory memory;

  void Update(float deltaTime) {
    timeInState += deltaTime;

    switch(currentState) {
      case NPCState.Idle:
        IdleUpdate(deltaTime);
        break;
      case NPCState.Patrol:
        PatrolUpdate(deltaTime);
        break;
      case NPCState.Work:
        WorkUpdate(deltaTime);
        break;
      case NPCState.Combat:
        CombatUpdate(deltaTime);
        break;
    }

    // 상태 전이 (상당히 많은 조건들)
    CheckStateTransitions();
  }

  void IdleUpdate(float deltaTime) {
    // 가만히 서있기
    PlayAnimation("Idle");

    // 일정 확률로 다른 상태로 전이
    if(timeInState > IDLE_DURATION) {
      if(seededRandom.Next(100) < WORK_CHANCE && CanWork()) {
        TransitionTo(NPCState.Work);
      } else if(seededRandom.Next(100) < PATROL_CHANCE) {
        TransitionTo(NPCState.Patrol);
        currentTarget = GeneratePatrolTarget();
      }
    }

    // 플레이어를 봤나?
    if(CanSeePlayer() && IsEnemy()) {
      TransitionTo(NPCState.Combat);
    }
  }

  void PatrolUpdate(float deltaTime) {
    // 목표 지점으로 이동
    Vector3 direction = (currentTarget - transform.position).normalized;
    transform.position += direction * moveSpeed * deltaTime;

    if(Vector3.Distance(transform.position, currentTarget) < ARRIVAL_THRESHOLD) {
      // 다음 순찰 지점 결정
      currentTarget = GeneratePatrolTarget();
    }
  }

  void CombatUpdate(float deltaTime) {
    // 전투 로직
    // 이것도 복잡한 상태 머신이다
    // Attack, Block, Dodge, UseSkill 등의 상태가 있다

    float distanceToPlayer = Vector3.Distance(transform.position, player.position);
    float myHealth = health / maxHealth; // 0~1

    // 여러 조건을 기반으로 행동 선택
    if(distanceToPlayer < MELEE_RANGE) {
      SelectMeleeAttack();
    } else if(distanceToPlayer < SPELL_RANGE && HasMana()) {
      SelectSpellAttack();
    } else if(myHealth < 0.3f) {
      // 도망치자
      TransitionTo(NPCState.Flee);
    }
  }

  void CheckStateTransitions() {
    // 여러 조건들...
    // 너무 많아서 다 나열하기 어렵다
    // 하지만 모두 "if-else" 기반의 결정이다

    if(PlayerIsNear()) {
      // ...
    }
    if(TimeOfDayIsSleepTime()) {
      TransitionTo(NPCState.Sleep);
    }
    // 수십 개의 조건들
  }
}

이 코드를 보면 뭐가 느껴지는가? 복잡하지만, "생각"을 하지 않는다. 모든 결정이 미리 정해진 규칙에 따른다. NPC가 "마치 생각하는 것처럼 보이도록" 설계된 것이다.

AI를 좀 더 쓴 경우

일부 최근 게임들은 작은 신경망이나 학습 모델을 NPC 행동에 사용한다. 하지만 이것도 제약이 있다.

// 약간 더 "지능적인" NPC (작은 신경망 사용)
class SmartNPC {
  private NeuralNetwork decisionNetwork;
  private float[] observationVector;

  void SelectAction() {
    // 현재 상황을 벡터로 변환
    observationVector = new float[] {
      Vector3.Distance(transform.position, player.position) / MAX_SIGHT_RANGE,
      health / maxHealth,
      mana / maxMana,
      timeOfDay / 24f,
      dayOfWeek / 7f,
      currentMoodValue,
      recentPlayerActions.Count / MAX_MEMORY,
      // 더 많은 상태들...
    };

    // 신경망으로 행동 결정
    float[] actionScores = decisionNetwork.Forward(observationVector);

    // 점수가 가장 높은 행동 선택
    int bestAction = FindMaxIndex(actionScores);
    ExecuteAction(bestAction);
  }

  void ExecuteAction(int action) {
    switch(action) {
      case 0: Attack(); break;
      case 1: Defend(); break;
      case 2: Flee(); break;
      case 3: UseItem(); break;
      case 4: CastSpell(); break;
      // 제한된 행동들만 가능
    }
  }

  // 문제들:
  // 1. 신경망도 결국 예측일 뿐, 창의성이 없다
  // 2. 신경망의 결정을 설명할 수 없다 ("왜 그렇게 행동했지?")
  // 3. 예상 밖의 행동을 할 수 있다 (버그처럼 보이는 이상한 행동)
  // 4. 게임 균형을 맞추기 어렵다
}

신경망을 쓰면 더 다양한 행동이 나온다. 하지만 여전히 제한적이다. 신경망도 학습 데이터에 있는 범위 내에서만 작동한다. 완전히 새로운 상황에서는 이상한 행동을 할 수 있다.

생성형 AI를 게임에 적용했을 때의 문제들

최근 일부 게임이 LLM 기반 NPC를 시도했다. 결과는 흥미롭지만 문제도 많다.

성공 사례: 스토리와 대사

LLM이 가장 잘하는 건 텍스트 생성이다. NPC와의 대사가 자연스러워진다. 같은 대사를 반복하지 않는다. 플레이어의 질문에 맥락 있게 응답한다.

// LLM 기반 NPC 대화 생성
class GenerativeMNPC {
  private LLMModel conversationModel;
  private string npcPersonality;
  private GameContext gameState;

  async Task RespondToPlayer(string playerText) {
    // NPC의 성격과 현재 상황 고려
    string prompt = $"""
      당신은 {npcPersonality} NPC입니다.
      현재 상황: {gameState.GetDescription()}
      플레이어가 이렇게 말했습니다: "{playerText}"

      1문장 또는 2문장으로 자연스럽게 응답하세요.
    """;

    string response = await conversationModel.Generate(prompt);
    return response;
  }
}

// 결과: 매우 자연스러운 대화가 가능하다
// 플레이어 입장에서는 "진짜 누군가와 대화하는 것 같다"

실패 사례: 행동과 행동 일관성

하지만 대사가 좋아도 행동이 맞지 않으면 몰입감이 깨진다. LLM이 생성한 대사는 훌륭할 수 있지만, NPC의 실제 행동은 여전히 상태 머신이다.

예를 들어 NPC가 "내 친구를 죽인 당신을 용서할 수 없다"고 분노하는 대사를 한다. 하지만 행동은? 그냥 서 있다. 공격하지 않는다. 도망치지도 않는다. 그냥 서서 같은 애니메이션만 반복한다. 플레이어는 "뭐 이 정도?" 하고 웃는다. 모든 몰입감이 깨진다.

LLM이 생성한 대사와 미리 정해진 행동의 불일치가 가장 큰 문제다. 대사를 생성할 때마다 NPC의 상태를 업데이트해야 하는데, 이건 복잡하다. NPC가 분노를 표현하는 대사를 했다면, 자동으로 "Combat" 상태로 전이되어야 한다. 하지만 이를 위해서는 LLM의 출력을 파싱해서 행동 코드로 변환해야 한다. 이건 비용이 크고 에러가 많이 난다.

경제성 문제

마지막으로 중요한 건 경제성이다. LLM을 게임에 쓰려면 API 비용이 든다. 매번 NPC 대사를 생성할 때마다 API 호출이 필요하다. 하루에 수천 명의 플레이어가 NPC와 대화하면, 비용이 어마어마하다. 게임사가 감수할 수 있는 규모가 아니다.

그래서 현실적인 타협은 이렇다. 자주 나오는 대사(상점 구매, 인사, 거절)는 미리 녹음한다. 특수한 상황의 대사만 LLM으로 생성한다. 이렇게 하면 비용을 줄일 수 있지만, 자연스러움도 줄어든다.

현실적인 AI 오픈월드의 모습

그렇다면 현재 기술로 만들 수 있는 "최고의 AI 오픈월드"는 뭐일까?

기술 스택

  1. 절차적 생성: 펄린 노이즈와 간단한 규칙 기반. 주요 구조는 손으로 만들고, 세부사항만 절차적.
  2. NPC 행동: 상태 머신. 복잡하지만 예측 가능. 플레이어가 게임을 깰 방법이 적다.
  3. NPC 대사: 미리 녹음된 대사. 주요 퀘스트는 전문 성우. 부수 대사는 자동 생성 AI.
  4. 동적 이벤트: AI가 게임 상태를 감시하다가 중요한 변화가 생기면 이벤트 발생. 예: 플레이어가 NPC를 죽이면 그의 친구들이 복수 추구.
  5. 난이도 조정: 플레이어의 행동을 분석해서 자동으로 난이도 조정.

이 모델의 장점

이 방식은 기술과 현실의 좋은 타협점이다.

플레이어는 게임이 "자신의 행동에 반응한다"고 느낀다. 절차적 생성이라는 걸 모르고, 게임이 동적으로 콘텐츠를 만든다고 생각한다. NPC가 인간처럼 보인다. 행동과 대사가 일치한다. 게임 균형이 유지된다.

개발사 입장에서도 좋다. 기술이 검증되었다. 위험이 낮다. 개발 과정을 예측할 수 있다. 버그도 적다. 비용도 관리 가능하다.

앞으로의 발전 방향

다음 5년을 예측해보면:

첫째, 절차적 생성이 더 정교해진다. AI가 게임 밸런스를 더 잘 이해하고, 생성된 콘텐츠의 품질이 높아진다. 하지만 여전히 "변형된 틀"일 것이다. 완전히 새로운 것은 아니다.

둘째, NPC의 행동이 더 복잡해진다. 신경망을 더 크게 쓰고, 학습 데이터를 더 많이 모은다. 하지만 여전히 제약이 있다. 완전한 자유도는 없을 것이다.

셋째, 음성 AI가 발전한다. 성우 없이 자연스러운 음성이 나온다. 이건 큰 변화일 것이다. NPC와의 상호작용이 훨씬 자연스러워진다.

넷째, 클라우드 기반 AI를 쓰는 게임이 늘어난다. 로컬에서 AI를 돌리지 않고, 서버에서 돌린다. 비용은 개선되겠지만, 인터넷 지연이 문제가 될 수 있다.

오픈월드 게임에서 AI의 미래는 "완벽한 자유도"가 아니라 "지능적인 제약"이다.

결론: 마케팅과 현실의 간극을 이해하기

게임사들의 "AI로 무한히 생성된 오픈월드" 마케팅은 과장이다. 하지만 완전한 거짓도 아니다. 기술은 실제로 그 방향으로 발전하고 있다. 단지 아직도 많은 제약이 있을 뿐이다.

개발자 입장에서 중요한 건 이 간극을 이해하고, 현실적인 기술로 최고의 게임을 만드는 것이다. 오래 게임 개발을 해오며 배운 게 있다면, 최신 기술이 항상 최고의 게임을 만드는 건 아니라는 것이다. 기술과 디자인의 조화, 무엇을 할 수 없는지를 아는 것도 중요하다.

AI는 도구다. 좋은 도구는 작업을 효율적으로 하고, 반복을 줄인다. 하지만 도구만으로는 좋은 게임이 만들어지지 않는다. 게임이 "살아있다"고 느껴지게 하는 건 AI가 아니라 그 AI를 어떻게 쓸지 결정하는 개발자의 창의성이다. 그게 변하지 않을 것 같다.

iL
ian.lab

실무 개발자입니다. 현장에서 겪은 문제와 해결 과정을 기록합니다. 오류 제보는 연락처로 보내주세요.