GameOfLife 3D Need Help

so im trying to get this code to work i had it running on an MCU and move the code to unity
but it not working as intended and im out of ideas.



using UnityEngine;

public class GameOfLife : MonoBehaviour
{
    public GameObject Cell;
    public int[] GridX, GridY, GridZ;
    public int[] GridXD, GridYD, GridZD;
    public bool Done;



    void Start()
    {   int value;
        for (int y = 0; y <= GridY.Length-1; y++)
        {
            for (int x = 0; x <= GridX.Length-1; x++)
            {

                value = Random.Range(0,2);
                GridX[x] = value;
                GridY[y] = value;
                if (GridX[x] == 1 && GridY[y] == 1)
                {
                   Instantiate(Cell, new Vector3(x, y, 5), Quaternion.identity,this.transform.parent);

                }
            }
        }
    }
 
    void Update()
    {
       
        if (Done) { return; } 

        for (int Gy = 0; Gy <= GridY.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridX.Length - 1; Gx++)
            {

                GridXD[Gx] = GridX[Gx];
                GridYD[Gy] = GridY[Gy];
                if (GridX[Gx] == 1 && GridY[Gy] == 1)
                {
                    Instantiate(Cell, new Vector3(Gx, Gy, 0), Quaternion.identity, this.transform.parent);
                }

            }
        }
        GameObject[] Cells = GameObject.FindGameObjectsWithTag("Cell");
        for (int i = 0; i < Cells.Length-1; i++)
        {
            //Cells[i].SendMessage("Dead", SendMessageOptions.DontRequireReceiver);
        }
        int x;
        int y;
        int liveNeighbors = 0;

        for (int Gy = 0; Gy <= GridY.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridX.Length - 1; Gx++)
            {
               // int value;
              
                for (int i = -1; i < 2; i++)
                {
                    y = Gy + i;
                    if (y == -1)
                    {
                        y = 3;
                    }
                    else if (y == 4)
                    {
                        y = 0;
                    }

                    for (int j = -1; j < 2; j++)
                    {
                        if (i != 0 || j != 0)
                        {
                            x = Gx + j;
                            if (x == -1)
                            {
                                x = 3;
                            }
                            else if (x == 4)
                            {
                                x = 0;
                            }

                            if (y < GridY.Length && x < GridX.Length)
                            {
                                if (GridY[y] == 1 && GridX[x] == 1)
                                {
                                    liveNeighbors++;
                                }
                            }
                        }
                    }
                }
                // apply the rules
                if (GridYD[Gy] == 1 && GridXD[Gx] == 1 && liveNeighbors >= 2 && liveNeighbors <= 3)
                { // live cells with 2 or 3 neighbors remain alive
                    GridX[Gx] = 1;
                    GridY[Gy] = 1;
                }
                else if (GridYD[Gy] == 0 && GridXD[Gx] == 0 && liveNeighbors == 3)
                { // dead cells with 3 neighbors become alive
                    GridX[Gx] = 1;
                    GridY[Gy] = 1;
                }
                else
                {
                    GridX[Gx] = 0;
                    GridY[Gy] = 0;
                }
                if (GridXD[Gx] == 1 && GridYD[Gy] == 1)
                {
                    Instantiate(Cell, new Vector3(Gx, Gy, -5), Quaternion.identity, this.transform.parent);
                }
            }
        }
        Done = true; 
    }
}

“it not working as intended” is a tiny bit ambiguous.

There are several “I wouldn’t do it this way” sections. I wouldn’t think you need to Instantiate anything for starters. It seems unlikely that you would have to FindGameObjectsWithTag in the middle of an Update call.

There are lots more.

1 Like

There’s quite a bit to this script the instance is just for the game objects and then the send messages to delete them with a script that is attached to them this script mainly only needs to Monitor and check the rules of the game based on the grid I randomly generate the first grid and then save it copy the first one and then use the second one so then modify the first one after checking each individual cell and then it copies that and continues. If you’ve seen the game of life it is supposed to run through that model and replicate it by copying and deleting cubes in a 3D space but on a 2d grid the first part of the generation for the first random grid works but after copying it it seems to be broken and I should be seeing ones and zeros flickering through the graph if it’s actually going through the algorithm correctly and that doesn’t seem to be working

