效果图:
高斯帕滑翔机枪:
通过基础规则 + 初始状态能产生很多令人惊讶的表现
基础规则:
(1)当前细胞为死亡状态时,当周围有3个存活细胞时,则迭代后该细胞变成存活状态(模拟繁殖);若原先为生,则保持不变。
(2)当前细胞为存活状态时,当周围的邻居细胞低于两个(不包含两个)存活时,该细胞变成死亡状态(模拟生命数量稀少)。
(3)当前细胞为存活状态时,当周围有两个或3个存活细胞时,该细胞保持原样。
(4)当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态(模拟生命数量过多)。
有个B站视频,介绍了很多不同变化的结构:【生命游戏|第一集】 几个方格演变出一个世界_哔哩哔哩_bilibili
项目包:unity 生命游戏
代码很简单:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LifeGame : MonoBehaviour
{
public class CellInfo
{
public CellInfo(Image imgParam)
{
img = imgParam;
SetState(false);
}
public Image img;
public bool state;
public void SetState(bool live)
{
state = live;
img.color = live ? Color.white : Color.black;
}
public bool IsDead()
{
return state == false;
}
public void SetTmpState(bool bState)
{
tmpState = bState;
}
public bool tmpState;
}
public int CellLength = 100;
public Image ImagePrefab;
public Transform CellsParent;
public float speed = 1;
List<List<CellInfo>> Cells = new List<List<CellInfo>>();
int width;
int height;
int round = 0;
// Start is called before the first frame update
void Start()
{
width = Screen.width / CellLength;
height = Screen.height / CellLength;
var size = new Vector2(CellLength-1, CellLength-1);
for(int i=0;i<height;++i)
{
List<CellInfo> curCells = new List<CellInfo>();
Cells.Add(curCells);
for (int j=0;j< width; ++j)
{
var img = Instantiate(ImagePrefab, CellsParent);
var rectTrans = (img.transform as RectTransform);
rectTrans.sizeDelta = size;
rectTrans.anchoredPosition = new Vector2(j * CellLength, i * CellLength);
curCells.Add(new CellInfo(img));
}
}
}
public void ClearState()
{
for (int i = 0; i < height; ++i)
{
for (int j = 0; j < width; ++j)
{
Cells[i][j].SetState(false);
}
}
round = 0;
}
public void NextRound()
{
++round;
for (int i = 0; i < height; ++i)
{
for (int j = 0; j < width; ++j)
{
UpdateState(i, j);
}
}
ChangeTmpState();
}
List<Vector2> roundMap = new List<Vector2>
{
new Vector2(-1,-1),
new Vector2(0,-1),
new Vector2(1,-1),
new Vector2(-1,0),
new Vector2(1,0),
new Vector2(-1,1),
new Vector2(0,1),
new Vector2(1,1)
};
void UpdateState(int y,int x)
{
// 周围存活细胞个数
int count = 0;
foreach(var map in roundMap)
{
int mx = x + ((int)map.x);
int my = y + ((int)map.y);
if(mx >= 0 && mx < width && my >=0 && my < height)
{
count += Cells[my][mx].state ? 1 : 0;
}
}
var cell = Cells[y][x];
var newState = cell.state;
//当前细胞为死亡状态时,当周围有3个存活细胞时,则迭代后该细胞变成存活状态(模拟繁殖);若原先为生,则保持不变。
if (cell.IsDead() && count == 3) newState = true;
else if(!cell.IsDead())
{
//当前细胞为存活状态时,当周围的邻居细胞低于两个(不包含两个)存活时,该细胞变成死亡状态(模拟生命数量稀少)。
if (count < 2) newState = false;
//当前细胞为存活状态时,当周围有两个或3个存活细胞时,该细胞保持原样。
if (count == 2 || count == 3) newState = cell.state;
//当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态(模拟生命数量过多)。
if (count > 3) newState = false;
}
cell.SetTmpState(newState);
}
void ChangeTmpState()
{
for (int i = 0; i < height; ++i)
{
for (int j = 0; j < width; ++j)
{
var cell = Cells[i][j];
cell.SetState(cell.tmpState);
}
}
}
// Update is called once per frame
void Update()
{
if(Input.GetMouseButtonDown(0))
{
var mousePos = Input.mousePosition;
int x = Mathf.FloorToInt(mousePos.x / CellLength);
int y = Mathf.FloorToInt(mousePos.y / CellLength);
if (x >= 0 && x < width && y >= 0 && y < height)
Cells[y][x].SetState(!Cells[y][x].state);
}
AutoUpdate();
}
float lastTime;
bool isAuto = false;
void AutoUpdate()
{
if(isAuto)
{
if(Time.time - lastTime >= speed)
{
lastTime = Time.time;
NextRound();
}
}
}
private void OnGUI()
{
GUI.Label(new Rect(Screen.width - 300, 0, 400, 40), $"Round {round}");
if (GUI.Button(new Rect(Screen.width - 100, 0, 100, 40), "Reset"))
{
ClearState();
isAuto = false;
}
if (GUI.Button(new Rect(Screen.width - 200, 00, 100, 40), "Next"))
{
NextRound();
}
if (GUI.Button(new Rect(Screen.width - 300, 00, 100, 40), "Auto"))
{
isAuto = !isAuto;
}
}
}