“生命游戏”介绍:
生命游戏(Game of Life)是一种经典的细胞自动机,由英国数学家约翰·康威(John Conway)在1970年提出。它是一个零玩家游戏,意味着其演化完全依赖于初始配置,不需要玩家的干预。
-
游戏发生在一个二维的方格世界中,每个方格被称为一个细胞,每个细胞可以处于存活(活细胞)或死亡(死细胞)的状态。
-
每个细胞的状态由其周围的八个相邻细胞决定。周围的八个相邻细胞是指横向、纵向和对角线上与当前细胞相邻的细胞。
-
根据当前细胞及其周围细胞的状态,按照以下规则确定下一代细胞的状态:
- 如果一个细胞是存活的,并且它周围的活细胞数量少于2个,那么它在下一代将变为死亡状态(模拟人口稀疏)。
- 如果一个细胞是存活的,并且它周围有2个或3个活细胞,那么它在下一代将保持存活状态。
- 如果一个细胞是存活的,并且它周围的活细胞数量超过3个,那么它在下一代将变为死亡状态(模拟人口过剩)。
- 如果一个细胞是死亡的,并且它周围的活细胞数量恰好是3个,那么它在下一代将变为存活状态(模拟繁殖)。
-
所有细胞同时进行状态更新,而不是一个接一个地更新。
-
按照这些规则,生命游戏的细胞状态会在每一代中进行演化和变化。游戏的初始状态可以是随机生成的,也可以由玩家设定。生命游戏的特点是简单的规则能够产生出复杂的演化和模式,包括静态结构、振荡器、飞船和稳定的无限增长模式等。
一、unity游戏简单布置
1、写好脚本、预制物件、材料等等: 
2、新建一个空物体:

3、将第一步的脚本(第三部分的代码文件)等拖动至左侧边栏处的空物体:

4、点击上方的运行按钮,开始运行(如果没有别的物件要添加的话):

二、游戏大致框架

