Home / Projects / ConwayGOL

Game Design

Conway's Game of Life

The Noita Grid State System is a Unity-based grid simulation that models interacting materials like powders, liquids, gases, and solids with behaviours such as gravity, viscosity, and dynamic reactions.

Role Developer / Researcher
Duration 1 Weeks
Stack Unity / C#
Focus Simulation
Related Project

KitKat Advertisement

May 2024

A dive into learning C# and finding the most efficient way to calculate squart roots.

Video Editing Experimental Blender
View project

Project Overview

What this project is

The Noita Grid State System is an experimental project where I attempted to recreate the core idea behind the simulation system used in Noita without researching how the original game implemented it. The goal was to explore how a grid-based particle simulation could support different material types interacting with each other in real time.

The result is a working sandbox that simulates elements such as powders, liquids, solids, and gases, each with their own behaviour rules. Materials respond to gravity, liquids flow depending on viscosity, and gases rise upward. Elements can also react with one another, allowing new materials to be created dynamically during the simulation. For example, when water and lava come into contact they produce stone and smoke.

The project originally started as a simple falling sand simulation, but gradually evolved into a more flexible system designed to support many different materials and interactions.

Problem

The challenge

The main challenge was designing a system that could simulate thousands of small particles interacting with each other while still remaining flexible enough to easily add new elements. Unlike traditional physics systems where objects are independent rigid bodies, this simulation works on a grid of cells where each cell represents a single particle of material. Each update step the simulation evaluates how particles should move and interact with neighbouring cells.

This means the system needs to handle several behaviours simultaneously:

- Gravity and falling particles

- Liquids flowing and spreading

- Powders forming piles

- Gases rising

- Chemical reactions between neighbouring materials

Another important challenge was expandability. Hardcoding behaviour for every element would quickly become difficult to maintain. Instead, the system needed to be designed in a way that made it easy to introduce new materials and interactions.

Notes

What is the interactive demo?

The demo on this page is a simplified sandbox built in Unity using a 2D grid simulation. Each visible pixel represents a particle in the simulation grid. When an element is placed into the world it immediately begins following the rules defined for that material.

Powders fall and accumulate naturally, liquids spread across surfaces depending on their viscosity, and gases rise upward through other materials. Certain elements can also react with each other, producing new materials as part of the simulation.

The purpose of this demo is not to perfectly replicate Noita, but to demonstrate how a grid-based particle system can support multiple material types and interactions in real time.

Approach

Element system [Scriptable Objects]

Elements in the simulation are defined using Unity Scriptable Objects. Each Scriptable Object represents a material and contains the properties that control how that element behaves inside the grid.

These properties include things such as gravity strength, viscosity, element type, and possible reactions with other elements. By defining elements as data rather than hardcoded logic, new materials can be created quickly inside the Unity editor without modifying the simulation code.

This makes the system highly expandable, allowing new materials such as lava, smoke, water, or acid to be introduced simply by creating new element definitions.

Code


using UnityEngine;

public enum ElementType { Empty, Powder, Liquid, Gas, Solid }

[CreateAssetMenu(menuName = "Simulation/Element")]
public class Element : ScriptableObject
{
    [Header("Identity")]
    public ushort id;                 // must be unique
    public string displayName;
    public Sprite sprite;
    public ElementType type;

    [Header("Visual")]
    public Color32 color;

    [Header("Physics")]
    public byte dispersion = 2;       // how far sideways it tries (liquid)
    public byte fallSpeed = 1;        // gravity
    public short density = 10;        // can be negative (smoke), positive (sand), etc.
    public byte viscosity = 0;        // 0 = water-ish, higher = syrup/soup

    [Header("Reactions")]
    public ReactionRule[] reactions;  
}

[System.Serializable]
public class ReactionRule
{
    public ushort withElementId;      // neighbor element
    public ushort resultSelfId;       // what current cell becomes
    public ushort resultOtherId;      // what neighbor becomes
    [Range(0f , 1f)] public float chance = 1f;
}
              

Technical Notes

Challenges and what I learned

Talk about the hardest parts, what changed during development, what trade-offs you made, and what you would improve next.