/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var LevelButton = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('level_button', { anchorX: 0.5, anchorY: 0.5 }); self.levelNumber = 1; self.unlocked = false; var levelText = new Text2('1', { size: 40, fill: 0x000000 }); levelText.anchor.set(0.5, 0.5); self.addChild(levelText); self.setLevel = function (level) { self.levelNumber = level; levelText.setText(level.toString()); self.unlocked = level <= unlockedLevel; graphics.tint = self.unlocked ? 0x90EE90 : 0x808080; }; self.down = function (x, y, obj) { if (self.unlocked) { startLevel(self.levelNumber); } }; return self; }); var PuzzlePiece = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('puzzle_piece', { anchorX: 0.5, anchorY: 0.5 }); self.originalX = 0; self.originalY = 0; self.targetX = 0; self.targetY = 0; self.pieceId = 0; self.isPlaced = false; self.isDragging = false; self.setColor = function (color) { graphics.tint = color; }; self.down = function (x, y, obj) { if (!self.isPlaced) { self.isDragging = true; self.originalX = self.x; self.originalY = self.y; LK.getSound('move').play(); } }; self.up = function (x, y, obj) { if (self.isDragging) { self.isDragging = false; self.checkPlacement(); } }; self.checkPlacement = function () { var targetSlot = findNearestSlot(self.x, self.y); if (targetSlot && !targetSlot.occupied && getDistance(self.x, self.y, targetSlot.x, targetSlot.y) < 80) { self.snapToSlot(targetSlot); } else { self.returnToOriginal(); } }; self.snapToSlot = function (slot) { tween(self, { x: slot.x, y: slot.y }, { duration: 300, easing: tween.easeOut }); self.isPlaced = true; slot.occupied = true; slot.pieceId = self.pieceId; LK.getSound('success').play(); checkLevelComplete(); }; self.returnToOriginal = function () { tween(self, { x: self.originalX, y: self.originalY }, { duration: 300, easing: tween.easeOut }); }; return self; }); var TargetSlot = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('target_slot', { anchorX: 0.5, anchorY: 0.5 }); self.slotId = 0; self.occupied = false; self.pieceId = -1; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xF5F5DC }); /**** * Game Code ****/ var gameState = 'menu'; // 'menu', 'playing', 'complete' var currentLevel = 1; var unlockedLevel = storage.unlockedLevel || 1; var puzzlePieces = []; var targetSlots = []; var levelButtons = []; var hintButton; var backButton; var levelCompleteText; var gameTimer = 60; // 60 seconds var timerText; var timerInterval; // Level definitions var levelConfigs = [{ pieces: 3, colors: [0xFF69B4, 0x87CEEB, 0x98FB98], pattern: 'simple' }, { pieces: 4, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700], pattern: 'simple' }, { pieces: 4, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700], pattern: 'cross' }, { pieces: 5, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347], pattern: 'simple' }, { pieces: 6, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB], pattern: 'grid' }, { pieces: 6, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB], pattern: 'circle' }, { pieces: 8, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1], pattern: 'grid' }, { pieces: 9, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1, 0xFFA500], pattern: 'grid' }, { pieces: 10, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1, 0xFFA500, 0x32CD32], pattern: 'complex' }, { pieces: 12, colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1, 0xFFA500, 0x32CD32, 0xFF4500, 0x8A2BE2], pattern: 'complex' }]; // Create title var titleText = new Text2('Labubu Puzzle Adventure', { size: 80, fill: 0xFF69B4 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 300; // Create Labubu mascot var labubuMascot = LK.getAsset('labubu', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 500, scaleX: 1.5, scaleY: 1.5 }); game.addChild(labubuMascot); function createMenu() { gameState = 'menu'; game.addChild(titleText); // Create level selection grid var startY = 800; var cols = 5; var spacing = 200; for (var i = 0; i < 10; i++) { var button = new LevelButton(); var row = Math.floor(i / cols); var col = i % cols; button.x = 400 + col * spacing; button.y = startY + row * 150; button.setLevel(i + 1); levelButtons.push(button); game.addChild(button); } } function startLevel(levelNum) { clearMenu(); currentLevel = levelNum; gameState = 'playing'; createLevel(levelNum); } function clearMenu() { game.removeChild(titleText); for (var i = 0; i < levelButtons.length; i++) { game.removeChild(levelButtons[i]); } levelButtons = []; } function createLevel(levelNum) { var config = levelConfigs[levelNum - 1]; // Create background board var board = LK.getAsset('board_bg', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); game.addChild(board); // Create level title var levelTitle = new Text2('Level ' + levelNum, { size: 60, fill: 0x333333 }); levelTitle.anchor.set(0.5, 0.5); levelTitle.x = 1024; levelTitle.y = 200; game.addChild(levelTitle); // Create back button backButton = LK.getAsset('level_button', { anchorX: 0.5, anchorY: 0.5, x: 150, y: 150, scaleX: 0.8, scaleY: 0.8 }); var backText = new Text2('Back', { size: 30, fill: 0x000000 }); backText.anchor.set(0.5, 0.5); backText.x = 150; backText.y = 150; game.addChild(backButton); game.addChild(backText); // Create hint button hintButton = LK.getAsset('hint_button', { anchorX: 0.5, anchorY: 0.5, x: 1900, y: 150 }); var hintText = new Text2('Hint', { size: 25, fill: 0x000000 }); hintText.anchor.set(0.5, 0.5); hintText.x = 1900; hintText.y = 150; game.addChild(hintButton); game.addChild(hintText); // Create instruction text at bottom of screen var instructionText = new Text2('Drag the puzzle pieces to the white puzzle pieces', { size: 90, fill: 0x333333 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 2500; game.addChild(instructionText); // Create timer text timerText = new Text2('Time: 60', { size: 60, fill: 0xFF0000 }); timerText.anchor.set(0.5, 0.5); timerText.x = 1024; timerText.y = 300; game.addChild(timerText); // Reset and start timer gameTimer = 60; if (timerInterval) { LK.clearInterval(timerInterval); } timerInterval = LK.setInterval(function () { gameTimer--; timerText.setText('Time: ' + gameTimer); if (gameTimer <= 0) { LK.clearInterval(timerInterval); LK.showGameOver(); } }, 1000); createPuzzleLayout(config); } function createPuzzleLayout(config) { var pieces = config.pieces; var colors = config.colors; var pattern = config.pattern; // Create target slots based on pattern createTargetSlots(pieces, pattern); // Create puzzle pieces createPuzzlePieces(pieces, colors); } function createTargetSlots(numSlots, pattern) { targetSlots = []; var centerX = 1024; var centerY = 1000; if (pattern === 'simple') { var spacing = 120; var startX = centerX - (numSlots - 1) * spacing / 2; for (var i = 0; i < numSlots; i++) { var slot = new TargetSlot(); slot.x = startX + i * spacing; slot.y = centerY; slot.slotId = i; targetSlots.push(slot); game.addChild(slot); } } else if (pattern === 'cross') { var positions = [{ x: centerX, y: centerY - 120 }, { x: centerX - 120, y: centerY }, { x: centerX, y: centerY }, { x: centerX + 120, y: centerY }, { x: centerX, y: centerY + 120 }]; for (var i = 0; i < Math.min(numSlots, positions.length); i++) { var slot = new TargetSlot(); slot.x = positions[i].x; slot.y = positions[i].y; slot.slotId = i; targetSlots.push(slot); game.addChild(slot); } } else if (pattern === 'grid') { var cols = Math.ceil(Math.sqrt(numSlots)); var rows = Math.ceil(numSlots / cols); var spacing = 120; var startX = centerX - (cols - 1) * spacing / 2; var startY = centerY - (rows - 1) * spacing / 2; for (var i = 0; i < numSlots; i++) { var row = Math.floor(i / cols); var col = i % cols; var slot = new TargetSlot(); slot.x = startX + col * spacing; slot.y = startY + row * spacing; slot.slotId = i; targetSlots.push(slot); game.addChild(slot); } } else if (pattern === 'circle') { var radius = 150; var angleStep = 2 * Math.PI / numSlots; for (var i = 0; i < numSlots; i++) { var angle = i * angleStep; var slot = new TargetSlot(); slot.x = centerX + Math.cos(angle) * radius; slot.y = centerY + Math.sin(angle) * radius; slot.slotId = i; targetSlots.push(slot); game.addChild(slot); } } else if (pattern === 'complex') { // Custom complex patterns for higher levels var positions = generateComplexPattern(numSlots, centerX, centerY); for (var i = 0; i < numSlots; i++) { var slot = new TargetSlot(); slot.x = positions[i].x; slot.y = positions[i].y; slot.slotId = i; targetSlots.push(slot); game.addChild(slot); } } } function generateComplexPattern(numSlots, centerX, centerY) { var positions = []; var spacing = 100; // Create a spiral pattern var angle = 0; var radius = 50; for (var i = 0; i < numSlots; i++) { positions.push({ x: centerX + Math.cos(angle) * radius, y: centerY + Math.sin(angle) * radius }); angle += Math.PI / 3; radius += 15; } return positions; } function createPuzzlePieces(numPieces, colors) { puzzlePieces = []; var startY = 1600; var spacing = 120; var startX = 1024 - (numPieces - 1) * spacing / 2; // Shuffle colors for random placement var shuffledColors = colors.slice(); for (var i = shuffledColors.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = shuffledColors[i]; shuffledColors[i] = shuffledColors[j]; shuffledColors[j] = temp; } for (var i = 0; i < numPieces; i++) { var piece = new PuzzlePiece(); piece.x = startX + i * spacing; piece.y = startY; piece.pieceId = i; piece.setColor(shuffledColors[i % shuffledColors.length]); piece.originalX = piece.x; piece.originalY = piece.y; puzzlePieces.push(piece); game.addChild(piece); } } function findNearestSlot(x, y) { var nearest = null; var minDistance = Infinity; for (var i = 0; i < targetSlots.length; i++) { var slot = targetSlots[i]; var distance = getDistance(x, y, slot.x, slot.y); if (distance < minDistance) { minDistance = distance; nearest = slot; } } return nearest; } function getDistance(x1, y1, x2, y2) { var dx = x2 - x1; var dy = y2 - y1; return Math.sqrt(dx * dx + dy * dy); } function checkLevelComplete() { var placedPieces = 0; for (var i = 0; i < puzzlePieces.length; i++) { if (puzzlePieces[i].isPlaced) { placedPieces++; } } if (placedPieces === puzzlePieces.length) { LK.getSound('complete').play(); completeLevel(); } } function completeLevel() { gameState = 'complete'; // Clear timer if (timerInterval) { LK.clearInterval(timerInterval); timerInterval = null; } // Update unlocked level if (currentLevel >= unlockedLevel) { unlockedLevel = currentLevel + 1; storage.unlockedLevel = unlockedLevel; } // Show completion message levelCompleteText = new Text2('Level Complete!', { size: 80, fill: 0x00FF00 }); levelCompleteText.anchor.set(0.5, 0.5); levelCompleteText.x = 1024; levelCompleteText.y = 600; game.addChild(levelCompleteText); // Flash effect LK.effects.flashScreen(0x00FF00, 1000); // Auto return to menu after delay LK.setTimeout(function () { returnToMenu(); }, 3000); } function returnToMenu() { // Clear timer if (timerInterval) { LK.clearInterval(timerInterval); timerInterval = null; } // Clear level elements for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child !== labubuMascot) { game.removeChild(child); } } puzzlePieces = []; targetSlots = []; createMenu(); } function showHint() { if (gameState === 'playing') { // Flash target slots to give hint for (var i = 0; i < targetSlots.length; i++) { LK.effects.flashObject(targetSlots[i], 0xFFD700, 1000); } } } var draggedPiece = null; game.move = function (x, y, obj) { if (draggedPiece && draggedPiece.isDragging) { draggedPiece.x = x; draggedPiece.y = y; } }; game.down = function (x, y, obj) { if (gameState === 'playing') { // Check if clicked on back button if (getDistance(x, y, 150, 150) < 60) { returnToMenu(); return; } // Check if clicked on hint button if (getDistance(x, y, 1900, 150) < 50) { showHint(); return; } // Find clicked puzzle piece for (var i = puzzlePieces.length - 1; i >= 0; i--) { var piece = puzzlePieces[i]; if (!piece.isPlaced && getDistance(x, y, piece.x, piece.y) < 60) { draggedPiece = piece; piece.down(x, y, obj); break; } } } }; game.up = function (x, y, obj) { if (draggedPiece) { draggedPiece.up(x, y, obj); draggedPiece = null; } }; // Animate Labubu mascot game.update = function () { if (gameState === 'menu') { labubuMascot.y = 500 + Math.sin(LK.ticks * 0.05) * 10; labubuMascot.rotation = Math.sin(LK.ticks * 0.03) * 0.1; } }; // Initialize the game createMenu();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var LevelButton = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('level_button', {
anchorX: 0.5,
anchorY: 0.5
});
self.levelNumber = 1;
self.unlocked = false;
var levelText = new Text2('1', {
size: 40,
fill: 0x000000
});
levelText.anchor.set(0.5, 0.5);
self.addChild(levelText);
self.setLevel = function (level) {
self.levelNumber = level;
levelText.setText(level.toString());
self.unlocked = level <= unlockedLevel;
graphics.tint = self.unlocked ? 0x90EE90 : 0x808080;
};
self.down = function (x, y, obj) {
if (self.unlocked) {
startLevel(self.levelNumber);
}
};
return self;
});
var PuzzlePiece = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('puzzle_piece', {
anchorX: 0.5,
anchorY: 0.5
});
self.originalX = 0;
self.originalY = 0;
self.targetX = 0;
self.targetY = 0;
self.pieceId = 0;
self.isPlaced = false;
self.isDragging = false;
self.setColor = function (color) {
graphics.tint = color;
};
self.down = function (x, y, obj) {
if (!self.isPlaced) {
self.isDragging = true;
self.originalX = self.x;
self.originalY = self.y;
LK.getSound('move').play();
}
};
self.up = function (x, y, obj) {
if (self.isDragging) {
self.isDragging = false;
self.checkPlacement();
}
};
self.checkPlacement = function () {
var targetSlot = findNearestSlot(self.x, self.y);
if (targetSlot && !targetSlot.occupied && getDistance(self.x, self.y, targetSlot.x, targetSlot.y) < 80) {
self.snapToSlot(targetSlot);
} else {
self.returnToOriginal();
}
};
self.snapToSlot = function (slot) {
tween(self, {
x: slot.x,
y: slot.y
}, {
duration: 300,
easing: tween.easeOut
});
self.isPlaced = true;
slot.occupied = true;
slot.pieceId = self.pieceId;
LK.getSound('success').play();
checkLevelComplete();
};
self.returnToOriginal = function () {
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 300,
easing: tween.easeOut
});
};
return self;
});
var TargetSlot = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('target_slot', {
anchorX: 0.5,
anchorY: 0.5
});
self.slotId = 0;
self.occupied = false;
self.pieceId = -1;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF5F5DC
});
/****
* Game Code
****/
var gameState = 'menu'; // 'menu', 'playing', 'complete'
var currentLevel = 1;
var unlockedLevel = storage.unlockedLevel || 1;
var puzzlePieces = [];
var targetSlots = [];
var levelButtons = [];
var hintButton;
var backButton;
var levelCompleteText;
var gameTimer = 60; // 60 seconds
var timerText;
var timerInterval;
// Level definitions
var levelConfigs = [{
pieces: 3,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98],
pattern: 'simple'
}, {
pieces: 4,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700],
pattern: 'simple'
}, {
pieces: 4,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700],
pattern: 'cross'
}, {
pieces: 5,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347],
pattern: 'simple'
}, {
pieces: 6,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB],
pattern: 'grid'
}, {
pieces: 6,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB],
pattern: 'circle'
}, {
pieces: 8,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1],
pattern: 'grid'
}, {
pieces: 9,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1, 0xFFA500],
pattern: 'grid'
}, {
pieces: 10,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1, 0xFFA500, 0x32CD32],
pattern: 'complex'
}, {
pieces: 12,
colors: [0xFF69B4, 0x87CEEB, 0x98FB98, 0xFFD700, 0xFF6347, 0x9370DB, 0xFF1493, 0x00CED1, 0xFFA500, 0x32CD32, 0xFF4500, 0x8A2BE2],
pattern: 'complex'
}];
// Create title
var titleText = new Text2('Labubu Puzzle Adventure', {
size: 80,
fill: 0xFF69B4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 300;
// Create Labubu mascot
var labubuMascot = LK.getAsset('labubu', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 500,
scaleX: 1.5,
scaleY: 1.5
});
game.addChild(labubuMascot);
function createMenu() {
gameState = 'menu';
game.addChild(titleText);
// Create level selection grid
var startY = 800;
var cols = 5;
var spacing = 200;
for (var i = 0; i < 10; i++) {
var button = new LevelButton();
var row = Math.floor(i / cols);
var col = i % cols;
button.x = 400 + col * spacing;
button.y = startY + row * 150;
button.setLevel(i + 1);
levelButtons.push(button);
game.addChild(button);
}
}
function startLevel(levelNum) {
clearMenu();
currentLevel = levelNum;
gameState = 'playing';
createLevel(levelNum);
}
function clearMenu() {
game.removeChild(titleText);
for (var i = 0; i < levelButtons.length; i++) {
game.removeChild(levelButtons[i]);
}
levelButtons = [];
}
function createLevel(levelNum) {
var config = levelConfigs[levelNum - 1];
// Create background board
var board = LK.getAsset('board_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
game.addChild(board);
// Create level title
var levelTitle = new Text2('Level ' + levelNum, {
size: 60,
fill: 0x333333
});
levelTitle.anchor.set(0.5, 0.5);
levelTitle.x = 1024;
levelTitle.y = 200;
game.addChild(levelTitle);
// Create back button
backButton = LK.getAsset('level_button', {
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: 150,
scaleX: 0.8,
scaleY: 0.8
});
var backText = new Text2('Back', {
size: 30,
fill: 0x000000
});
backText.anchor.set(0.5, 0.5);
backText.x = 150;
backText.y = 150;
game.addChild(backButton);
game.addChild(backText);
// Create hint button
hintButton = LK.getAsset('hint_button', {
anchorX: 0.5,
anchorY: 0.5,
x: 1900,
y: 150
});
var hintText = new Text2('Hint', {
size: 25,
fill: 0x000000
});
hintText.anchor.set(0.5, 0.5);
hintText.x = 1900;
hintText.y = 150;
game.addChild(hintButton);
game.addChild(hintText);
// Create instruction text at bottom of screen
var instructionText = new Text2('Drag the puzzle pieces to the white puzzle pieces', {
size: 90,
fill: 0x333333
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 2500;
game.addChild(instructionText);
// Create timer text
timerText = new Text2('Time: 60', {
size: 60,
fill: 0xFF0000
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 1024;
timerText.y = 300;
game.addChild(timerText);
// Reset and start timer
gameTimer = 60;
if (timerInterval) {
LK.clearInterval(timerInterval);
}
timerInterval = LK.setInterval(function () {
gameTimer--;
timerText.setText('Time: ' + gameTimer);
if (gameTimer <= 0) {
LK.clearInterval(timerInterval);
LK.showGameOver();
}
}, 1000);
createPuzzleLayout(config);
}
function createPuzzleLayout(config) {
var pieces = config.pieces;
var colors = config.colors;
var pattern = config.pattern;
// Create target slots based on pattern
createTargetSlots(pieces, pattern);
// Create puzzle pieces
createPuzzlePieces(pieces, colors);
}
function createTargetSlots(numSlots, pattern) {
targetSlots = [];
var centerX = 1024;
var centerY = 1000;
if (pattern === 'simple') {
var spacing = 120;
var startX = centerX - (numSlots - 1) * spacing / 2;
for (var i = 0; i < numSlots; i++) {
var slot = new TargetSlot();
slot.x = startX + i * spacing;
slot.y = centerY;
slot.slotId = i;
targetSlots.push(slot);
game.addChild(slot);
}
} else if (pattern === 'cross') {
var positions = [{
x: centerX,
y: centerY - 120
}, {
x: centerX - 120,
y: centerY
}, {
x: centerX,
y: centerY
}, {
x: centerX + 120,
y: centerY
}, {
x: centerX,
y: centerY + 120
}];
for (var i = 0; i < Math.min(numSlots, positions.length); i++) {
var slot = new TargetSlot();
slot.x = positions[i].x;
slot.y = positions[i].y;
slot.slotId = i;
targetSlots.push(slot);
game.addChild(slot);
}
} else if (pattern === 'grid') {
var cols = Math.ceil(Math.sqrt(numSlots));
var rows = Math.ceil(numSlots / cols);
var spacing = 120;
var startX = centerX - (cols - 1) * spacing / 2;
var startY = centerY - (rows - 1) * spacing / 2;
for (var i = 0; i < numSlots; i++) {
var row = Math.floor(i / cols);
var col = i % cols;
var slot = new TargetSlot();
slot.x = startX + col * spacing;
slot.y = startY + row * spacing;
slot.slotId = i;
targetSlots.push(slot);
game.addChild(slot);
}
} else if (pattern === 'circle') {
var radius = 150;
var angleStep = 2 * Math.PI / numSlots;
for (var i = 0; i < numSlots; i++) {
var angle = i * angleStep;
var slot = new TargetSlot();
slot.x = centerX + Math.cos(angle) * radius;
slot.y = centerY + Math.sin(angle) * radius;
slot.slotId = i;
targetSlots.push(slot);
game.addChild(slot);
}
} else if (pattern === 'complex') {
// Custom complex patterns for higher levels
var positions = generateComplexPattern(numSlots, centerX, centerY);
for (var i = 0; i < numSlots; i++) {
var slot = new TargetSlot();
slot.x = positions[i].x;
slot.y = positions[i].y;
slot.slotId = i;
targetSlots.push(slot);
game.addChild(slot);
}
}
}
function generateComplexPattern(numSlots, centerX, centerY) {
var positions = [];
var spacing = 100;
// Create a spiral pattern
var angle = 0;
var radius = 50;
for (var i = 0; i < numSlots; i++) {
positions.push({
x: centerX + Math.cos(angle) * radius,
y: centerY + Math.sin(angle) * radius
});
angle += Math.PI / 3;
radius += 15;
}
return positions;
}
function createPuzzlePieces(numPieces, colors) {
puzzlePieces = [];
var startY = 1600;
var spacing = 120;
var startX = 1024 - (numPieces - 1) * spacing / 2;
// Shuffle colors for random placement
var shuffledColors = colors.slice();
for (var i = shuffledColors.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = shuffledColors[i];
shuffledColors[i] = shuffledColors[j];
shuffledColors[j] = temp;
}
for (var i = 0; i < numPieces; i++) {
var piece = new PuzzlePiece();
piece.x = startX + i * spacing;
piece.y = startY;
piece.pieceId = i;
piece.setColor(shuffledColors[i % shuffledColors.length]);
piece.originalX = piece.x;
piece.originalY = piece.y;
puzzlePieces.push(piece);
game.addChild(piece);
}
}
function findNearestSlot(x, y) {
var nearest = null;
var minDistance = Infinity;
for (var i = 0; i < targetSlots.length; i++) {
var slot = targetSlots[i];
var distance = getDistance(x, y, slot.x, slot.y);
if (distance < minDistance) {
minDistance = distance;
nearest = slot;
}
}
return nearest;
}
function getDistance(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
function checkLevelComplete() {
var placedPieces = 0;
for (var i = 0; i < puzzlePieces.length; i++) {
if (puzzlePieces[i].isPlaced) {
placedPieces++;
}
}
if (placedPieces === puzzlePieces.length) {
LK.getSound('complete').play();
completeLevel();
}
}
function completeLevel() {
gameState = 'complete';
// Clear timer
if (timerInterval) {
LK.clearInterval(timerInterval);
timerInterval = null;
}
// Update unlocked level
if (currentLevel >= unlockedLevel) {
unlockedLevel = currentLevel + 1;
storage.unlockedLevel = unlockedLevel;
}
// Show completion message
levelCompleteText = new Text2('Level Complete!', {
size: 80,
fill: 0x00FF00
});
levelCompleteText.anchor.set(0.5, 0.5);
levelCompleteText.x = 1024;
levelCompleteText.y = 600;
game.addChild(levelCompleteText);
// Flash effect
LK.effects.flashScreen(0x00FF00, 1000);
// Auto return to menu after delay
LK.setTimeout(function () {
returnToMenu();
}, 3000);
}
function returnToMenu() {
// Clear timer
if (timerInterval) {
LK.clearInterval(timerInterval);
timerInterval = null;
}
// Clear level elements
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child !== labubuMascot) {
game.removeChild(child);
}
}
puzzlePieces = [];
targetSlots = [];
createMenu();
}
function showHint() {
if (gameState === 'playing') {
// Flash target slots to give hint
for (var i = 0; i < targetSlots.length; i++) {
LK.effects.flashObject(targetSlots[i], 0xFFD700, 1000);
}
}
}
var draggedPiece = null;
game.move = function (x, y, obj) {
if (draggedPiece && draggedPiece.isDragging) {
draggedPiece.x = x;
draggedPiece.y = y;
}
};
game.down = function (x, y, obj) {
if (gameState === 'playing') {
// Check if clicked on back button
if (getDistance(x, y, 150, 150) < 60) {
returnToMenu();
return;
}
// Check if clicked on hint button
if (getDistance(x, y, 1900, 150) < 50) {
showHint();
return;
}
// Find clicked puzzle piece
for (var i = puzzlePieces.length - 1; i >= 0; i--) {
var piece = puzzlePieces[i];
if (!piece.isPlaced && getDistance(x, y, piece.x, piece.y) < 60) {
draggedPiece = piece;
piece.down(x, y, obj);
break;
}
}
}
};
game.up = function (x, y, obj) {
if (draggedPiece) {
draggedPiece.up(x, y, obj);
draggedPiece = null;
}
};
// Animate Labubu mascot
game.update = function () {
if (gameState === 'menu') {
labubuMascot.y = 500 + Math.sin(LK.ticks * 0.05) * 10;
labubuMascot.rotation = Math.sin(LK.ticks * 0.03) * 0.1;
}
};
// Initialize the game
createMenu();