三、lifegame(生命游戏)代码部分(第一步中的代码文件内容)
代码分为三个部分:
(1)、Entities and their states / Model
一些实体、变量等
(2)、System Handlers
包括start、ongui函数等
(3)、Components /controls
一些功能函数(初始化、更新、按钮事件)
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class LifeGame : MonoBehaviour
{
// 第一部分:Entities and their states / Model
private int gridSize = 80;
private float buttonSize =8f;
private float buttonSpacing = 0f;
private float buttonSpacing2 = 20f;
private Rect firstGridRect;
private Rect actionRect;
private Rect cleanRect;
private int[,] cellboard;
private int[,] new_cellboard;
private int action=0;
public UnityEngine.Color buttonColor = UnityEngine.Color.red; // 要更改的按钮颜色
public int[,] dir = new int[,]
{
{-1, -1}, // 左上
{-1, 0}, // 上
{-1, 1}, // 右上
{0, 1}, // 右
{1, 1}, // 右下
{1, 0}, // 下
{1, -1}, // 左下
{0, -1} // 左
};
private int count=0;
// 第二部分: System Handlers
void Start () {
Initboard();
}
void OnGUI()
{
// 计算网格的位置和大小
float gridWidth = (buttonSize + buttonSpacing) * gridSize;
float gridHeight = (buttonSize + buttonSpacing) * gridSize;
float gridX = (Screen.width - gridWidth) / 2f; // 在视图中央水平居中
float gridY = (Screen.height - gridHeight) / 2f; // 在视图中央垂直居中
firstGridRect = new Rect(gridX, gridY, gridWidth, gridHeight);
// 绘制网格
DrawGrid();
// 计算开始按钮的位置和大小
float actionButtonX = firstGridRect.x + firstGridRect.width + buttonSpacing2;
float actionButtonY = firstGridRect.y;
actionRect = new Rect(actionButtonX, actionButtonY, buttonSize * 5, buttonSize * 3);
// 绘制按钮
DrawActionButton();
// 计算清除按钮的位置和大小
float cleanButtonX = firstGridRect.x + firstGridRect.width + buttonSpacing2;
float cleanButtonY = firstGridRect.y + buttonSize * 5;
cleanRect = new Rect(cleanButtonX, cleanButtonY, buttonSize * 5, buttonSize * 3);
// 绘制按钮
DrawCleanButton();
//更新(count用来控制更新速度)
if(action==1&&count%9==1){
updateCellBoard();
}
count++;
if(count>10000000){
count=0;//简单地避免count超出整型范围(或许没有必要)
}
}
// 第三部分: Components /controls
void Initboard(){
UnityEngine.Debug.Log("init");
cellboard = new int[gridSize, gridSize];
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
cellboard[i,j]=0;
}
}
new_cellboard=new int[gridSize,gridSize];
}
void DrawGrid()
{
GUIStyle customButtonStyle = new GUIStyle(GUI.skin.button);
// 创建纯色背景贴图
Texture2D backgroundTexture = new Texture2D(1, 1);
backgroundTexture.SetPixel(0, 0, buttonColor);
backgroundTexture.Apply();
// 设置按钮背景贴图
customButtonStyle.normal.background = backgroundTexture;
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
float x = firstGridRect.x + j * (buttonSize + buttonSpacing);
float y = firstGridRect.y + i * (buttonSize + buttonSpacing);
Rect buttonRect = new Rect(x, y, buttonSize, buttonSize);
if(action==0){
if(cellboard[i,j]==0&&GUI.Button(buttonRect, "")){
cellboard[i,j]=1-cellboard[i,j];
}
else if(cellboard[i,j]==1&&GUI.Button(buttonRect, "",customButtonStyle)) {
cellboard[i,j]=1-cellboard[i,j];
}
}
else if(action==1){
if(cellboard[i,j]==0){
GUI.Button(buttonRect, "");
}
else if(cellboard[i,j]==1) {
GUI.Button(buttonRect, "",customButtonStyle);
}
}
}
}
customButtonStyle.normal.background = null;
}
void DrawActionButton()
{
if (action==0 && GUI.Button(actionRect, "start")){
action=1-action;
}
else if(action==1 && GUI.Button(actionRect, "stop"))
{
action=1-action;
}
}
void DrawCleanButton()
{
if(action==0 && GUI.Button(cleanRect, "clean"))
{
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
cellboard[i,j]=0;
}
}
}
}
void updateCellBoard(){
//红为1,黑为0
//格周,多于3红则为黑,3红则为红,2红则不变,少于2红则为黑
//在生命游戏中,红代表存活的细胞,黑代表死亡的细胞
for(int i=0;i<gridSize;i++){
for(int j=0;j<gridSize;j++){
int life_num=0;
for(int k=0;k<8;k++){
int new_i=dir[k,0]+i;
int new_j=dir[k,1]+j;
if(new_i>=0&&new_i<gridSize && new_j>=0&&new_j<gridSize){
if(cellboard[new_i,new_j]==1){
life_num++;
}
}
}
if(life_num>3) new_cellboard[i,j]=0;
else if(life_num==3) new_cellboard[i,j]=1;
else if(life_num==2) new_cellboard[i,j]=cellboard[i,j];
else if(life_num<2) new_cellboard[i,j]=0;
}
}
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
cellboard[i,j]=new_cellboard[i,j];
}
}
}
}
四、效果:
点击按钮可以使之变红(代表一个存活的细胞)。布置好初始状态之后,点击start,开始进行细胞的繁衍与消亡。期间可以点击stop查看状态,或者clean掉重新布置。
视频链接:unity小游戏--模拟“生命游戏”(在简单的规则下,生命的演变也能如此复杂而有规律)




可以看到,在某些初始状态下,细胞最终能演变成稳定的或者振荡的状态。
本文介绍了如何使用Unity编程实现经典的生命游戏,包括游戏规则、二维方格的设定、系统处理和控制组件。玩家可以通过按钮操作细胞的生存与繁殖,观察复杂模式的出现。
777

被折叠的 条评论
为什么被折叠?



