/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Palette button class
var PaletteButton = Container.expand(function () {
var self = Container.call(this);
self.colorId = null;
self.block = self.attachAsset('color_white', {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = paletteCellSize;
self.block.height = paletteCellSize;
self.setColor = function (colorId) {
self.colorId = colorId;
self.removeChild(self.block);
self.block = self.attachAsset(colorId, {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = paletteCellSize;
self.block.height = paletteCellSize;
};
// Touch event
self.down = function (x, y, obj) {
selectColor(self.colorId);
};
return self;
});
// Pixel cell class for the drawing grid
var PixelCell = Container.expand(function () {
var self = Container.call(this);
self.colorId = null; // Current color id (e.g. 'color_yellow')
self.gridX = 0;
self.gridY = 0;
// The colored block
self.block = self.attachAsset('color_white', {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
// Draws the cell with the given color id
self.setColor = function (colorId) {
self.colorId = colorId;
self.removeChild(self.block);
self.block = self.attachAsset(colorId, {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
};
// For checking if the cell is filled with the correct color
self.getColorId = function () {
return self.colorId;
};
// Touch event
self.down = function (x, y, obj) {
if (!selectedColorId) return;
// Find grid coordinates of this cell
var gx = self.gridX;
var gy = self.gridY;
if (fillMode) {
// --- FILL TOOL ---
var targetColor = self.getColorId();
if (targetColor === selectedColorId) return; // Already filled
// Flood fill algorithm (non-recursive, stack-based)
var stack = [];
stack.push([gx, gy]);
var visited = {};
while (stack.length > 0) {
var pos = stack.pop();
var px = pos[0];
var py = pos[1];
var key = px + ',' + py;
if (visited[key]) continue;
visited[key] = true;
if (px >= 0 && px < gridCols && py >= 0 && py < gridRows && gridCells[py][px].getColorId() === targetColor) {
gridCells[py][px].setColor(selectedColorId);
// Add neighbors
stack.push([px - 1, py]);
stack.push([px + 1, py]);
stack.push([px, py - 1]);
stack.push([px, py + 1]);
}
}
checkIfComplete();
return;
}
// --- BRUSH TOOL ---
var size = brushSize;
for (var dy = 0; dy < size; dy++) {
for (var dx = 0; dx < size; dx++) {
var px = gx + dx;
var py = gy + dy;
if (px < gridCols && py < gridRows) {
gridCells[py][px].setColor(selectedColorId);
}
}
}
checkIfComplete();
};
return self;
});
// Reference cell class (non-interactive, just for showing the reference)
var ReferenceCell = Container.expand(function () {
var self = Container.call(this);
self.block = self.attachAsset('color_white', {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
self.setColor = function (colorId) {
self.removeChild(self.block);
self.block = self.attachAsset(colorId, {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xE0E0E0
});
/****
* Game Code
****/
// This block is moved to ensure correct data initialization.
// --- CONFIGURATION ---
// Define color palette for SpongeBob pixel art (approximate colors)
// Reference image: We'll use a grid of colored blocks as a reference (not an actual image asset, but a grid rendered in-game).
var gridCols = 12;
var gridRows = 16;
var cellSize = 90; // px, for main grid
var paletteCellSize = 80; // px, for palette
// Center the grid
var gridStartX = Math.floor((2048 - gridCols * cellSize) / 2);
var gridStartY = 350;
// Reference grid (smaller, at top)
var refCellSize = 40;
var refGridStartX = Math.floor((2048 - gridCols * refCellSize) / 2);
var refGridStartY = 120;
// Palette bar
var paletteStartY = 2732 - 220;
// Color palette (order matters for palette bar)
var colorPalette = ['color_yellow', 'color_white', 'color_black', 'color_brown', 'color_blue', 'color_red', 'color_pink', 'color_green'];
// Map colorId to color name for display
var colorNames = {
'color_yellow': 'Yellow',
'color_white': 'White',
'color_black': 'Black',
'color_brown': 'Brown',
'color_blue': 'Blue',
'color_red': 'Red',
'color_pink': 'Pink',
'color_green': 'Green'
};
// The reference pixel art for SpongeBob (12x16 grid, using colorPalette indices)
// 0: yellow, 1: white, 2: black, 3: brown, 4: blue, 5: red, 6: pink, 7: green
// Improved SpongeBob reference pixel art (12x16 grid)
// 0: yellow, 1: white, 2: black, 3: brown, 4: blue, 5: red, 6: pink, 7: green
var spongebobReference = [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2], [2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2], [2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2], [2, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 2], [2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2], [2, 0, 4, 4, 1, 1, 1, 1, 4, 4, 0, 2], [2, 0, 4, 4, 1, 1, 1, 1, 4, 4, 0, 2], [2, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 2], [2, 0, 0, 7, 7, 0, 0, 7, 7, 0, 0, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]];
// Convert indices to colorIds for easier comparison
function getColorIdByIndex(idx) {
return colorPalette[idx];
}
var spongebobReferenceColorIds = [];
for (var y = 0; y < gridRows; y++) {
var row = [];
for (var x = 0; x < gridCols; x++) {
row.push(getColorIdByIndex(spongebobReference[y][x]));
}
spongebobReferenceColorIds.push(row);
}
// spongebobReferenceColorIds array creation moved after spongebobReference definition is finalized.
// --- STATE ---
var gridCells = []; // 2D array of PixelCell
var selectedColorId = colorPalette[0]; // Default selected color
var paletteButtons = [];
var isComplete = false;
// --- UI ---
// Title
var titleText = new Text2('SpongeBob Pixel Art', {
size: 90,
fill: 0x222222
});
titleText.anchor.set(0.5, 0);
LK.gui.top.addChild(titleText);
// Instructions
var instrText = new Text2('Tap a color, then tap the grid to fill. Try to match the reference above!', {
size: 48,
fill: 0x444444
});
instrText.anchor.set(0.5, 0);
LK.gui.top.addChild(instrText);
instrText.y = 110;
// --- REFERENCE GRID ---
var referenceCells = [];
for (var y = 0; y < gridRows; y++) {
var row = [];
for (var x = 0; x < gridCols; x++) {
var refCell = new ReferenceCell();
refCell.setColor(spongebobReferenceColorIds[y][x]);
refCell.x = refGridStartX + x * refCellSize + refCellSize / 2;
refCell.y = refGridStartY + y * refCellSize + refCellSize / 2;
game.addChild(refCell);
row.push(refCell);
}
referenceCells.push(row);
}
// --- MAIN DRAWING GRID ---
for (var y = 0; y < gridRows; y++) {
var row = [];
for (var x = 0; x < gridCols; x++) {
var cell = new PixelCell();
cell.x = gridStartX + x * cellSize + cellSize / 2;
cell.y = gridStartY + y * cellSize + cellSize / 2;
cell.gridX = x;
cell.gridY = y;
cell.setColor('color_white');
game.addChild(cell);
row.push(cell);
}
gridCells.push(row);
}
// --- PALETTE BAR ---
var paletteBarWidth = colorPalette.length * (paletteCellSize + 24) - 24;
var paletteBarStartX = Math.floor((2048 - paletteBarWidth) / 2);
for (var i = 0; i < colorPalette.length; i++) {
var colorId = colorPalette[i];
var btn = new PaletteButton();
btn.setColor(colorId);
btn.x = paletteBarStartX + i * (paletteCellSize + 24) + paletteCellSize / 2;
btn.y = paletteStartY + paletteCellSize / 2;
game.addChild(btn);
paletteButtons.push(btn);
}
// --- BRUSH SIZE & FILL TOOL UI ---
// Place these tools vertically on the right side of the screen, above the palette bar
var toolButtonSize = 100;
var toolButtonMargin = 32;
var toolStartX = 2048 - toolButtonSize - 40;
var toolStartY = paletteStartY - (toolButtonSize + toolButtonMargin) * 2;
// Brush size state: 1 or 2 (for 1x1 or 2x2)
var brushSize = 1;
var fillMode = false;
// Brush 1x1 button
var brush1Btn = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
brush1Btn.width = toolButtonSize;
brush1Btn.height = toolButtonSize;
brush1Btn.alpha = 0.18;
brush1Btn.x = toolStartX + toolButtonSize / 2;
brush1Btn.y = toolStartY + toolButtonSize / 2;
game.addChild(brush1Btn);
var brush1Icon = new Text2('1x1', {
size: 44,
fill: 0x222222
});
brush1Icon.anchor.set(0.5, 0.5);
brush1Icon.x = brush1Btn.x;
brush1Icon.y = brush1Btn.y;
game.addChild(brush1Icon);
// Brush 2x2 button
var brush2Btn = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
brush2Btn.width = toolButtonSize;
brush2Btn.height = toolButtonSize;
brush2Btn.alpha = 0.18;
brush2Btn.x = toolStartX + toolButtonSize / 2;
brush2Btn.y = toolStartY + toolButtonSize * 1.5 + toolButtonMargin;
game.addChild(brush2Btn);
var brush2Icon = new Text2('2x2', {
size: 44,
fill: 0x222222
});
brush2Icon.anchor.set(0.5, 0.5);
brush2Icon.x = brush2Btn.x;
brush2Icon.y = brush2Btn.y;
game.addChild(brush2Icon);
// Fill tool button
var fillBtn = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
fillBtn.width = toolButtonSize;
fillBtn.height = toolButtonSize;
fillBtn.alpha = 0.18;
fillBtn.x = toolStartX + toolButtonSize / 2;
fillBtn.y = toolStartY + toolButtonSize * 2.5 + toolButtonMargin * 2;
game.addChild(fillBtn);
var fillIcon = new Text2('Fill', {
size: 44,
fill: 0x222222
});
fillIcon.anchor.set(0.5, 0.5);
fillIcon.x = fillBtn.x;
fillIcon.y = fillBtn.y;
game.addChild(fillIcon);
// Tool selection indicator
var toolIndicator = LK.getAsset('color_blue', {
anchorX: 0.5,
anchorY: 0.5
});
toolIndicator.width = toolButtonSize + 16;
toolIndicator.height = toolButtonSize + 16;
toolIndicator.alpha = 0.22;
game.addChild(toolIndicator);
// Set initial tool indicator position
function updateToolIndicator() {
if (fillMode) {
toolIndicator.x = fillBtn.x;
toolIndicator.y = fillBtn.y;
} else if (brushSize === 2) {
toolIndicator.x = brush2Btn.x;
toolIndicator.y = brush2Btn.y;
} else {
toolIndicator.x = brush1Btn.x;
toolIndicator.y = brush1Btn.y;
}
}
updateToolIndicator();
// Tool button events
brush1Btn.down = function () {
brushSize = 1;
fillMode = false;
updateToolIndicator();
};
brush2Btn.down = function () {
brushSize = 2;
fillMode = false;
updateToolIndicator();
};
fillBtn.down = function () {
fillMode = true;
updateToolIndicator();
};
// --- PALETTE SELECTION INDICATOR ---
var paletteIndicator = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
paletteIndicator.width = paletteCellSize + 16;
paletteIndicator.height = paletteCellSize + 16;
paletteIndicator.alpha = 0.25;
game.addChild(paletteIndicator);
// --- MINI SPONGEBOB REFERENCE AT BOTTOM ---
// Use the SpongeBobReference image asset at the bottom center as a reference
// Set the mini reference image to be a square aspect ratio
var miniRefImageSize = 384; // Make it a square, same as previous height
var miniRefGridMarginAbovePalette = 40; // Margin between top of palette and bottom of mini-grid
var miniRefImageBottomY = paletteStartY - miniRefGridMarginAbovePalette;
var miniRefImageStartX = Math.floor((2048 - miniRefImageSize) / 2);
var miniRefImageStartY = miniRefImageBottomY - miniRefImageSize;
// Add the reference image asset as a square
var miniRefImage = LK.getAsset('SpongeBobReference', {
anchorX: 0,
anchorY: 0,
x: miniRefImageStartX,
y: miniRefImageStartY,
width: miniRefImageSize,
height: miniRefImageSize,
alpha: 0.95
});
game.addChild(miniRefImage);
// --- PALETTE SELECTION LOGIC ---
// Play and loop the music asset named Music on first user interaction (to comply with browser autoplay policies)
var musicStarted = false;
function startMusicIfNeeded() {
if (!musicStarted) {
LK.playMusic('Music', {
loop: true
});
musicStarted = true;
}
}
// Listen for first interaction to start music
game.down = function (x, y, obj) {
startMusicIfNeeded();
// If a palette button or grid cell is pressed, their own .down will also be called
};
function selectColor(colorId) {
selectedColorId = colorId;
// Move indicator to selected button
for (var i = 0; i < paletteButtons.length; i++) {
if (paletteButtons[i].colorId === colorId) {
paletteIndicator.x = paletteButtons[i].x;
paletteIndicator.y = paletteButtons[i].y;
break;
}
}
}
selectColor(selectedColorId);
// --- COMPLETION CHECK ---
function checkIfComplete() {
if (isComplete) return;
for (var y = 0; y < gridRows; y++) {
for (var x = 0; x < gridCols; x++) {
if (gridCells[y][x].getColorId() !== spongebobReferenceColorIds[y][x]) {
return;
}
}
}
// All cells match!
isComplete = true;
showCompletion();
}
// --- COMPLETION UI ---
function showCompletion() {
// Flash green
LK.effects.flashScreen(0x7ED957, 800);
// Show "You did it!" message
var winText = new Text2('You did it!', {
size: 120,
fill: 0x7ED957
});
winText.anchor.set(0.5, 0.5);
winText.x = 2048 / 2;
winText.y = 2732 / 2 - 100;
game.addChild(winText);
var compareText = new Text2('Your SpongeBob matches the reference!', {
size: 60,
fill: 0x222222
});
compareText.anchor.set(0.5, 0.5);
compareText.x = 2048 / 2;
compareText.y = 2732 / 2 + 40;
game.addChild(compareText);
// Animate winText
tween(winText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(winText, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
// --- GAME UPDATE ---
game.update = function () {
// No per-frame logic needed for this game
};
// --- DRAG PREVENTION ---
// No drag logic needed; all interaction is tap/click
// --- GUI LAYOUT ---
// Position title and instructions
titleText.x = 2048 / 2;
titleText.y = 20;
instrText.x = 2048 / 2;
instrText.y = 120;
// --- END OF GAME CODE --- /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Palette button class
var PaletteButton = Container.expand(function () {
var self = Container.call(this);
self.colorId = null;
self.block = self.attachAsset('color_white', {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = paletteCellSize;
self.block.height = paletteCellSize;
self.setColor = function (colorId) {
self.colorId = colorId;
self.removeChild(self.block);
self.block = self.attachAsset(colorId, {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = paletteCellSize;
self.block.height = paletteCellSize;
};
// Touch event
self.down = function (x, y, obj) {
selectColor(self.colorId);
};
return self;
});
// Pixel cell class for the drawing grid
var PixelCell = Container.expand(function () {
var self = Container.call(this);
self.colorId = null; // Current color id (e.g. 'color_yellow')
self.gridX = 0;
self.gridY = 0;
// The colored block
self.block = self.attachAsset('color_white', {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
// Draws the cell with the given color id
self.setColor = function (colorId) {
self.colorId = colorId;
self.removeChild(self.block);
self.block = self.attachAsset(colorId, {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
};
// For checking if the cell is filled with the correct color
self.getColorId = function () {
return self.colorId;
};
// Touch event
self.down = function (x, y, obj) {
if (!selectedColorId) return;
// Find grid coordinates of this cell
var gx = self.gridX;
var gy = self.gridY;
if (fillMode) {
// --- FILL TOOL ---
var targetColor = self.getColorId();
if (targetColor === selectedColorId) return; // Already filled
// Flood fill algorithm (non-recursive, stack-based)
var stack = [];
stack.push([gx, gy]);
var visited = {};
while (stack.length > 0) {
var pos = stack.pop();
var px = pos[0];
var py = pos[1];
var key = px + ',' + py;
if (visited[key]) continue;
visited[key] = true;
if (px >= 0 && px < gridCols && py >= 0 && py < gridRows && gridCells[py][px].getColorId() === targetColor) {
gridCells[py][px].setColor(selectedColorId);
// Add neighbors
stack.push([px - 1, py]);
stack.push([px + 1, py]);
stack.push([px, py - 1]);
stack.push([px, py + 1]);
}
}
checkIfComplete();
return;
}
// --- BRUSH TOOL ---
var size = brushSize;
for (var dy = 0; dy < size; dy++) {
for (var dx = 0; dx < size; dx++) {
var px = gx + dx;
var py = gy + dy;
if (px < gridCols && py < gridRows) {
gridCells[py][px].setColor(selectedColorId);
}
}
}
checkIfComplete();
};
return self;
});
// Reference cell class (non-interactive, just for showing the reference)
var ReferenceCell = Container.expand(function () {
var self = Container.call(this);
self.block = self.attachAsset('color_white', {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
self.setColor = function (colorId) {
self.removeChild(self.block);
self.block = self.attachAsset(colorId, {
anchorX: 0.5,
anchorY: 0.5
});
self.block.width = cellSize;
self.block.height = cellSize;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xE0E0E0
});
/****
* Game Code
****/
// This block is moved to ensure correct data initialization.
// --- CONFIGURATION ---
// Define color palette for SpongeBob pixel art (approximate colors)
// Reference image: We'll use a grid of colored blocks as a reference (not an actual image asset, but a grid rendered in-game).
var gridCols = 12;
var gridRows = 16;
var cellSize = 90; // px, for main grid
var paletteCellSize = 80; // px, for palette
// Center the grid
var gridStartX = Math.floor((2048 - gridCols * cellSize) / 2);
var gridStartY = 350;
// Reference grid (smaller, at top)
var refCellSize = 40;
var refGridStartX = Math.floor((2048 - gridCols * refCellSize) / 2);
var refGridStartY = 120;
// Palette bar
var paletteStartY = 2732 - 220;
// Color palette (order matters for palette bar)
var colorPalette = ['color_yellow', 'color_white', 'color_black', 'color_brown', 'color_blue', 'color_red', 'color_pink', 'color_green'];
// Map colorId to color name for display
var colorNames = {
'color_yellow': 'Yellow',
'color_white': 'White',
'color_black': 'Black',
'color_brown': 'Brown',
'color_blue': 'Blue',
'color_red': 'Red',
'color_pink': 'Pink',
'color_green': 'Green'
};
// The reference pixel art for SpongeBob (12x16 grid, using colorPalette indices)
// 0: yellow, 1: white, 2: black, 3: brown, 4: blue, 5: red, 6: pink, 7: green
// Improved SpongeBob reference pixel art (12x16 grid)
// 0: yellow, 1: white, 2: black, 3: brown, 4: blue, 5: red, 6: pink, 7: green
var spongebobReference = [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2], [2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], [2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2], [2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2], [2, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 2], [2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2], [2, 0, 4, 4, 1, 1, 1, 1, 4, 4, 0, 2], [2, 0, 4, 4, 1, 1, 1, 1, 4, 4, 0, 2], [2, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 2], [2, 0, 0, 7, 7, 0, 0, 7, 7, 0, 0, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]];
// Convert indices to colorIds for easier comparison
function getColorIdByIndex(idx) {
return colorPalette[idx];
}
var spongebobReferenceColorIds = [];
for (var y = 0; y < gridRows; y++) {
var row = [];
for (var x = 0; x < gridCols; x++) {
row.push(getColorIdByIndex(spongebobReference[y][x]));
}
spongebobReferenceColorIds.push(row);
}
// spongebobReferenceColorIds array creation moved after spongebobReference definition is finalized.
// --- STATE ---
var gridCells = []; // 2D array of PixelCell
var selectedColorId = colorPalette[0]; // Default selected color
var paletteButtons = [];
var isComplete = false;
// --- UI ---
// Title
var titleText = new Text2('SpongeBob Pixel Art', {
size: 90,
fill: 0x222222
});
titleText.anchor.set(0.5, 0);
LK.gui.top.addChild(titleText);
// Instructions
var instrText = new Text2('Tap a color, then tap the grid to fill. Try to match the reference above!', {
size: 48,
fill: 0x444444
});
instrText.anchor.set(0.5, 0);
LK.gui.top.addChild(instrText);
instrText.y = 110;
// --- REFERENCE GRID ---
var referenceCells = [];
for (var y = 0; y < gridRows; y++) {
var row = [];
for (var x = 0; x < gridCols; x++) {
var refCell = new ReferenceCell();
refCell.setColor(spongebobReferenceColorIds[y][x]);
refCell.x = refGridStartX + x * refCellSize + refCellSize / 2;
refCell.y = refGridStartY + y * refCellSize + refCellSize / 2;
game.addChild(refCell);
row.push(refCell);
}
referenceCells.push(row);
}
// --- MAIN DRAWING GRID ---
for (var y = 0; y < gridRows; y++) {
var row = [];
for (var x = 0; x < gridCols; x++) {
var cell = new PixelCell();
cell.x = gridStartX + x * cellSize + cellSize / 2;
cell.y = gridStartY + y * cellSize + cellSize / 2;
cell.gridX = x;
cell.gridY = y;
cell.setColor('color_white');
game.addChild(cell);
row.push(cell);
}
gridCells.push(row);
}
// --- PALETTE BAR ---
var paletteBarWidth = colorPalette.length * (paletteCellSize + 24) - 24;
var paletteBarStartX = Math.floor((2048 - paletteBarWidth) / 2);
for (var i = 0; i < colorPalette.length; i++) {
var colorId = colorPalette[i];
var btn = new PaletteButton();
btn.setColor(colorId);
btn.x = paletteBarStartX + i * (paletteCellSize + 24) + paletteCellSize / 2;
btn.y = paletteStartY + paletteCellSize / 2;
game.addChild(btn);
paletteButtons.push(btn);
}
// --- BRUSH SIZE & FILL TOOL UI ---
// Place these tools vertically on the right side of the screen, above the palette bar
var toolButtonSize = 100;
var toolButtonMargin = 32;
var toolStartX = 2048 - toolButtonSize - 40;
var toolStartY = paletteStartY - (toolButtonSize + toolButtonMargin) * 2;
// Brush size state: 1 or 2 (for 1x1 or 2x2)
var brushSize = 1;
var fillMode = false;
// Brush 1x1 button
var brush1Btn = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
brush1Btn.width = toolButtonSize;
brush1Btn.height = toolButtonSize;
brush1Btn.alpha = 0.18;
brush1Btn.x = toolStartX + toolButtonSize / 2;
brush1Btn.y = toolStartY + toolButtonSize / 2;
game.addChild(brush1Btn);
var brush1Icon = new Text2('1x1', {
size: 44,
fill: 0x222222
});
brush1Icon.anchor.set(0.5, 0.5);
brush1Icon.x = brush1Btn.x;
brush1Icon.y = brush1Btn.y;
game.addChild(brush1Icon);
// Brush 2x2 button
var brush2Btn = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
brush2Btn.width = toolButtonSize;
brush2Btn.height = toolButtonSize;
brush2Btn.alpha = 0.18;
brush2Btn.x = toolStartX + toolButtonSize / 2;
brush2Btn.y = toolStartY + toolButtonSize * 1.5 + toolButtonMargin;
game.addChild(brush2Btn);
var brush2Icon = new Text2('2x2', {
size: 44,
fill: 0x222222
});
brush2Icon.anchor.set(0.5, 0.5);
brush2Icon.x = brush2Btn.x;
brush2Icon.y = brush2Btn.y;
game.addChild(brush2Icon);
// Fill tool button
var fillBtn = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
fillBtn.width = toolButtonSize;
fillBtn.height = toolButtonSize;
fillBtn.alpha = 0.18;
fillBtn.x = toolStartX + toolButtonSize / 2;
fillBtn.y = toolStartY + toolButtonSize * 2.5 + toolButtonMargin * 2;
game.addChild(fillBtn);
var fillIcon = new Text2('Fill', {
size: 44,
fill: 0x222222
});
fillIcon.anchor.set(0.5, 0.5);
fillIcon.x = fillBtn.x;
fillIcon.y = fillBtn.y;
game.addChild(fillIcon);
// Tool selection indicator
var toolIndicator = LK.getAsset('color_blue', {
anchorX: 0.5,
anchorY: 0.5
});
toolIndicator.width = toolButtonSize + 16;
toolIndicator.height = toolButtonSize + 16;
toolIndicator.alpha = 0.22;
game.addChild(toolIndicator);
// Set initial tool indicator position
function updateToolIndicator() {
if (fillMode) {
toolIndicator.x = fillBtn.x;
toolIndicator.y = fillBtn.y;
} else if (brushSize === 2) {
toolIndicator.x = brush2Btn.x;
toolIndicator.y = brush2Btn.y;
} else {
toolIndicator.x = brush1Btn.x;
toolIndicator.y = brush1Btn.y;
}
}
updateToolIndicator();
// Tool button events
brush1Btn.down = function () {
brushSize = 1;
fillMode = false;
updateToolIndicator();
};
brush2Btn.down = function () {
brushSize = 2;
fillMode = false;
updateToolIndicator();
};
fillBtn.down = function () {
fillMode = true;
updateToolIndicator();
};
// --- PALETTE SELECTION INDICATOR ---
var paletteIndicator = LK.getAsset('color_black', {
anchorX: 0.5,
anchorY: 0.5
});
paletteIndicator.width = paletteCellSize + 16;
paletteIndicator.height = paletteCellSize + 16;
paletteIndicator.alpha = 0.25;
game.addChild(paletteIndicator);
// --- MINI SPONGEBOB REFERENCE AT BOTTOM ---
// Use the SpongeBobReference image asset at the bottom center as a reference
// Set the mini reference image to be a square aspect ratio
var miniRefImageSize = 384; // Make it a square, same as previous height
var miniRefGridMarginAbovePalette = 40; // Margin between top of palette and bottom of mini-grid
var miniRefImageBottomY = paletteStartY - miniRefGridMarginAbovePalette;
var miniRefImageStartX = Math.floor((2048 - miniRefImageSize) / 2);
var miniRefImageStartY = miniRefImageBottomY - miniRefImageSize;
// Add the reference image asset as a square
var miniRefImage = LK.getAsset('SpongeBobReference', {
anchorX: 0,
anchorY: 0,
x: miniRefImageStartX,
y: miniRefImageStartY,
width: miniRefImageSize,
height: miniRefImageSize,
alpha: 0.95
});
game.addChild(miniRefImage);
// --- PALETTE SELECTION LOGIC ---
// Play and loop the music asset named Music on first user interaction (to comply with browser autoplay policies)
var musicStarted = false;
function startMusicIfNeeded() {
if (!musicStarted) {
LK.playMusic('Music', {
loop: true
});
musicStarted = true;
}
}
// Listen for first interaction to start music
game.down = function (x, y, obj) {
startMusicIfNeeded();
// If a palette button or grid cell is pressed, their own .down will also be called
};
function selectColor(colorId) {
selectedColorId = colorId;
// Move indicator to selected button
for (var i = 0; i < paletteButtons.length; i++) {
if (paletteButtons[i].colorId === colorId) {
paletteIndicator.x = paletteButtons[i].x;
paletteIndicator.y = paletteButtons[i].y;
break;
}
}
}
selectColor(selectedColorId);
// --- COMPLETION CHECK ---
function checkIfComplete() {
if (isComplete) return;
for (var y = 0; y < gridRows; y++) {
for (var x = 0; x < gridCols; x++) {
if (gridCells[y][x].getColorId() !== spongebobReferenceColorIds[y][x]) {
return;
}
}
}
// All cells match!
isComplete = true;
showCompletion();
}
// --- COMPLETION UI ---
function showCompletion() {
// Flash green
LK.effects.flashScreen(0x7ED957, 800);
// Show "You did it!" message
var winText = new Text2('You did it!', {
size: 120,
fill: 0x7ED957
});
winText.anchor.set(0.5, 0.5);
winText.x = 2048 / 2;
winText.y = 2732 / 2 - 100;
game.addChild(winText);
var compareText = new Text2('Your SpongeBob matches the reference!', {
size: 60,
fill: 0x222222
});
compareText.anchor.set(0.5, 0.5);
compareText.x = 2048 / 2;
compareText.y = 2732 / 2 + 40;
game.addChild(compareText);
// Animate winText
tween(winText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(winText, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
// --- GAME UPDATE ---
game.update = function () {
// No per-frame logic needed for this game
};
// --- DRAG PREVENTION ---
// No drag logic needed; all interaction is tap/click
// --- GUI LAYOUT ---
// Position title and instructions
titleText.x = 2048 / 2;
titleText.y = 20;
instrText.x = 2048 / 2;
instrText.y = 120;
// --- END OF GAME CODE ---