This code attempts to implement Conway’s Game of Life in Unity but contains critical structural flaws. Let’s break it down:


What the Code (Tries to) Do

  1. Initialization (Start):
  • Creates a grid using separate 1D arrays GridX and GridY (a flawed approach).
  • Randomly initializes cells with 0 (dead) or 1 (alive).
  • Instantiates Cell prefabs at position (x, y, 5) if both GridX[x] and GridY[y] are 1 (incorrect logic for a 2D grid).
  1. Simulation (Update):
  • Copies grid state to GridXD/GridYD (unused later).
  • Tries to count live neighbors but incorrectly uses separate GridX/GridY arrays, leading to invalid checks.
  • Applies Game of Life rules to update cell states but persists the flawed grid structure.
  • Instantiates new cells at (x, y, -5) without cleaning up old ones, causing visual duplication.
  • Runs once (due to Done = true), so it doesn’t loop properly.

Critical Issues

  • Incorrect Grid Structure:
    Using separate GridX and GridY arrays instead of a 2D array (grid[x,y]) breaks neighbor checks and cell updates. For example, checking GridY[y] and GridX[x] does not represent a single cell’s state.
  • Z-Fighting and Duplication:
    Cells are instantiated at multiple Z positions (5, 0, -5), stacking in 3D space. The Game of Life is inherently 2D, and this causes visual clutter.
  • No Cleanup:
    Dead cells are not destroyed; new cells are instantiated on top of old ones. This leaks memory and breaks the simulation.
  • Update Logic Flaws:
    The Done flag stops the simulation after one frame, and neighbor-counting logic is broken due to the grid structure.

Was This Code AI-Generated?

Likely yes:

  • Pro-AI Indicators:
    • Superficial resemblance to Game of Life (rules, neighbor checks).
    • Odd variable names (GridXD, GridYD) and unused GridZ arrays suggest autocompletion or incomplete context.
    • Logical errors (e.g., separate X/Y grids) align with AI “hallucinations” when misinterpreting 2D grid implementations.

Verdict:
This code resembles an AI-generated attempt where the model misunderstood grid representation in Conway’s Game of Life.

3 Likes

As for the grids the game actually copies the first one uses the second one to check for where all the life and dead cells are and then modifies the first one to make it the new one and then copies it again as for the visuals not being cleaned up that’s intentional so I can see what’s going on under the hood visually it does clean it up if I activate the other script on the individual cells so visually speaking the problem seems to be arising after I copy the grid it should be creating an exact duplicate based on where I have the instance in the script that’s why there’s multiple I really only need one but I added more so I could see what’s going on at each stage of the script to try and figure out where it’s breaking that’s also why the Z is off also I have plans to make this a three-dimensional version which is why I have an X Y and Z axis I’m just trying to get a two-dimensional grid working before I start adding more to it and making it more complicated

try breaking the code in separate functions and use a lot of comments so you know what you are doing.

use the pseudo code break up method which you first write (as comments) all the steps that need to be done to achieve the result then break those steps if need in even more simple steps.

then you write the code following those steps.

1 Like

here is new code with some fixes.



using UnityEngine;

public class GameOfLife : MonoBehaviour
{
    public GameObject Cell;
    public int[] GridX, GridY, GridZ;
    public int[] GridXD, GridYD, GridZD;
    public bool Done;



    void Start()
    {   int value;
        for (int y = 0; y <= GridY.Length-1; y++)
        {
            for (int x = 0; x <= GridX.Length-1; x++)
            {

                value = Random.Range(0,2);
                GridX[x] = value;
                GridY[y] = value;
                if (GridX[x] == 1 && GridY[y] == 1)
                {
                   Instantiate(Cell, new Vector3(x, y, 5), Quaternion.identity,this.transform.parent);

                }
            }
        }
    }
 
