Стаття
Розробка ігор · Алгоритми · ⏱ ≈ 14 хв читання · Останнє оновлення: 23 червня 2026 р.

Колапс хвильової функції — процедурна генерація, керована обмеженнями

Колапс хвильової функції (WFC) Максима Гуміна (2016) генерує плиткові рівні, текстури та 3D-воксельні світи, що виглядають створеними вручну — формулюючи процедурну генерацію як задачу задоволення обмежень, запозичену з метафори квантової механіки. Алгоритм «спостерігає» клітинки по одній, колапсуючи їхню суперпозицію можливих плиток, а потім поширює отримані обмеження на сусідів через дугову узгодженість. Розуміння WFC відкриває сімейство інструментів генерації контенту під керуванням ШІ, які використовуються по всій сучасній розробці ігор.

1. Метафора суперпозиції

Уявіть сітку, де кожна клітинка може бути будь-яким із T типів плиток. Спочатку кожна клітинка має всі T плиток у своїй «суперпозиції» (множина ще можливих плиток). Мета — призначити рівно одну плитку кожній клітинці так, щоб усі обмеження суміжності задовольнялися.

Сітка: W × H клітинок, T типів плиток Стан: possibilities[y][x] ⊆ {0 … T−1} Спочатку: possibilities[y][x] = {0,1,2, … T−1} ∀ (x,y) Мета: |possibilities[y][x]| = 1 ∀ (x,y), і всі суміжні плитки задовольняють правила суміжності. Аналогія з КМ: незколапсована клітинка = частинка в суперпозиції «Спостерігати» = колапс до одного власного стану Поширення на сусідів = заплутаність / декогеренція

2. Спостереження, кероване ентропією

Яку клітинку колапсувати наступною? Завжди обирайте клітинку з найнижчою ентропією Шеннона (ще не сколапсовану). Низька ентропія означає, що в неї менше можливостей — обираючи її першою, ми мінімізуємо суперечності:

Ентропія Шеннона клітинки (x,y): H(x,y) = −Σₜ p(t) · log₂ p(t) де p(t) = weight[t] / Σ weight[t'], t ∈ possibilities[y][x] Якщо всі ваги рівні → H = log₂(|possibilities|) Сколапсована клітинка → H = 0 Крок алгоритму: 1. Знайти (x,y) = argmin H(x,y), де |possibilities[y][x]| > 1 2. Якщо не знайдено → ГОТОВО ✓ 3. Вибрати плитку t за вагами з possibilities[y][x] 4. Встановити possibilities[y][x] = {t} 5. Додати (x,y) до черги поширення

3. Поширення обмежень (AC-3)

Після колапсу клітинки її сусіди можуть більше не підтримувати певні плитки. Ми поширюємо, видаляючи з сусідів плитки, які не мають дійсної сусідньої плитки для парування — подібно до алгоритму дугової узгодженості AC-3 у розв’язанні CSP:

Для кожного напрямку d ∈ {N, E, S, W}: Для кожної плитки t ∈ possibilities[ny][nx] (сусідня клітинка): Якщо НЕ ∃ t' ∈ possibilities[cy][cx] : rules[d][t'][t] == true: Видалити t з possibilities[ny][nx] Якщо видалення відбулося → додати (nx,ny) до черги поширення Це триває, доки черга не спорожніє (нерухома точка). rules[d][t_source][t_target] = true означає: «плитка t_source у поточній клітинці сумісна з t_target у напрямку d» Суперечність: possibilities[y][x] = ∅ → відкат!

4. Відкат при суперечності

Коли поширення спорожнює можливості клітинки, поточне спостереження несумісне з обмеженнями. Класичний підхід WFC перезапускається з нуля; просунуті версії реалізують хронологічний відкат або відкат, керований залежностями:

Простий перезапуск (оригінал Гуміна): При суперечності → скопіювати початковий стан, перезапустити Хронологічний відкат: підтримувати стек (клітинка, обрана_плитка, знімок_стану) При суперечності → витягти, спробувати наступну плитку з possibilities Евристика мінімального конфлікту: при повторному спостереженні після відкату обрати плитку, що порушує найменше залишкових обмежень (підвищує успішність на складних наборах правил)

5. Перекривна модель проти плиткової

Плиткова модель

Явна множина з T різних плиток із створеними вручну або витягнутими попарними правилами суміжності. Швидко, повний творчий контроль. Використовується для більшості генераторів ігрових рівнів.

Перекривна модель

Вивчає візерунки N×N зі зразкового зображення. Кожне вікно N×N у виході має зустрічатися у вході. Дає текстури, що виглядають як приклад. Повільніше, але без жодного ручного створення правил.

3D-розширення

Сусіди за 6 напрямками (±X ±Y ±Z). Той самий алгоритм, більші таблиці суміжності. Використовується у воксельних світах (кімнати WFC у Caves of Qud, дослідження синтезу форм).

Wave Function Collapse Jr.

Спрощена версія, що використовує лише кількості плиток і частоти пар. Швидше, але дає менш складні структури. Достатньо для текстур рельєфу.

6. Витягання правил суміжності з прикладів

