zoukankan      html  css  js  c++  java
  • 游戏中的过程生成——元胞自动机 Celluar Automata 生成洞穴地形

    最近在学习过程生成技术,在这里写一些心得。

    对于元胞自动机,我们这里只讨论输入是一副二维bool数组的情况,即大多数游戏中的情况。

    一个元胞自动机,对于一个输入,给出一个同样格式的输出。输出中的每个点都是按照自动机中的规则从输入中演化而来的。大部分情况下,一个输出上的点,是根据输入中该点周围的点的状态来决定输出中的状态。

    我们输入一个二维bool数组,并且规定它的演化规则为,某个点周围的true较多,就演化为true,否则演化为false。这种规则下,我们输入一个随机生成的噪点图,经过一定次数的演化,就可以获得相当自然的“洞穴”地图。

    根据噪点图中噪点的数量,最终生成的洞穴被填充的面积也不同。

    unity官方给出了一个用元胞自动机随机生成洞穴地形的教程 https://unity3d.com/cn/learn/tutorials/projects/procedural-cave-generation-tutorial

    其中的元胞自动机生成的部分代码有一点错误,它并没有把输入的数组进行备份,直接对每个点进行遍历,因此每个点取到的之前一行的点都是新生成的点。

    不过负负得正的是因此生成了看起来更像洞穴的结果。事实上如果按照它的规则,写一个周围有4个true,则下一次变为true,否则变为false的自动机的话,最终的图像会出现非常明显的锯齿抖动。如下图。


    上图中的锯齿不管进行几次迭代都会一直存在

    我做出的修正是当周围的格子为true时刚好有4个时,则自身保持不变。最终获得了看起来像是洞穴的效果。

    类似这样的小调整可以做很多,比如边界上的点的处理等。通过不断调整可以获得各种不同效果。

    贴一下代码

    using UnityEngine;
    using System.Collections;
    namespace CS.MapGeneration {
        public class CelluarAutomata {
            private static int[,] offset = {
                { -1, -1 }, { -1, 0 }, { -1, 1 },
                {0,-1 },    {0,1 },
                {1,-1 }, {1,0 }, {1,1 }
            };
            private static int GetNeighbourCount(bool[,] map,int x,int y) {
                int res = 0;
                for (int i = 0; i < offset.GetLength(0); i++) {
                    int nx = x + offset[i, 0];
                    int ny = y + offset[i, 1];
                    if (nx<=0 || ny <=0 || nx>=map.GetLength(0) || ny >= map.GetLength(1) ||map[nx,ny])
                        res++;
                }
                return res;
            }
            
            public void Iterate(bool[,] map) {
                bool[,] copy = map.Clone() as bool[,];
                for(int i = 0; i < copy.GetLength(0); i++) {
                    for(int j = 0; j < copy.GetLength(1); j++) {
                        map[i, j] = Rule(copy, i, j);
                    }
                }
            }
    
            protected static bool Rule(bool[,] map, int x,int y) {
                if (!map[x, y] && GetNeighbourCount(map, x, y) > 4)
                    return true;
                else if (map[x, y] && GetNeighbourCount(map, x, y) < 4)
                    return false;
                return map[x, y];
            }
        }
    }
    
  • 相关阅读:
    「转」xtrabackup新版详细说明
    微博MySQL优化之路--dockone微信群分享
    分享的好处
    DBA的技能图谱
    高效运维--数据库坐而论道活动
    MySQL的诡异同步问题-重复执行一条relay-log
    把信送给加西亚读后感
    一次由于字符集问题引发的MySQL主从同步不一致问题追查
    nginx解决浏览器跨域问题
    kubernetes之pod调度
  • 原文地址:https://www.cnblogs.com/yangrouchuan/p/6392441.html
Copyright © 2011-2022 走看看