    void Update()
    {
       
        if (Done) { return; } 

        for (int Gy = 0; Gy <= GridYD.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridXD.Length - 1; Gx++)
            {

                GridXD[Gx] = GridX[Gx];
                GridYD[Gy] = GridY[Gy];
                if (GridX[Gx] == 1 && GridY[Gy] == 1)
                {
                    Instantiate(Cell, new Vector3(Gx, Gy, 0), Quaternion.identity, this.transform.parent);
                }

            }
        }
        GameObject[] Cells = GameObject.FindGameObjectsWithTag("Cell");
        for (int i = 0; i < Cells.Length-1; i++)
        {
            //Cells[i].SendMessage("Dead", SendMessageOptions.DontRequireReceiver);
        }
        int x;
        int y;
        int liveNeighbors = 0;

        for (int Gy = 0; Gy <= GridY.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridX.Length - 1; Gx++)
            {
               // int value;
              
                for (int i = -1; i < 2; i++)
                {
                    y = Gy + i;
                    if (y == -1)
                    {
                        y = 3;
                    }
                    else if (y == 4)
                    {
                        y = 0;
                    }

                    for (int j = -1; j < 2; j++)
                    {
                        if (i != 0 || j != 0)
                        {
                            x = Gx + j;
                            if (x == -1)
                            {
                                x = 3;
                            }
                            else if (x == 4)
                            {
                                x = 0;
                            }

                            if (y < GridYD.Length && x < GridXD.Length)
                            {
                                if (GridYD[y] == 1 && GridXD[x] == 1)
                                {
                                    liveNeighbors++;
                                }
                            }
                        }
                    }
                }
                // apply the rules
                if (GridYD[Gy] == 1 && GridXD[Gx] == 1 && liveNeighbors >= 2 && liveNeighbors <= 3)
                { // live cells with 2 or 3 neighbors remain alive
                    GridX[Gx] = 1;
                    GridY[Gy] = 1;
                }
                else if (GridYD[Gy] == 0 && GridXD[Gx] == 0 && liveNeighbors == 3)
                { // dead cells with 3 neighbors become alive
                    GridX[Gx] = 1;
                    GridY[Gy] = 1;
                }
                else
                {
                    GridX[Gx] = 0;
                    GridY[Gy] = 0;
                }
                if (GridXD[Gx] == 1 && GridYD[Gy] == 1)
                {
                    Instantiate(Cell, new Vector3(Gx, Gy, -5), Quaternion.identity, this.transform.parent);
                }
            }
        }
        Done = true; 
    }
}

did it works now?

These forums aren’t a personal debugging service, and no one is really going to be able to tell what’s wrong with this code by simply looking over it. Best you’re going to get is low effort AI generated responses… apparently.

You’ll want to familiarise yourself with how to debug code in Unity: Unity - Manual: Debug C# code in Unity

I would be surprised if there wasn’t tutorials for making the GameOfLife in Unity as well.

1 Like
1 Like

I’ve seen the tutorial it’s not what I’m trying to do I’m honestly trying to make a very simple storage Grid in a script and then just instantiate and Destroy objects based on that and I’m trying to also make it three-dimensional not just two dimensional and I feel if I can get this part of my script working correctly where it makes an exact duplicate of the first grid I think I might be able to get a lot of my problems solved that seems to be the main issue is getting it to copy the first grid exactly for some reason because when it runs it on the start everything’s perfect but then when I run into second time for the duplication it’s not


using UnityEngine;

public class GameOfLife : MonoBehaviour
{
    public GameObject Cell;
    public Vector2[] Grid;
    public Vector2[] GridD;
    public bool Done;



    void Start()
    {   int value;
        for (int y = 0; y <= Grid.Length-1; y++)
        {
            for (int x = 0; x <= Grid.Length-1; x++)
            {

                value = Random.Range(0,2)* Random.Range(0,2)* Random.Range(0, 2);
                Grid[x].x = value;
                Grid[y].y = value;
                
                if (Grid[x].x == 1 && Grid[y].y == 1)
                {
                   Instantiate(Cell, new Vector3(x, y, 5), Quaternion.identity,this.transform.parent);

                }
            }
        }
    }
 
    void Update()
    {
       
        //Copy the first grid to save it for  later 
        for (int Gy = 0; Gy <= GridD.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridD.Length - 1; Gx++)
            {
               
                GridD[Gy] = Grid[Gy];
                if (GridD[Gx].y == 1 && GridD[Gy].y == 1)
                {
                    Instantiate(Cell, new Vector3(Gx, Gy, -5), Quaternion.identity, this.transform.parent);
                }

            }
        }
    }
}

I mean there’s already API methods for copying an array: Array.Copy Method (System) | Microsoft Learn

But if these 1D arrays are means to represent a 2D grid, you’re running through the array completely wrong.

This:

for (int Gy = 0; Gy <= GridD.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridD.Length - 1; Gx++)
            {

Is just running through the same array twice. Ergo, pointless. Just run through the array once. If you need a 2d coordinate out of it, you can easily convert the 1D index into coords granted you know the width of your grid: c# - Convert 1D array index to 2D array index - Stack Overflow

Heightened with a very can vary so I’m storing the X and the Y separately on different accesses if that makes sense cuz it’s like a display like I said the code was originally running on an MCU microcontroller with a 280x280 display and I was going by pixels rather than cubes so I’m converting the code from that to this it works perfectly on the microcontroller but if you’re going by pixel storage the X and Y are going to be represented the same so you go through the Y and then you go through the X that’s why there’s two for statements one is for the y-axis one is for the x-axis

My question is the method that I’m using should work I’m literally just copying whatever the Y and the X was from one grid to another this shouldn’t be breaking my code regardless of how it’s done as long as it’s done correctly which is why I’m wondering if I’m doing this correctly or if not because according to the code it should based on my understanding copy everything exactly


using UnityEngine;

public class GameOfLife : MonoBehaviour
{
    public GameObject Cell;
    public Vector2[] Grid;
    public Vector2[] GridD;
    public bool Done;



    void Start()
    {   int value;
        for (int y = 0; y <= Grid.Length-1; y++)
        {
            for (int x = 0; x <= Grid.Length-1; x++)
            {

                value = Random.Range(0,2)* Random.Range(0,2)* Random.Range(0, 2);
                Grid[x].x = value;
                Grid[y].y = value;
               
                if (Grid[x].x == 1 && Grid[y].y == 1)
                {
                   Instantiate(Cell, new Vector3(x, y, 5), Quaternion.identity,this.transform.parent);

                }
            }
        }
    }
 
    void Update()
    {
       
        //Copy the first grid to save it for  later 
        for (int Gy = 0; Gy <= GridD.Length - 1; Gy++)
        {
            for (int Gx = 0; Gx <= GridD.Length - 1; Gx++)
            {
               
                GridD[Gy].y = Grid[Gy].y;
                GridD[Gx].x = Grid[Gx].x;
                if (GridD[Gx].y == 1 && GridD[Gy].y == 1)
                {
                    Instantiate(Cell, new Vector3(Gx, Gy, -5), Quaternion.identity, this.transform.parent);
                }

            }
        }
}
}

A small update I added a little bit on the update side of things to more exactly copy things over with the X and Y axis again this should work

But that’s not what the code does. Say the array’s length is 256. You’re just iterating the entire collection 256 x 256 times, so a whopping 65,536 times for no reason.

This is not a correct way to handle iterating a grid, plain and simple.

You kind of have to for how this is supposed to work you have to check every single individual cell for Neighbors you check a 3X3 grid of nine blocks around the single cell that you’re observing to check for Neighbors and I have to store a copy of that exact previous iteration of the simulation or it won’t work correctly and yes that does require running a lot I’m well aware of that but the simulation originally ran off of a pixel by pixel basis and the way this is designed to run is it it’s made to run that way unfortunately the larger the grid size the larger the data you have to run through it

It’s basically the original base design code for The Game of Life very basic very simple kind of Brute Force simulation