unity—GUI小游戏“生命游戏”

本文介绍了如何使用Unity编程实现经典的生命游戏,包括游戏规则、二维方格的设定、系统处理和控制组件。玩家可以通过按钮操作细胞的生存与繁殖,观察复杂模式的出现。

“生命游戏”介绍:

        生命游戏(Game of Life)是一种经典的细胞自动机,由英国数学家约翰·康威(John Conway)在1970年提出。它是一个零玩家游戏,意味着其演化完全依赖于初始配置,不需要玩家的干预。

  1. 游戏发生在一个二维的方格世界中,每个方格被称为一个细胞,每个细胞可以处于存活(活细胞)或死亡(死细胞)的状态。

  2. 每个细胞的状态由其周围的八个相邻细胞决定。周围的八个相邻细胞是指横向、纵向和对角线上与当前细胞相邻的细胞。

  3. 根据当前细胞及其周围细胞的状态,按照以下规则确定下一代细胞的状态:

    • 如果一个细胞是存活的,并且它周围的活细胞数量少于2个,那么它在下一代将变为死亡状态(模拟人口稀疏)。
    • 如果一个细胞是存活的,并且它周围有2个或3个活细胞,那么它在下一代将保持存活状态。
    • 如果一个细胞是存活的,并且它周围的活细胞数量超过3个,那么它在下一代将变为死亡状态(模拟人口过剩)。
    • 如果一个细胞是死亡的,并且它周围的活细胞数量恰好是3个,那么它在下一代将变为存活状态(模拟繁殖)。
  4. 所有细胞同时进行状态更新,而不是一个接一个地更新。

  5. 按照这些规则,生命游戏的细胞状态会在每一代中进行演化和变化。游戏的初始状态可以是随机生成的,也可以由玩家设定。生命游戏的特点是简单的规则能够产生出复杂的演化和模式,包括静态结构、振荡器、飞船和稳定的无限增长模式等。

一、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小游戏--模拟“生命游戏”(在简单的规则下,生命的演变也能如此复杂而有规律)

可以看到,在某些初始状态下,细胞最终能演变成稳定的或者振荡的状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值