/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Single cell in the grid var Cell = Container.expand(function () { var self = Container.call(this); // Attach a square asset for the cell var cellAsset = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); // Add inner cell for better visual effect var innerCell = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.85, scaleY: 0.85 }); self.isAlive = false; self.gridX = 0; self.gridY = 0; // Set cell state (alive/dead) self.setAlive = function (alive) { self.isAlive = alive; cellAsset.color = alive ? 0x9c27b0 : 0x1a1a1a; cellAsset.alpha = alive ? 0.9 : 0.3; innerCell.color = alive ? 0x8e24aa : 0x222222; innerCell.alpha = alive ? 1 : 0.2; }; // Flash cell when it changes state self.flash = function () { // Flash outer cell tween(cellAsset, { alpha: 1, scaleX: 1.1, scaleY: 1.1 }, { duration: 60, easing: tween.easeOut, onFinish: function onFinish() { tween(cellAsset, { alpha: self.isAlive ? 0.9 : 0.3, scaleX: 1, scaleY: 1 }, { duration: 90 }); } }); // Flash inner cell tween(innerCell, { scaleX: 1.2, scaleY: 1.2 }, { duration: 50, easing: tween.easeOut, onFinish: function onFinish() { tween(innerCell, { scaleX: 0.85, scaleY: 0.85 }, { duration: 75 }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a0a }); /**** * Game Code ****/ // Grid settings var GRID_COLS = 24; var GRID_ROWS = 24; var CELL_SIZE = 80; // Smaller cells to fit more var GRID_WIDTH = GRID_COLS * CELL_SIZE; var GRID_HEIGHT = GRID_ROWS * CELL_SIZE; var GRID_OFFSET_X = (2048 - GRID_WIDTH) / 2; var GRID_OFFSET_Y = (2732 - GRID_HEIGHT) / 2 + 60; // 2D array of cells var grid = []; var cellNodes = []; // Used to track drawing state var isDrawing = false; var drawState = true; // true = drawing alive, false = erasing // Create cell asset (square) // Create grid of cells for (var y = 0; y < GRID_ROWS; y++) { var row = []; var nodeRow = []; for (var x = 0; x < GRID_COLS; x++) { var cell = new Cell(); cell.gridX = x; cell.gridY = y; cell.x = GRID_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2; cell.y = GRID_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2; cell.setAlive(false); game.addChild(cell); row.push(0); nodeRow.push(cell); } grid.push(row); cellNodes.push(nodeRow); } // Draw grid lines for visual styling // Horizontal lines for (var y = 0; y <= GRID_ROWS; y++) { var hLine = LK.getAsset('gridLine', { anchorX: 0, anchorY: 0.5, scaleX: GRID_WIDTH / 2, scaleY: 1 }); hLine.x = GRID_OFFSET_X; hLine.y = GRID_OFFSET_Y + y * CELL_SIZE; hLine.alpha = 0.3; game.addChild(hLine); } // Vertical lines for (var x = 0; x <= GRID_COLS; x++) { var vLine = LK.getAsset('gridLine', { anchorX: 0.5, anchorY: 0, scaleX: 1, scaleY: GRID_HEIGHT / 2 }); vLine.x = GRID_OFFSET_X + x * CELL_SIZE; vLine.y = GRID_OFFSET_Y; vLine.alpha = 0.3; game.addChild(vLine); } // Draw instructions var instructions = new Text2("Draw: Tap cells\nEvolve: Press ▶", { size: 70, fill: 0xE0E0E0 }); instructions.anchor.set(0.5, 0); LK.gui.top.addChild(instructions); // Add Glider text below instructions var gliderText = new Text2("Glaud", { size: 60, fill: 0x9c27b0 }); gliderText.anchor.set(0.5, 0); gliderText.y = 100; LK.gui.top.addChild(gliderText); // Add evolve/play button var playBtn = new Text2("▶", { size: 120, fill: 0x9c27b0 }); playBtn.anchor.set(0.5, 0.5); playBtn.x = 0; playBtn.y = -120; LK.gui.bottom.addChild(playBtn); // Add reset button var resetBtn = new Text2("⟳", { size: 90, fill: 0xFFFFFF }); resetBtn.anchor.set(0.5, 0.5); resetBtn.x = -180; resetBtn.y = -120; LK.gui.bottom.addChild(resetBtn); // Add step button var stepBtn = new Text2("⏭", { size: 90, fill: 0xFFFFFF }); stepBtn.anchor.set(0.5, 0.5); stepBtn.x = 180; stepBtn.y = -120; LK.gui.bottom.addChild(stepBtn); // Conway's Game of Life instructions.setText("Conway's Game of Life\nDraw & Press ▶"); // State var isRunning = false; var evolveTimer = null; // Helper: get alive neighbor count function countAliveNeighbors(gx, gy) { var count = 0; for (var dy = -1; dy <= 1; dy++) { for (var dx = -1; dx <= 1; dx++) { if (dx === 0 && dy === 0) { continue; } var nx = gx + dx; var ny = gy + dy; if (nx >= 0 && nx < GRID_COLS && ny >= 0 && ny < GRID_ROWS) { if (cellNodes[ny][nx].isAlive) { count++; } } } } return count; } // Evolve grid by one step function evolveGrid() { var toLive = []; var toDie = []; var toRegen = []; var changed = false; for (var y = 0; y < GRID_ROWS; y++) { for (var x = 0; x < GRID_COLS; x++) { var cell = cellNodes[y][x]; var alive = cell.isAlive; var neighbors = countAliveNeighbors(x, y); // Conway's Game of Life rules if (alive) { // Living cell survives with 2 or 3 neighbors if (neighbors < 2 || neighbors > 3) { toDie.push(cell); changed = true; } } else { // Dead cell becomes alive with exactly 3 neighbors if (neighbors === 3) { toRegen.push(cell); changed = true; } } } } // Apply changes for (var i = 0; i < toDie.length; i++) { toDie[i].setAlive(false); toDie[i].flash(); } if (toDie.length > 0) { LK.getSound('cellDie').play(); } for (var i = 0; i < toRegen.length; i++) { toRegen[i].setAlive(true); toRegen[i].flash(); } if (toRegen.length > 0) { LK.getSound('cellBorn').play(); } } // Start/stop evolution function startEvolve() { if (isRunning) { return; } isRunning = true; instructions.setText("Running - Draw to modify"); evolveTimer = LK.setInterval(function () { evolveGrid(); }, 200); } function stopEvolve() { if (!isRunning) { return; } isRunning = false; instructions.setText("Conway's Game of Life\nDraw & Press ▶"); if (evolveTimer) { LK.clearInterval(evolveTimer); evolveTimer = null; } } // Reset grid function resetGrid() { stopEvolve(); for (var y = 0; y < GRID_ROWS; y++) { for (var x = 0; x < GRID_COLS; x++) { cellNodes[y][x].setAlive(false); } } } // Step evolution once function stepEvolve() { if (isRunning) { return; } evolveGrid(); } // Draw GLAUD text pattern on grid function drawGlaud() { // Clear grid first for (var y = 0; y < GRID_ROWS; y++) { for (var x = 0; x < GRID_COLS; x++) { cellNodes[y][x].setAlive(false); } } // GLAUD pattern (3x5 letters with 1 space between) - smaller version // Starting position to center the text var startX = 3; var startY = 10; // G var G = [[1, 1, 1], [1, 0, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1]]; // L var L = [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]]; // A var A = [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]]; // U var U = [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]]; // D var D = [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]]; var letters = [G, L, A, U, D]; var xOffset = startX; // Draw each letter for (var letterIdx = 0; letterIdx < letters.length; letterIdx++) { var letter = letters[letterIdx]; for (var ly = 0; ly < letter.length; ly++) { for (var lx = 0; lx < letter[ly].length; lx++) { var cellX = xOffset + lx; var cellY = startY + ly; if (cellX < GRID_COLS && cellY < GRID_ROWS && letter[ly][lx] === 1) { cellNodes[cellY][cellX].setAlive(true); cellNodes[cellY][cellX].flash(); } } } xOffset += 4; // Move to next letter position (3 width + 1 space) } } // Find cell at game coordinates function getCellAt(x, y) { for (var row = 0; row < GRID_ROWS; row++) { for (var col = 0; col < GRID_COLS; col++) { var cell = cellNodes[row][col]; var left = cell.x - CELL_SIZE / 2; var right = cell.x + CELL_SIZE / 2; var top = cell.y - CELL_SIZE / 2; var bottom = cell.y + CELL_SIZE / 2; if (x >= left && x < right && y >= top && y < bottom) { return cell; } } } return null; } // Handle drawing on grid game.down = function (x, y, obj) { var cell = getCellAt(x, y); if (cell) { isDrawing = true; drawState = !cell.isAlive; cell.setAlive(drawState); cell.flash(); LK.getSound('draw').play(); } }; game.move = function (x, y, obj) { // Add hover effect even when not drawing var cell = getCellAt(x, y); if (cell && !isDrawing) { // Subtle hover effect tween(cell, { alpha: 0.8 }, { duration: 100 }); } if (!isDrawing) { return; } if (cell && cell.isAlive !== drawState) { cell.setAlive(drawState); cell.flash(); LK.getSound('draw').play(); } }; game.up = function (x, y, obj) { isDrawing = false; }; // Play button events playBtn.down = function (x, y, obj) { if (isRunning) { stopEvolve(); playBtn.setText("▶"); LK.getSound('evolveStop').play(); } else { startEvolve(); playBtn.setText("⏸"); LK.getSound('evolveStart').play(); } }; resetBtn.down = function (x, y, obj) { resetGrid(); playBtn.setText("▶"); LK.getSound('buttonPress').play(); }; stepBtn.down = function (x, y, obj) { stepEvolve(); LK.getSound('buttonPress').play(); }; // Prevent accidental grid drawing when using GUI LK.gui.bottom.down = function (x, y, obj) {}; LK.gui.bottom.move = function (x, y, obj) {}; LK.gui.bottom.up = function (x, y, obj) {}; // Initialize with GLAUD pattern drawGlaud(); // Play background music LK.playMusic('bgMusic'); // No update loop needed for this game game.update = function () { // No-op };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Single cell in the grid
var Cell = Container.expand(function () {
var self = Container.call(this);
// Attach a square asset for the cell
var cellAsset = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
// Add inner cell for better visual effect
var innerCell = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.85,
scaleY: 0.85
});
self.isAlive = false;
self.gridX = 0;
self.gridY = 0;
// Set cell state (alive/dead)
self.setAlive = function (alive) {
self.isAlive = alive;
cellAsset.color = alive ? 0x9c27b0 : 0x1a1a1a;
cellAsset.alpha = alive ? 0.9 : 0.3;
innerCell.color = alive ? 0x8e24aa : 0x222222;
innerCell.alpha = alive ? 1 : 0.2;
};
// Flash cell when it changes state
self.flash = function () {
// Flash outer cell
tween(cellAsset, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(cellAsset, {
alpha: self.isAlive ? 0.9 : 0.3,
scaleX: 1,
scaleY: 1
}, {
duration: 90
});
}
});
// Flash inner cell
tween(innerCell, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(innerCell, {
scaleX: 0.85,
scaleY: 0.85
}, {
duration: 75
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
// Grid settings
var GRID_COLS = 24;
var GRID_ROWS = 24;
var CELL_SIZE = 80; // Smaller cells to fit more
var GRID_WIDTH = GRID_COLS * CELL_SIZE;
var GRID_HEIGHT = GRID_ROWS * CELL_SIZE;
var GRID_OFFSET_X = (2048 - GRID_WIDTH) / 2;
var GRID_OFFSET_Y = (2732 - GRID_HEIGHT) / 2 + 60;
// 2D array of cells
var grid = [];
var cellNodes = [];
// Used to track drawing state
var isDrawing = false;
var drawState = true; // true = drawing alive, false = erasing
// Create cell asset (square)
// Create grid of cells
for (var y = 0; y < GRID_ROWS; y++) {
var row = [];
var nodeRow = [];
for (var x = 0; x < GRID_COLS; x++) {
var cell = new Cell();
cell.gridX = x;
cell.gridY = y;
cell.x = GRID_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
cell.y = GRID_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
cell.setAlive(false);
game.addChild(cell);
row.push(0);
nodeRow.push(cell);
}
grid.push(row);
cellNodes.push(nodeRow);
}
// Draw grid lines for visual styling
// Horizontal lines
for (var y = 0; y <= GRID_ROWS; y++) {
var hLine = LK.getAsset('gridLine', {
anchorX: 0,
anchorY: 0.5,
scaleX: GRID_WIDTH / 2,
scaleY: 1
});
hLine.x = GRID_OFFSET_X;
hLine.y = GRID_OFFSET_Y + y * CELL_SIZE;
hLine.alpha = 0.3;
game.addChild(hLine);
}
// Vertical lines
for (var x = 0; x <= GRID_COLS; x++) {
var vLine = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1,
scaleY: GRID_HEIGHT / 2
});
vLine.x = GRID_OFFSET_X + x * CELL_SIZE;
vLine.y = GRID_OFFSET_Y;
vLine.alpha = 0.3;
game.addChild(vLine);
}
// Draw instructions
var instructions = new Text2("Draw: Tap cells\nEvolve: Press ▶", {
size: 70,
fill: 0xE0E0E0
});
instructions.anchor.set(0.5, 0);
LK.gui.top.addChild(instructions);
// Add Glider text below instructions
var gliderText = new Text2("Glaud", {
size: 60,
fill: 0x9c27b0
});
gliderText.anchor.set(0.5, 0);
gliderText.y = 100;
LK.gui.top.addChild(gliderText);
// Add evolve/play button
var playBtn = new Text2("▶", {
size: 120,
fill: 0x9c27b0
});
playBtn.anchor.set(0.5, 0.5);
playBtn.x = 0;
playBtn.y = -120;
LK.gui.bottom.addChild(playBtn);
// Add reset button
var resetBtn = new Text2("⟳", {
size: 90,
fill: 0xFFFFFF
});
resetBtn.anchor.set(0.5, 0.5);
resetBtn.x = -180;
resetBtn.y = -120;
LK.gui.bottom.addChild(resetBtn);
// Add step button
var stepBtn = new Text2("⏭", {
size: 90,
fill: 0xFFFFFF
});
stepBtn.anchor.set(0.5, 0.5);
stepBtn.x = 180;
stepBtn.y = -120;
LK.gui.bottom.addChild(stepBtn);
// Conway's Game of Life
instructions.setText("Conway's Game of Life\nDraw & Press ▶");
// State
var isRunning = false;
var evolveTimer = null;
// Helper: get alive neighbor count
function countAliveNeighbors(gx, gy) {
var count = 0;
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) {
continue;
}
var nx = gx + dx;
var ny = gy + dy;
if (nx >= 0 && nx < GRID_COLS && ny >= 0 && ny < GRID_ROWS) {
if (cellNodes[ny][nx].isAlive) {
count++;
}
}
}
}
return count;
}
// Evolve grid by one step
function evolveGrid() {
var toLive = [];
var toDie = [];
var toRegen = [];
var changed = false;
for (var y = 0; y < GRID_ROWS; y++) {
for (var x = 0; x < GRID_COLS; x++) {
var cell = cellNodes[y][x];
var alive = cell.isAlive;
var neighbors = countAliveNeighbors(x, y);
// Conway's Game of Life rules
if (alive) {
// Living cell survives with 2 or 3 neighbors
if (neighbors < 2 || neighbors > 3) {
toDie.push(cell);
changed = true;
}
} else {
// Dead cell becomes alive with exactly 3 neighbors
if (neighbors === 3) {
toRegen.push(cell);
changed = true;
}
}
}
}
// Apply changes
for (var i = 0; i < toDie.length; i++) {
toDie[i].setAlive(false);
toDie[i].flash();
}
if (toDie.length > 0) {
LK.getSound('cellDie').play();
}
for (var i = 0; i < toRegen.length; i++) {
toRegen[i].setAlive(true);
toRegen[i].flash();
}
if (toRegen.length > 0) {
LK.getSound('cellBorn').play();
}
}
// Start/stop evolution
function startEvolve() {
if (isRunning) {
return;
}
isRunning = true;
instructions.setText("Running - Draw to modify");
evolveTimer = LK.setInterval(function () {
evolveGrid();
}, 200);
}
function stopEvolve() {
if (!isRunning) {
return;
}
isRunning = false;
instructions.setText("Conway's Game of Life\nDraw & Press ▶");
if (evolveTimer) {
LK.clearInterval(evolveTimer);
evolveTimer = null;
}
}
// Reset grid
function resetGrid() {
stopEvolve();
for (var y = 0; y < GRID_ROWS; y++) {
for (var x = 0; x < GRID_COLS; x++) {
cellNodes[y][x].setAlive(false);
}
}
}
// Step evolution once
function stepEvolve() {
if (isRunning) {
return;
}
evolveGrid();
}
// Draw GLAUD text pattern on grid
function drawGlaud() {
// Clear grid first
for (var y = 0; y < GRID_ROWS; y++) {
for (var x = 0; x < GRID_COLS; x++) {
cellNodes[y][x].setAlive(false);
}
}
// GLAUD pattern (3x5 letters with 1 space between) - smaller version
// Starting position to center the text
var startX = 3;
var startY = 10;
// G
var G = [[1, 1, 1], [1, 0, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1]];
// L
var L = [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]];
// A
var A = [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]];
// U
var U = [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]];
// D
var D = [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]];
var letters = [G, L, A, U, D];
var xOffset = startX;
// Draw each letter
for (var letterIdx = 0; letterIdx < letters.length; letterIdx++) {
var letter = letters[letterIdx];
for (var ly = 0; ly < letter.length; ly++) {
for (var lx = 0; lx < letter[ly].length; lx++) {
var cellX = xOffset + lx;
var cellY = startY + ly;
if (cellX < GRID_COLS && cellY < GRID_ROWS && letter[ly][lx] === 1) {
cellNodes[cellY][cellX].setAlive(true);
cellNodes[cellY][cellX].flash();
}
}
}
xOffset += 4; // Move to next letter position (3 width + 1 space)
}
}
// Find cell at game coordinates
function getCellAt(x, y) {
for (var row = 0; row < GRID_ROWS; row++) {
for (var col = 0; col < GRID_COLS; col++) {
var cell = cellNodes[row][col];
var left = cell.x - CELL_SIZE / 2;
var right = cell.x + CELL_SIZE / 2;
var top = cell.y - CELL_SIZE / 2;
var bottom = cell.y + CELL_SIZE / 2;
if (x >= left && x < right && y >= top && y < bottom) {
return cell;
}
}
}
return null;
}
// Handle drawing on grid
game.down = function (x, y, obj) {
var cell = getCellAt(x, y);
if (cell) {
isDrawing = true;
drawState = !cell.isAlive;
cell.setAlive(drawState);
cell.flash();
LK.getSound('draw').play();
}
};
game.move = function (x, y, obj) {
// Add hover effect even when not drawing
var cell = getCellAt(x, y);
if (cell && !isDrawing) {
// Subtle hover effect
tween(cell, {
alpha: 0.8
}, {
duration: 100
});
}
if (!isDrawing) {
return;
}
if (cell && cell.isAlive !== drawState) {
cell.setAlive(drawState);
cell.flash();
LK.getSound('draw').play();
}
};
game.up = function (x, y, obj) {
isDrawing = false;
};
// Play button events
playBtn.down = function (x, y, obj) {
if (isRunning) {
stopEvolve();
playBtn.setText("▶");
LK.getSound('evolveStop').play();
} else {
startEvolve();
playBtn.setText("⏸");
LK.getSound('evolveStart').play();
}
};
resetBtn.down = function (x, y, obj) {
resetGrid();
playBtn.setText("▶");
LK.getSound('buttonPress').play();
};
stepBtn.down = function (x, y, obj) {
stepEvolve();
LK.getSound('buttonPress').play();
};
// Prevent accidental grid drawing when using GUI
LK.gui.bottom.down = function (x, y, obj) {};
LK.gui.bottom.move = function (x, y, obj) {};
LK.gui.bottom.up = function (x, y, obj) {};
// Initialize with GLAUD pattern
drawGlaud();
// Play background music
LK.playMusic('bgMusic');
// No update loop needed for this game
game.update = function () {
// No-op
};