TwitterでアップしたLifeGameのコードを書いておきます。
気分転換にLifeGame組んだ。HighLife(23/36)設定。
— MIYAKE (@ScreenPocket) March 31, 2020
Unityで組むのは初かも?コードは簡単なので後でどこかに上げます。 pic.twitter.com/0IQGm4av47
使用する際はこのコードのコンポーネントをつけるだけで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);
}
}