Маючи зразкове зображення W_s×H_s пікселів, розмір плитки N: Крок 1: витягти всі підзображення N×N (візерунки) → дедуплікувати (опційно дозволити повороти/відбиття) → підрахувати frequency(pattern) Крок 2: для кожної пари візерунків (A, B) та напрямку d: compatible[d][A][B] = true, якщо перекриття N×N між A, зміщеним на d, дорівнює краю B Для N=3, напрямок Схід: 2 праві стовпці A мають збігатися з 2 лівими стовпцями B (піксель у піксель) Weight[pattern] = frequency(pattern) / Σ frequencies → плитки, що зустрічаються частіше, ймовірніше будуть обрані

7. Реалізація на JavaScript

// Мінімальна плиткова модель WFC
class WFC {
  constructor(W, H, tiles, rules, weights) {
    // rules[dir][tileA][tileB] = bool; напрямки: 0=N 1=E 2=S 3=W
    this.W = W; this.H = H;
    this.T = tiles.length;
    this.rules = rules;
    this.weights = weights ?? new Array(this.T).fill(1);
    this._init();
  }

  _init() {
    // Кожна клітинка починається з усіма можливими плитками
    this.grid = Array.from({length: this.H}, () =>
      Array.from({length: this.W}, () =>
        new Set(Array.from({length: this.T}, (_,i) => i))
      )
    );
  }

  entropy(x, y) {
    const poss = this.grid[y][x];
    if (poss.size === 1) return 0;
    const total = [...poss].reduce((s,t) => s + this.weights[t], 0);
    return [...poss].reduce((s,t) => {
      const p = this.weights[t] / total;
      return s - p * Math.log2(p);
    }, 0);
  }

  observe() {
    // Знаходимо незколапсовану клітинку з мінімальною ентропією
    let minH = Infinity, cx = -1, cy = -1;
    for (let y = 0; y < this.H; y++) {
      for (let x = 0; x < this.W; x++) {
        const sz = this.grid[y][x].size;
        if (sz <= 1) continue;
        const h = this.entropy(x, y);
        if (h < minH) { minH = h; cx = x; cy = y; }
      }
    }
    if (cx === -1) return 'done';

    // Зважений випадковий вибір плитки
    const poss = [...this.grid[cy][cx]];
    const total = poss.reduce((s,t) => s + this.weights[t], 0);
    let r = Math.random() * total;
    const chosen = poss.find(t => (r -= this.weights[t]) <= 0) ?? poss[poss.length-1];
    this.grid[cy][cx] = new Set([chosen]);
    return this.propagate(cx, cy);
  }

  propagate(startX, startY) {
    const queue = [[startX, startY]];
    const DX = [0,1,0,-1], DY = [-1,0,1,0];
    const OPP = [2,3,0,1);  // індекс протилежного напрямку
    while (queue.length) {
      const [cx,cy] = queue.shift();
      for (let d = 0; d < 4; d++) {
        const nx = cx+DX[d], ny = cy+DY[d];
        if (nx<0||ny<0||nx>=this.W||ny>=this.H) continue;
        const nbPoss = this.grid[ny][nx];
        const before = nbPoss.size;
        for (const tNb of [...nbPoss]) {
          // Видаляємо tNb, якщо жодна плитка в поточній клітинці його не підтримує
          const ok = [...this.grid[cy][cx]].some(tC => this.rules[d][tC][tNb]);
          if (!ok) nbPoss.delete(tNb);
        }
        if (nbPoss.size === 0) return 'contradiction';
        if (nbPoss.size < before) queue.push([nx, ny]);
      }
    }
    return 'ok';
  }

  run(maxRestarts = 50) {
    for (let attempt = 0; attempt < maxRestarts; attempt++) {
      this._init();
      let status;
      do { status = this.observe(); } while (status === 'ok');
      if (status === 'done') return true;
    }
    return false; // невдача
  }

  result() {
    return this.grid.map(row => row.map(s => [...s][0]));
  }
}

8. Застосування та розширення

Генерація рівнів

Підземелля, печери, міські квартали з узгодженими стилями. Noita використовує процедурну систему укладання плиток, натхненну WFC, для свого піксельного світу. Підготуйте вручну малий зразок — генеруйте необмежені карти.

Синтез текстур

Перекривна модель на зразку текстури дає безшовні нескінченні текстури, що відповідають статистиці входу. Використовується для рельєфу, листя, цегляних візерунків без очевидного повторення.

Синтез 3D-форм

Академічна робота (Пол Меррелл, 2007, передує появі терміна WFC) генерує 3D-фасади будівель та міські плани, вивчаючи воксельну суміжність зі зразкових 3D-моделей.

Генерація музики

Застосовуйте WFC до послідовностей музичних нот: правила кодують гармонійну сумісність, ритмічні візерунки. Генерує музику, що слідує вивченим стилістичним обмеженням такт за тактом.

Нещодавні розширення включають WFC, кероване обмеженнями (користувач малює клітинки «має бути водою» / «має бути стіною» перед генерацією), ієрархічний WFC (спершу генерувати план кімнат, потім заповнювати кожну кімнату) та анімований WFC (генерувати плиткові карти, що також правильно анімуються, розширюючи правила на часовий вимір).

🌀 Відкрити генератор лабіринтів →