LoginSignup
0
1

More than 3 years have passed since last update.

UnityでLifeGameのコードを書いた

Last updated at Posted at 2020-04-01

TwitterでアップしたLifeGameのコードを書いておきます。

使用する際はこのコードのコンポーネントをつけるだけでOK。自動でMeshFilterもMeshRendererも準備されます。
こういうのをぼんやり眺めるのが結構好き。
※パラメータはご自由に調整してください。

lifegame.cs
using UnityEngine;
using UnityEngine.Rendering;

public class LifeGame : MonoBehaviour
{
    private const int kWidth = 512;
    private const int kHeight = 512;

    /// <summary>
    /// 格子
    /// </summary>
    private readonly int[] _grids = new int[kWidth * kHeight];
    /// <summary>
    /// 次のフレームの結果格納用
    /// </summary>
    private readonly int[] _nextGrids = new int[kWidth * kHeight];

    private MeshFilter _meshFilter;
    private MeshRenderer _meshRenderer;

    private Material _material;
    private Mesh _mesh;

    /// <summary>
    /// 位置座標
    /// 最初に確定しておいて、後はindexでピクセルの有無を切り替える
    /// </summary>
    private readonly Vector3[] _positions = new Vector3[kWidth * kHeight];
    /// <summary>
    /// index
    /// </summary>
    private readonly int[] _indices = new int[kWidth * kHeight];

    private void Start()
    {
        var minPos = new Vector3(-kWidth * 0.5f, -kHeight * 0.5f, 0f);
        for (int i = 0; i < kWidth * kHeight; ++i)
        {
            var x = i % kWidth;
            var y = i / kWidth;
            //4%くらいの確率でLifeを置く
            _grids[i] = Random.Range(0,100) < 4 ? 1 : 0;
            //先に頂点を並べておいてIndexの変更でピクセルを切り替える
            _positions[i] = minPos + new Vector3(x,y,0);
        }

        _meshFilter = gameObject.AddComponent<MeshFilter>();
        _mesh = new Mesh();
        _mesh.name = "GridPoint";
        _mesh.MarkDynamic();
        _mesh.SetVertices(_positions, 0, kWidth * kHeight);
        _mesh.indexFormat = IndexFormat.UInt32;
        _meshFilter.sharedMesh = _mesh;
        _mesh.RecalculateBounds();

        _material = new Material(Shader.Find("Unlit/Color"));
        _material.color = Color.white;

        _meshRenderer = gameObject.AddComponent<MeshRenderer>();
        _meshRenderer.sharedMaterial = _material;
    }

    private void Update()
    {
        int lifeCount = 0;
        for (int i = 0, count = kWidth * kHeight; i < count ; ++i)
        {
            var x = i % kWidth;
            var y = i / kWidth;

            //左
            var l = x == 0 ? kWidth - 1 : x - 1;
            //右
            var r = x == kWidth - 1 ? 0 : x + 1;
            //上
            var t = y == 0 ? kHeight - 1 : y - 1;
            //下
            var b = y == kHeight - 1 ? 0 : y + 1;


            //隣接生存数を集計
            var neighborCount = _grids[l + t * kWidth];//左上
            neighborCount += _grids[x + t * kWidth];//上
            neighborCount += _grids[r + t * kWidth];//右上
            neighborCount += _grids[l + y * kWidth];//左
            neighborCount += _grids[r + y * kWidth];//右
            neighborCount += _grids[l + b * kWidth];//左下
            neighborCount += _grids[x + b * kWidth];//下
            neighborCount += _grids[r + b * kWidth];//右下

            var centerIndex = x + y * kWidth;
            if (neighborCount == 3 || neighborCount == 6)
            {
                //発生
                _nextGrids[centerIndex] = 1;
            }
            else if (neighborCount == 2 || neighborCount == 3)
            {
                //現状維持
                _nextGrids[centerIndex] = _grids[centerIndex];
            }
            else
            {
                //死亡
                _nextGrids[centerIndex] = 0;
            }

            if (_nextGrids[centerIndex] != 0)
            {
                //index更新
                _indices[lifeCount] = i;
                lifeCount++;
            }
        }

        System.Array.Copy(_nextGrids, _grids, _nextGrids.Length);

        //index更新
        _mesh.SetIndices(_indices, 0, lifeCount,MeshTopology.Points, 0);
    }
}

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1