Skip to content

Instantly share code, notes, and snippets.

@GRAYgoose124
Created November 5, 2023 22:18
Show Gist options
  • Save GRAYgoose124/7ff0a85728ff3acda8fac81075af15c4 to your computer and use it in GitHub Desktop.
Save GRAYgoose124/7ff0a85728ff3acda8fac81075af15c4 to your computer and use it in GitHub Desktop.
3d gol experiment w/ three.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3D Game of Life</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<script>
// Set up the scene, camera, and renderer as usual
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 20;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// GoL constants
const gridSize = 20;
const GENERATION_DELAY = 250;
// init grid with rand states
const cells = new Array(gridSize);
const cellDistances = new Array(gridSize);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.25 });
const cube = new THREE.InstancedMesh(geometry, material, gridSize * gridSize * gridSize);
scene.add(cube);
function initScene() {
for (let x = 0; x < gridSize; x++) {
cells[x] = new Array(gridSize);
for (let y = 0; y < gridSize; y++) {
cells[x][y] = new Array(gridSize);
for (let z = 0; z < gridSize; z++) {
cells[x][y][z] = Math.floor(Math.random() * 2) === 0 ? 1 : 0;
}
}
}
}
function updateScene() {
let instanceId = 0;
const dummy = new THREE.Object3D();
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
for (let z = 0; z < gridSize; z++) {
if (cells[x][y][z] === 1) {
dummy.position.set(x - gridSize / 2, y - gridSize / 2, z - gridSize / 2);
dummy.updateMatrix();
cube.setMatrixAt(instanceId++, dummy.matrix);
}
}
}
}
cube.instanceMatrix.needsUpdate = true;
}
function cloneCells(cells) {
const clonedCells = new Array(cells.length);
for (let x = 0; x < cells.length; x++) {
clonedCells[x] = new Array(cells[x].length);
for (let y = 0; y < cells[x].length; y++) {
clonedCells[x][y] = cells[x][y].slice();
}
}
return clonedCells;
}
function computeNextGeneration() {
const newCells = cloneCells(cells);
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
for (let z = 0; z < gridSize; z++) {
let liveNeighbors = 0;
// neighborhood of 3x3x3
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
for (let k = -1; k <= 1; k++) {
if (i === 0 && j === 0 && k === 0) continue; // Skip the current cell
const nx = x + i;
const ny = y + j;
const nz = z + k;
if (nx >= 0 && nx < gridSize && ny >= 0 && ny < gridSize && nz >= 0 && nz < gridSize) {
liveNeighbors += cells[nx][ny][nz];
}
}
}
}
if (cells[x][y][z] === 1) { // If the cell is alive
if (liveNeighbors < 4 || liveNeighbors > 8) {
newCells[x][y][z] = 0; // Cell dies
}
} else { // If the cell is dead
if (liveNeighbors === 5 || liveNeighbors === 6) {
newCells[x][y][z] = 1; // Cell becomes alive
}
}
}
}
}
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
for (let z = 0; z < gridSize; z++) {
cells[x][y][z] = newCells[x][y][z];
}
}
}
setTimeout(computeNextGeneration, GENERATION_DELAY);
}
function animate() {
requestAnimationFrame(animate);
scene.rotation.x += 0.005;
scene.rotation.y += 0.005;
updateScene();
renderer.render(scene, camera);
}
initScene();
animate();
computeNextGeneration();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment