CellularAutomation(细胞自动机)

CellularAutomation(细胞自动机)本文探讨了细胞自动机的概念及其应用 通过详细解释生命游戏规则 展示如何利用细胞自动机生成复杂结构与地形

大家好,欢迎来到IT知识分享网。

CellularAutomation(细胞自动机)

生命游戏

有个可以直接玩这个游戏的链接 – Game of Life

下面用Unity自己写一下。

using UnityEngine; using System.Collections; public enum State{ Died, Living }; public class Cell { public State currentState; } public class Earth : MonoBehaviour { public int width; public int height; public string seed; public bool useRandomSeed; public float updateInterval = 1.0f; float refreshTime = -1f; [Range(0, 100)] public int randomFillPercent; Cell[,] map; Cell[,] mapTmp; // Use this for initialization void Start () { map = new Cell[width,height]; mapTmp = new Cell[width, height]; for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) { map[i,j] = new Cell(); map[i, j].currentState = State.Died; mapTmp[i, j] = new Cell(); mapTmp[i, j].currentState = State.Died; } initEarth(); } // Update is called once per frame void Update () { if(Time.time - refreshTime > updateInterval) { UpdateEarth(); refreshTime = Time.time; } } void UpdateEarth() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { mapTmp[x, y].currentState = map[x, y].currentState; int neighbourLiveCells = GetSurroundingLiveCells(x, y); if (map[x, y].currentState == State.Died && neighbourLiveCells == 3) { mapTmp[x, y].currentState = State.Living; } if (map[x, y].currentState == State.Living) { if(neighbourLiveCells < 2) { mapTmp[x, y].currentState = State.Died; }else if( neighbourLiveCells > 3) { mapTmp[x, y].currentState = State.Died; } else { mapTmp[x, y].currentState = State.Living; } } } } for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) { map[x, y].currentState = mapTmp[x, y].currentState; } } int GetSurroundingLiveCells(int gridX, int gridY) { int count = 0; for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX++) { for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY++) { if (neighbourX >= 0 && neighbourX < width && neighbourY >= 0 && neighbourY < height) { if (neighbourX != gridX || neighbourY != gridY) { count += map[neighbourX, neighbourY].currentState == State.Living? 1 : 0; } } } } return count; } void initEarth() { if (useRandomSeed) { seed = Time.time.ToString(); } System.Random pseudoRandom = new System.Random(seed.GetHashCode()); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (x == 0 || x == width - 1 || y == 0 || y == height - 1) { map[x, y].currentState = State.Living; } else { map[x, y].currentState = (pseudoRandom.Next(0, 100) < randomFillPercent) ? State.Living : State.Died; } } } } void OnDrawGizmos() { if (map != null) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (map[x, y] != null) { Gizmos.color = (map[x, y].currentState == State.Living) ? Color.black : Color.white; Vector3 pos = new Vector3(-width / 2 + x + .5f, 0, -height / 2 + y + .5f); Gizmos.DrawCube(pos, Vector3.one); } } } } } } 

代码其实就是按照前面算法的描述实现出来。

初始的细胞分布用了Unity自带的随机来生成,然后在OnDrawGizmos函数中绘制出来。运行起来是这样的:

CellularAutomation(细胞自动机)

可以将初始状态设置为经典的glider,修改 initEarth() 函数就可以了。

//Glider map[20, 20].currentState = State.Living; map[20, 21].currentState = State.Living; map[20, 22].currentState = State.Living; map[21, 22].currentState = State.Living; map[22, 21].currentState = State.Living;

CellularAutomation(细胞自动机)

程序生成地形

程序生成有很多中方法,利用细胞自动机主要用生成地牢等类似的地形,常用于Roguelike类的游戏。主要的算法就是还是利用细胞生存的规则,比如现在规定只要细胞周围有四个以上的细胞,该细胞就存活,否则死去。

for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int neighbourWallTiles = GetSurroundingWallCount(x, y); if (neighbourWallTiles > 4) map[x, y] = 1; else if (neighbourWallTiles < 4) map[x, y] = 0; } }

不断迭代,就可以得到一张地图。当然首先还是要在画布上随机分布一些细胞。迭代5次,最终生成地图如下

CellularAutomation(细胞自动机)    CellularAutomation(细胞自动机)

代码清单

using UnityEngine; using System.Collections; public class MapGenerator : MonoBehaviour { public int width; public int height; public string seed; public bool useRandomSeed; [Range(0, 100)] public int randomFillPercent; int[,] map; // Use this for initialization void Start () { GenerateMap(); } // Update is called once per frame void Update () { if (Input.GetMouseButtonDown(0)) { GenerateMap(); } } void GenerateMap() { map = new int[width, height]; RandomFillMap(); for (int i = 0; i < 5; i++) { SmoothMap(); } } void RandomFillMap() { if (useRandomSeed) { seed = Time.time.ToString(); } System.Random pseudoRandom = new System.Random(seed.GetHashCode()); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (x == 0 || x == width - 1 || y == 0 || y == height - 1) { map[x, y] = 1; } else { map[x, y] = (pseudoRandom.Next(0, 100) < randomFillPercent) ? 1 : 0; } } } } void SmoothMap() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int neighbourWallTiles = GetSurroundingWallCount(x, y); if (neighbourWallTiles > 4) map[x, y] = 1; else if (neighbourWallTiles < 4) map[x, y] = 0; } } } int GetSurroundingWallCount(int gridX, int gridY) { int wallCount = 0; for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX++) { for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY++) { if (neighbourX >= 0 && neighbourX < width && neighbourY >= 0 && neighbourY < height) { if (neighbourX != gridX || neighbourY != gridY) { wallCount += map[neighbourX, neighbourY]; } } else { wallCount++; } } } return wallCount; } void OnDrawGizmos() { if (map != null) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Gizmos.color = (map[x, y] == 1) ? Color.black : Color.white; Vector3 pos = new Vector3(-width / 2 + x + .5f, 0, -height / 2 + y + .5f); Gizmos.DrawCube(pos, Vector3.one); } } } } } 

参考

Game of Life – http://www.bitstorm.org/gameoflife/









免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/135954.html

(0)
上一篇 2025-06-30 21:33
下一篇 2025-06-30 21:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信