Game_Num_Basics_And_Calc

波函数坍缩 (WFC) 生成 (Wave Function Collapse)

[!NOTE] 核心思想: WFC 是一种基于约束 (Constraint) 的生成算法。它不是告诉计算机“怎么画”,而是告诉它“什么不能画”。

在 Roguelike 地牢生成中,WFC 能比传统的“房间+走廊”算法生成更自然、更有机的结构。


1. 核心概念 (Core Concepts)

1.1 叠加态 (Superposition)

在算法开始时,地图上的每一个格子都同时处于“所有可能状态”的叠加中。

1.2 熵 (Entropy)

熵是衡量不确定性的指标。

1.3 坍缩 (Collapse)

观测导致坍缩。我们人为地(或随机地)选择一个格子,将其状态固定下来。

1.4 约束传播 (Constraint Propagation)

一旦一个格子确定了(例如变成了“水”),它的邻居就不可能是“岩浆”(假设水火不容)。这种约束会像波纹一样向四周传播,减少邻居的熵。


2. 算法流程 (Algorithm Flow)

  1. 初始化: 将网格中所有单元格设为叠加态 (包含所有可能的 Tile)。
  2. 寻找最小熵: 找到当前网格中熵最小(可能性最少)但尚未坍缩的单元格。
    • 如果有多个最小熵,随机选一个。
  3. 观测/坍缩: 根据权重随机选择该单元格的一个状态,将其固定。
  4. 传播:
    • 更新该单元格的所有邻居。
    • 如果邻居的可能性减少了,继续更新邻居的邻居 (递归或堆栈)。
    • 如果在传播过程中某个单元格的可能性变为 0 (无解),则生成失败,需要回溯或重试。
  5. 循环: 重复步骤 2-4,直到所有单元格都坍缩完成。

3. 实现指南 (Implementation Guide)

3.1 定义 Tile 与 Socket (接口)

为了判断两个 Tile 是否能相邻,我们需要定义它们的边缘接口 (Socket)。

假设我们有 4 个方向:上、下、左、右。

规则: Tile A 的“右”接口必须与 Tile B 的“左”接口匹配 (可以是相同 ID,也可以是定义的对称 ID)。

3.2 旋转与镜像

为了节省美术资源,我们可以自动生成旋转变体。

3.3 回溯与重试 (Backtracking)

WFC 可能会遇到“死胡同” (Contradiction)。

3.4 性能优化


4. Unity 代码片段 (伪代码)

public class WFCGenerator : MonoBehaviour {
    struct Cell {
        public bool Collapsed;
        public List<Tile> PossibleTiles;
        public int Entropy => PossibleTiles.Count;
    }

    void RunWFC() {
        // 1. Init
        InitializeGrid();

        while (IsAnyCellUncollapsed()) {
            // 2. Find Min Entropy
            Vector2Int coords = GetMinEntropyCell();
            
            // 3. Collapse
            CollapseCell(coords);
            
            // 4. Propagate
            PropagateConstraints(coords);
        }
        
        DrawMap();
    }
    
    void PropagateConstraints(Vector2Int startNode) {
        Stack<Vector2Int> stack = new Stack<Vector2Int>();
        stack.Push(startNode);
        
        while (stack.Count > 0) {
            var current = stack.Pop();
            foreach (var neighbor in GetNeighbors(current)) {
                if (Constrain(current, neighbor)) {
                    stack.Push(neighbor); // 如果邻居被修改了,继续传播
                }
            }
        }
    }
}

5. 业界案例 (Industry Cases)

Townscaper

Bad North (北方绝境)

Caves of Qud


6. 扩展阅读