/****
* 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();