User prompt
sayıları küçült ve kutularıda küçült
User prompt
kutular arasında boşluk bırak
User prompt
biraz daha büyüt ve aralarında boşluk bırak
User prompt
sayıları büyüt ve aralarında boşluk bırak
User prompt
kutuları biraz daha küçük yap ve aralarında boşluk bırak
User prompt
sayıların yanına bir kutu boşluk bırak onu kaydırarak bütün sayıları soldan sağa doğru sıralamalıyız
User prompt
15 sayıyı sadece 1 kutu içerisine al
User prompt
bütün sayıları bir kutu içerisine al
User prompt
sayıları kutu içine alma bütün sayıları bir kutu içerisine al
User prompt
bunu 15 sayı yap ve bir tablo içerisine koy
User prompt
biraz dah küçük olsun
User prompt
kenarları gözüksün
User prompt
bunu ekranı kaplayacak bir kare şeklinde yap
User prompt
arkada bir kutu içinde
User prompt
sayıları yana kaydırarak sıralamak istiyorum
User prompt
Please fix the bug: 'Uncaught TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 241
Code edit (1 edits merged)
Please save this source code
User prompt
Sayı Sıralama Yarışı
Initial prompt
bana bir sayı oyunu yap
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // NumberButton: A tappable number on the board var NumberButton = Container.expand(function () { var self = Container.call(this); // Attach circle background, always use btnSize for size and scaling var btnSize = 240; // unified button/box size (increased for bigger buttons) var circle = self.attachAsset('numberCircle', { anchorX: 0.5, anchorY: 0.5, width: btnSize, height: btnSize, scaleX: btnSize / 220, scaleY: btnSize / 220 }); // Number text var numberText = new Text2('1', { size: 120, // increased for bigger buttons // This will be scaled with the button fill: 0xFFFFFF }); numberText.anchor.set(0.5, 0.5); self.addChild(numberText); self.value = 1; // The number this button represents self.isActive = true; // If false, ignore taps self.setNumber = function (n) { self.value = n; numberText.setText(n); }; // flash method removed to prevent color changes // Touch/click event self.down = function (x, y, obj) { if (!self.isActive) return; // Find empty box and check adjacency if (typeof numbersContainer !== "undefined" && numbersContainer) { var emptyBox = null; for (var i = 0; i < numbersContainer.children.length; i++) { var child = numbersContainer.children[i]; if (child.alpha && child.alpha < 1) { emptyBox = child; break; } } if (emptyBox) { // Get grid positions var btnPos = getGridPos(self); var emptyPos = getGridPos(emptyBox); var isAdjacent = false; if (btnPos.row === emptyPos.row && Math.abs(btnPos.col - emptyPos.col) === 1) { isAdjacent = true; } else if (btnPos.col === emptyPos.col && Math.abs(btnPos.row - emptyPos.row) === 1) { isAdjacent = true; } if (isAdjacent) { // Animate swap var oldX = self.x, oldY = self.y; tween(self, { x: emptyBox.x, y: emptyBox.y }, { duration: 120, easing: tween.easeOut }); tween(emptyBox, { x: oldX, y: oldY }, { duration: 120, easing: tween.easeOut }); // Swap positions in-place var tmpX = self.x, tmpY = self.y; self.x = emptyBox.x; self.y = emptyBox.y; emptyBox.x = oldX; emptyBox.y = oldY; return; // Do not trigger number tap logic } } } if (typeof onNumberButtonPressed === "function") { onNumberButtonPressed(self); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c20 }); /**** * Game Code ****/ // We'll use a simple circle as a background for each number for better touch targets. // Numbers will be rendered as Text2, so no need for custom shapes or images for numbers. // --- Game parameters --- var boardPadding = 80; var minNumbers = 15; var maxNumbers = 15; var level = 1; var numbersOnBoard = minNumbers; var maxLevel = 20; // --- State --- var numberButtons = []; var nextNumber = 1; var isPlaying = false; // --- UI --- // Timer and number UI removed as per requirements // --- Functions --- // Define btnSize globally so it is accessible in all functions var btnSize = 240; // unified button/box size, used everywhere for NumberButton (increased for bigger buttons) function shuffleArray(arr) { for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } return arr; } function layoutNumbers(n) { // Remove old buttons for (var i = 0; i < numberButtons.length; i++) { numberButtons[i].destroy(); } numberButtons = []; // Remove old background if exists if (typeof numberRowBgBorder !== "undefined" && numberRowBgBorder && numberRowBgBorder.parent) { numberRowBgBorder.parent.removeChild(numberRowBgBorder); numberRowBgBorder.destroy(); } numberRowBgBorder = null; if (typeof numberRowBg !== "undefined" && numberRowBg && numberRowBg.parent) { numberRowBg.parent.removeChild(numberRowBg); numberRowBg.destroy(); } numberRowBg = null; // Make a smaller square background and border, centered var squareSize = Math.floor((Math.min(2048, 2732) - boardPadding * 2) * 0.7); // 70% of previous size var bgX = 2048 / 2; var bgY = 2732 / 2; // Add border: create a slightly larger square behind the main background var borderThickness = 14; numberRowBgBorder = LK.getAsset('numberCircle', { width: squareSize + borderThickness * 2, height: squareSize + borderThickness * 2, color: 0xffffff, // White border for visibility anchorX: 0.5, anchorY: 0.5, scaleX: (squareSize + borderThickness * 2) / 220, scaleY: (squareSize + borderThickness * 2) / 220, x: bgX, y: bgY }); game.addChild(numberRowBgBorder); numberRowBg = LK.getAsset('numberCircle', { width: squareSize, height: squareSize, color: 0x222b38, anchorX: 0.5, anchorY: 0.5, scaleX: squareSize / 220, scaleY: squareSize / 220, x: bgX, y: bgY }); game.addChild(numberRowBg); // Add a second box at the bottom of the board var bottomBoxY = bgY + squareSize / 2 + 80 + squareSize * 0.15; // 80px below main box, adjust as needed var bottomBox = LK.getAsset('numberCircle', { width: squareSize * 0.7, height: squareSize * 0.7, color: 0x222b38, anchorX: 0.5, anchorY: 0.5, scaleX: squareSize * 0.7 / 220, scaleY: squareSize * 0.7 / 220, x: bgX, y: bottomBoxY }); game.addChild(bottomBox); // Add a third box below the second box var thirdBoxY = bottomBoxY + squareSize * 0.7 / 2 + 60 + squareSize * 0.7 / 2; // 60px below second box var thirdBox = LK.getAsset('numberCircle', { width: squareSize * 0.7, height: squareSize * 0.7, color: 0x222b38, anchorX: 0.5, anchorY: 0.5, scaleX: squareSize * 0.7 / 220, scaleY: squareSize * 0.7 / 220, x: bgX, y: thirdBoxY }); game.addChild(thirdBox); // Create a container to hold all numbers, centered in the square if (typeof numbersContainer !== "undefined" && numbersContainer && numbersContainer.parent) { numbersContainer.parent.removeChild(numbersContainer); numbersContainer.destroy(); } numbersContainer = new Container(); numbersContainer.x = bgX; numbersContainer.y = bgY; game.addChild(numbersContainer); // Layout numbers in a 5x3 table grid, all boxes the same size, with a visual empty box var cols = 5; var rows = 3; var btnSize = 240; // unified button/box size, used everywhere for NumberButton (increased for bigger buttons) var btnSpacing = 70; // space between all boxes var gridWidth = cols * btnSize + (cols - 1) * btnSpacing; var gridHeight = rows * btnSize + (rows - 1) * btnSpacing; var startX = -gridWidth / 2 + btnSize / 2; var startY = -gridHeight / 2 + btnSize / 2; var positions = []; for (var row = 0; row < rows; row++) { for (var col = 0; col < cols; col++) { positions.push({ x: startX + col * (btnSize + btnSpacing), y: startY + row * (btnSize + btnSpacing) }); } } // Decide which position will be empty (last one for now) var emptyIndex = positions.length - 1; // Always use 1-15 for the board var nums = []; for (var i = 1; i <= 15; i++) nums.push(i); shuffleArray(nums); // Place all numbers inside the single numbersContainer, no per-number backgrounds // Ensure each number is assigned a unique position and no two numbers overlap // To avoid clustering, use a grid and assign each number to a unique cell, but shuffle the number assignments, not the positions. // This ensures all numbers are evenly spread and never overlap or cluster. var numIdx = 0; for (var i = 0; i < positions.length; i++) { if (i === emptyIndex) { // Add a visual empty box var emptyBox = LK.getAsset('numberCircle', { anchorX: 0.5, anchorY: 0.5, width: btnSize, height: btnSize, scaleX: btnSize / 220, scaleY: btnSize / 220, x: positions[i].x, y: positions[i].y, color: 0x222b38, alpha: 0.25 }); numbersContainer.addChild(emptyBox); continue; } // Assign each number to a unique, evenly distributed position (no clustering) var btn = new NumberButton(); btn.setNumber(nums[numIdx]); btn.x = positions[i].x; btn.y = positions[i].y; btn.isActive = true; btn.scaleX = 1; btn.scaleY = 1; numberButtons.push(btn); numbersContainer.addChild(btn); numIdx++; } // All numbers are now inside a single container (numbersContainer) which is inside the large square background. } function startLevel(lvl) { level = lvl; numbersOnBoard = 15; nextNumber = 1; layoutNumbers(numbersOnBoard); isPlaying = true; } // updateScoreText and updateTimerText removed function endGame(win) { isPlaying = false; // Remove all number buttons for (var i = 0; i < numberButtons.length; i++) { numberButtons[i].destroy(); } numberButtons = []; // Show win/lose if (win) { LK.showYouWin(); } else { LK.showGameOver(); } } function onNumberButtonPressed(btn) { if (!isPlaying) return; if (!btn.isActive) return; // --- No swap logic needed, just process number tap --- if (btn.value === nextNumber) { // Correct btn.isActive = false; // No color change, no disappearance, just mark as inactive // Do not remove or hide the number, keep it visible nextNumber++; if (nextNumber > numbersOnBoard) { // Level complete isPlaying = false; LK.setTimeout(function () { if (level >= maxLevel) { endGame(true); } else { startLevel(level + 1); } }, 600); } } else { // Wrong // No color change, no penalty // Do nothing, do not trigger game over } } // --- Game event handlers --- game.update = function () { if (!isPlaying) return; // Timer and time-based game over removed }; // --- Start game --- function startGame() { level = 1; startLevel(level); } startGame(); // --- Touch handling for drag-and-slide of rows/columns (sliding puzzle style) --- var dragButton = null; var dragStartX = 0; var dragStartY = 0; var dragBtnStartX = 0; var dragBtnStartY = 0; var dragRowOrCol = null; // {type: 'row'|'col', idx: number} var dragGroup = []; // buttons being dragged var dragEmptyBox = null; var dragEmptyStartX = 0; var dragEmptyStartY = 0; // Helper: find the NumberButton under a given (x, y) in numbersContainer local space function getButtonAtPoint(x, y) { for (var i = 0; i < numberButtons.length; i++) { var btn = numberButtons[i]; // Convert global (x, y) to numbersContainer local var local = numbersContainer.toLocal({ x: x, y: y }); var bx = btn.x, by = btn.y; var half = btnSize / 2; if (local.x >= bx - half && local.x <= bx + half && local.y >= by - half && local.y <= by + half) { return btn; } } return null; } // Helper: get grid position (col, row) for a button or empty box function getGridPos(obj) { // Use layoutNumbers grid logic var cols = 5, rows = 3; var btnSpacing = 70; var gridWidth = cols * btnSize + (cols - 1) * btnSpacing; var gridHeight = rows * btnSize + (rows - 1) * btnSpacing; var startX = -gridWidth / 2 + btnSize / 2; var startY = -gridHeight / 2 + btnSize / 2; var col = Math.round((obj.x - startX) / (btnSize + btnSpacing)); var row = Math.round((obj.y - startY) / (btnSize + btnSpacing)); return { col: col, row: row }; } // Helper: get the empty box object function getEmptyBox() { for (var i = 0; i < numbersContainer.children.length; i++) { var child = numbersContainer.children[i]; if (child.alpha && child.alpha < 1) { return child; } } return null; } // Helper: get all buttons in a row or column (excluding empty box) function getButtonsInLine(type, idx) { var result = []; for (var i = 0; i < numberButtons.length; i++) { var btn = numberButtons[i]; var pos = getGridPos(btn); if (type === 'row' && pos.row === idx || type === 'col' && pos.col === idx) { result.push(btn); } } return result; } // Only allow sliding if game is playing game.down = function (x, y, obj) { if (!isPlaying) return; // Convert to numbersContainer local var local = numbersContainer.toLocal({ x: x, y: y }); var btn = getButtonAtPoint(x, y); if (btn && btn.isActive) { dragButton = btn; dragStartX = x; dragStartY = y; dragBtnStartX = btn.x; dragBtnStartY = btn.y; // Determine if we can slide row or column (must contain empty box) var emptyBox = getEmptyBox(); var btnPos = getGridPos(btn); var emptyPos = getGridPos(emptyBox); if (btnPos.row === emptyPos.row) { dragRowOrCol = { type: 'row', idx: btnPos.row }; dragGroup = getButtonsInLine('row', btnPos.row); } else if (btnPos.col === emptyPos.col) { dragRowOrCol = { type: 'col', idx: btnPos.col }; dragGroup = getButtonsInLine('col', btnPos.col); } else { dragRowOrCol = null; dragGroup = []; dragButton = null; return; } dragEmptyBox = emptyBox; dragEmptyStartX = emptyBox.x; dragEmptyStartY = emptyBox.y; } }; game.move = function (x, y, obj) { if (!isPlaying) return; if (!dragButton || !dragRowOrCol) return; var dx = x - dragStartX; var dy = y - dragStartY; // Only allow drag if movement is significant (avoid accidental tap) if (Math.abs(dx) > 10 || Math.abs(dy) > 10) { // Move the group visually along the allowed axis if (dragRowOrCol.type === 'row') { for (var i = 0; i < dragGroup.length; i++) { dragGroup[i].x += dx - (dragGroup[i].lastDragDX || 0); } dragEmptyBox.x += dx - (dragEmptyBox.lastDragDX || 0); // Store last drag for (var i = 0; i < dragGroup.length; i++) { dragGroup[i].lastDragDX = dx; } dragEmptyBox.lastDragDX = dx; } else if (dragRowOrCol.type === 'col') { for (var i = 0; i < dragGroup.length; i++) { dragGroup[i].y += dy - (dragGroup[i].lastDragDY || 0); } dragEmptyBox.y += dy - (dragEmptyBox.lastDragDY || 0); // Store last drag for (var i = 0; i < dragGroup.length; i++) { dragGroup[i].lastDragDY = dy; } dragEmptyBox.lastDragDY = dy; } } }; game.up = function (x, y, obj) { if (!dragButton || !dragRowOrCol) { dragButton = null; dragRowOrCol = null; dragGroup = []; dragEmptyBox = null; return; } // On release, check if drag is enough to swap with empty box var threshold = btnSize * 0.6; var moved = false; if (dragRowOrCol.type === 'row') { var dx = dragGroup[0].lastDragDX || 0; if (Math.abs(dx) > threshold) { // Determine direction: right or left var dir = dx > 0 ? 1 : -1; var emptyPos = getGridPos(dragEmptyBox); // Only allow if empty is adjacent in row var canMove = false; for (var i = 0; i < dragGroup.length; i++) { var pos = getGridPos(dragGroup[i]); if (Math.abs(pos.col - emptyPos.col) === 1) { canMove = true; break; } } if (canMove) { // Prevent merging: only allow swap if no other button is at the empty box's position var mergeDetected = false; for (var j = 0; j < numberButtons.length; j++) { if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === dragEmptyBox.x && numberButtons[j].y === dragEmptyBox.y) { mergeDetected = true; break; } } if (!mergeDetected) { // Before swapping, ensure no two buttons will end up at the same position var targetX = dragEmptyBox.x; var targetY = dragEmptyBox.y; var collision = false; for (var j = 0; j < numberButtons.length; j++) { if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === targetX && numberButtons[j].y === targetY) { collision = true; break; } } if (!collision) { // Swap positions: move all buttons in row toward empty, move empty to button's old pos for (var i = 0; i < dragGroup.length; i++) { var btn = dragGroup[i]; var pos = getGridPos(btn); if (dir === 1 && pos.col < emptyPos.col || dir === -1 && pos.col > emptyPos.col) { // Move this button to empty tween(btn, { x: dragEmptyBox.x, y: dragEmptyBox.y }, { duration: 120, easing: tween.easeOut }); dragEmptyBox.x = btn.x; dragEmptyBox.y = btn.y; moved = true; break; } } } } } } } else if (dragRowOrCol.type === 'col') { var dy = dragGroup[0].lastDragDY || 0; if (Math.abs(dy) > threshold) { // Determine direction: down or up var dir = dy > 0 ? 1 : -1; var emptyPos = getGridPos(dragEmptyBox); // Only allow if empty is adjacent in col var canMove = false; for (var i = 0; i < dragGroup.length; i++) { var pos = getGridPos(dragGroup[i]); if (Math.abs(pos.row - emptyPos.row) === 1) { canMove = true; break; } } if (canMove) { // Prevent merging: only allow swap if no other button is at the empty box's position var mergeDetected = false; for (var j = 0; j < numberButtons.length; j++) { if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === dragEmptyBox.x && numberButtons[j].y === dragEmptyBox.y) { mergeDetected = true; break; } } if (!mergeDetected) { // Before swapping, ensure no two buttons will end up at the same position var targetX = dragEmptyBox.x; var targetY = dragEmptyBox.y; var collision = false; for (var j = 0; j < numberButtons.length; j++) { if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === targetX && numberButtons[j].y === targetY) { collision = true; break; } } if (!collision) { // Swap positions: move all buttons in col toward empty, move empty to button's old pos for (var i = 0; i < dragGroup.length; i++) { var btn = dragGroup[i]; var pos = getGridPos(btn); if (dir === 1 && pos.row < emptyPos.row || dir === -1 && pos.row > emptyPos.row) { // Move this button to empty tween(btn, { x: dragEmptyBox.x, y: dragEmptyBox.y }, { duration: 120, easing: tween.easeOut }); dragEmptyBox.x = btn.x; dragEmptyBox.y = btn.y; moved = true; break; } } } } } } } // Snap all to grid if not moved if (!moved) { // Snap all buttons in group and empty box back to original for (var i = 0; i < dragGroup.length; i++) { var btn = dragGroup[i]; tween(btn, { x: dragBtnStartX, y: dragBtnStartY }, { duration: 120, easing: tween.easeOut }); btn.lastDragDX = 0; btn.lastDragDY = 0; } if (dragEmptyBox) { tween(dragEmptyBox, { x: dragEmptyStartX, y: dragEmptyStartY }, { duration: 120, easing: tween.easeOut }); dragEmptyBox.lastDragDX = 0; dragEmptyBox.lastDragDY = 0; } } // Reset drag state dragButton = null; dragRowOrCol = null; dragGroup = []; dragEmptyBox = null; }; // --- Storage (for future highscore etc.) --- // Not implemented in MVP // --- Music/Sound --- // Not implemented in MVP // --- End of file ---
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// NumberButton: A tappable number on the board
var NumberButton = Container.expand(function () {
var self = Container.call(this);
// Attach circle background, always use btnSize for size and scaling
var btnSize = 240; // unified button/box size (increased for bigger buttons)
var circle = self.attachAsset('numberCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: btnSize,
height: btnSize,
scaleX: btnSize / 220,
scaleY: btnSize / 220
});
// Number text
var numberText = new Text2('1', {
size: 120,
// increased for bigger buttons
// This will be scaled with the button
fill: 0xFFFFFF
});
numberText.anchor.set(0.5, 0.5);
self.addChild(numberText);
self.value = 1; // The number this button represents
self.isActive = true; // If false, ignore taps
self.setNumber = function (n) {
self.value = n;
numberText.setText(n);
};
// flash method removed to prevent color changes
// Touch/click event
self.down = function (x, y, obj) {
if (!self.isActive) return;
// Find empty box and check adjacency
if (typeof numbersContainer !== "undefined" && numbersContainer) {
var emptyBox = null;
for (var i = 0; i < numbersContainer.children.length; i++) {
var child = numbersContainer.children[i];
if (child.alpha && child.alpha < 1) {
emptyBox = child;
break;
}
}
if (emptyBox) {
// Get grid positions
var btnPos = getGridPos(self);
var emptyPos = getGridPos(emptyBox);
var isAdjacent = false;
if (btnPos.row === emptyPos.row && Math.abs(btnPos.col - emptyPos.col) === 1) {
isAdjacent = true;
} else if (btnPos.col === emptyPos.col && Math.abs(btnPos.row - emptyPos.row) === 1) {
isAdjacent = true;
}
if (isAdjacent) {
// Animate swap
var oldX = self.x,
oldY = self.y;
tween(self, {
x: emptyBox.x,
y: emptyBox.y
}, {
duration: 120,
easing: tween.easeOut
});
tween(emptyBox, {
x: oldX,
y: oldY
}, {
duration: 120,
easing: tween.easeOut
});
// Swap positions in-place
var tmpX = self.x,
tmpY = self.y;
self.x = emptyBox.x;
self.y = emptyBox.y;
emptyBox.x = oldX;
emptyBox.y = oldY;
return; // Do not trigger number tap logic
}
}
}
if (typeof onNumberButtonPressed === "function") {
onNumberButtonPressed(self);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c20
});
/****
* Game Code
****/
// We'll use a simple circle as a background for each number for better touch targets.
// Numbers will be rendered as Text2, so no need for custom shapes or images for numbers.
// --- Game parameters ---
var boardPadding = 80;
var minNumbers = 15;
var maxNumbers = 15;
var level = 1;
var numbersOnBoard = minNumbers;
var maxLevel = 20;
// --- State ---
var numberButtons = [];
var nextNumber = 1;
var isPlaying = false;
// --- UI ---
// Timer and number UI removed as per requirements
// --- Functions ---
// Define btnSize globally so it is accessible in all functions
var btnSize = 240; // unified button/box size, used everywhere for NumberButton (increased for bigger buttons)
function shuffleArray(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
function layoutNumbers(n) {
// Remove old buttons
for (var i = 0; i < numberButtons.length; i++) {
numberButtons[i].destroy();
}
numberButtons = [];
// Remove old background if exists
if (typeof numberRowBgBorder !== "undefined" && numberRowBgBorder && numberRowBgBorder.parent) {
numberRowBgBorder.parent.removeChild(numberRowBgBorder);
numberRowBgBorder.destroy();
}
numberRowBgBorder = null;
if (typeof numberRowBg !== "undefined" && numberRowBg && numberRowBg.parent) {
numberRowBg.parent.removeChild(numberRowBg);
numberRowBg.destroy();
}
numberRowBg = null;
// Make a smaller square background and border, centered
var squareSize = Math.floor((Math.min(2048, 2732) - boardPadding * 2) * 0.7); // 70% of previous size
var bgX = 2048 / 2;
var bgY = 2732 / 2;
// Add border: create a slightly larger square behind the main background
var borderThickness = 14;
numberRowBgBorder = LK.getAsset('numberCircle', {
width: squareSize + borderThickness * 2,
height: squareSize + borderThickness * 2,
color: 0xffffff,
// White border for visibility
anchorX: 0.5,
anchorY: 0.5,
scaleX: (squareSize + borderThickness * 2) / 220,
scaleY: (squareSize + borderThickness * 2) / 220,
x: bgX,
y: bgY
});
game.addChild(numberRowBgBorder);
numberRowBg = LK.getAsset('numberCircle', {
width: squareSize,
height: squareSize,
color: 0x222b38,
anchorX: 0.5,
anchorY: 0.5,
scaleX: squareSize / 220,
scaleY: squareSize / 220,
x: bgX,
y: bgY
});
game.addChild(numberRowBg);
// Add a second box at the bottom of the board
var bottomBoxY = bgY + squareSize / 2 + 80 + squareSize * 0.15; // 80px below main box, adjust as needed
var bottomBox = LK.getAsset('numberCircle', {
width: squareSize * 0.7,
height: squareSize * 0.7,
color: 0x222b38,
anchorX: 0.5,
anchorY: 0.5,
scaleX: squareSize * 0.7 / 220,
scaleY: squareSize * 0.7 / 220,
x: bgX,
y: bottomBoxY
});
game.addChild(bottomBox);
// Add a third box below the second box
var thirdBoxY = bottomBoxY + squareSize * 0.7 / 2 + 60 + squareSize * 0.7 / 2; // 60px below second box
var thirdBox = LK.getAsset('numberCircle', {
width: squareSize * 0.7,
height: squareSize * 0.7,
color: 0x222b38,
anchorX: 0.5,
anchorY: 0.5,
scaleX: squareSize * 0.7 / 220,
scaleY: squareSize * 0.7 / 220,
x: bgX,
y: thirdBoxY
});
game.addChild(thirdBox);
// Create a container to hold all numbers, centered in the square
if (typeof numbersContainer !== "undefined" && numbersContainer && numbersContainer.parent) {
numbersContainer.parent.removeChild(numbersContainer);
numbersContainer.destroy();
}
numbersContainer = new Container();
numbersContainer.x = bgX;
numbersContainer.y = bgY;
game.addChild(numbersContainer);
// Layout numbers in a 5x3 table grid, all boxes the same size, with a visual empty box
var cols = 5;
var rows = 3;
var btnSize = 240; // unified button/box size, used everywhere for NumberButton (increased for bigger buttons)
var btnSpacing = 70; // space between all boxes
var gridWidth = cols * btnSize + (cols - 1) * btnSpacing;
var gridHeight = rows * btnSize + (rows - 1) * btnSpacing;
var startX = -gridWidth / 2 + btnSize / 2;
var startY = -gridHeight / 2 + btnSize / 2;
var positions = [];
for (var row = 0; row < rows; row++) {
for (var col = 0; col < cols; col++) {
positions.push({
x: startX + col * (btnSize + btnSpacing),
y: startY + row * (btnSize + btnSpacing)
});
}
}
// Decide which position will be empty (last one for now)
var emptyIndex = positions.length - 1;
// Always use 1-15 for the board
var nums = [];
for (var i = 1; i <= 15; i++) nums.push(i);
shuffleArray(nums);
// Place all numbers inside the single numbersContainer, no per-number backgrounds
// Ensure each number is assigned a unique position and no two numbers overlap
// To avoid clustering, use a grid and assign each number to a unique cell, but shuffle the number assignments, not the positions.
// This ensures all numbers are evenly spread and never overlap or cluster.
var numIdx = 0;
for (var i = 0; i < positions.length; i++) {
if (i === emptyIndex) {
// Add a visual empty box
var emptyBox = LK.getAsset('numberCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: btnSize,
height: btnSize,
scaleX: btnSize / 220,
scaleY: btnSize / 220,
x: positions[i].x,
y: positions[i].y,
color: 0x222b38,
alpha: 0.25
});
numbersContainer.addChild(emptyBox);
continue;
}
// Assign each number to a unique, evenly distributed position (no clustering)
var btn = new NumberButton();
btn.setNumber(nums[numIdx]);
btn.x = positions[i].x;
btn.y = positions[i].y;
btn.isActive = true;
btn.scaleX = 1;
btn.scaleY = 1;
numberButtons.push(btn);
numbersContainer.addChild(btn);
numIdx++;
}
// All numbers are now inside a single container (numbersContainer) which is inside the large square background.
}
function startLevel(lvl) {
level = lvl;
numbersOnBoard = 15;
nextNumber = 1;
layoutNumbers(numbersOnBoard);
isPlaying = true;
}
// updateScoreText and updateTimerText removed
function endGame(win) {
isPlaying = false;
// Remove all number buttons
for (var i = 0; i < numberButtons.length; i++) {
numberButtons[i].destroy();
}
numberButtons = [];
// Show win/lose
if (win) {
LK.showYouWin();
} else {
LK.showGameOver();
}
}
function onNumberButtonPressed(btn) {
if (!isPlaying) return;
if (!btn.isActive) return;
// --- No swap logic needed, just process number tap ---
if (btn.value === nextNumber) {
// Correct
btn.isActive = false;
// No color change, no disappearance, just mark as inactive
// Do not remove or hide the number, keep it visible
nextNumber++;
if (nextNumber > numbersOnBoard) {
// Level complete
isPlaying = false;
LK.setTimeout(function () {
if (level >= maxLevel) {
endGame(true);
} else {
startLevel(level + 1);
}
}, 600);
}
} else {
// Wrong
// No color change, no penalty
// Do nothing, do not trigger game over
}
}
// --- Game event handlers ---
game.update = function () {
if (!isPlaying) return;
// Timer and time-based game over removed
};
// --- Start game ---
function startGame() {
level = 1;
startLevel(level);
}
startGame();
// --- Touch handling for drag-and-slide of rows/columns (sliding puzzle style) ---
var dragButton = null;
var dragStartX = 0;
var dragStartY = 0;
var dragBtnStartX = 0;
var dragBtnStartY = 0;
var dragRowOrCol = null; // {type: 'row'|'col', idx: number}
var dragGroup = []; // buttons being dragged
var dragEmptyBox = null;
var dragEmptyStartX = 0;
var dragEmptyStartY = 0;
// Helper: find the NumberButton under a given (x, y) in numbersContainer local space
function getButtonAtPoint(x, y) {
for (var i = 0; i < numberButtons.length; i++) {
var btn = numberButtons[i];
// Convert global (x, y) to numbersContainer local
var local = numbersContainer.toLocal({
x: x,
y: y
});
var bx = btn.x,
by = btn.y;
var half = btnSize / 2;
if (local.x >= bx - half && local.x <= bx + half && local.y >= by - half && local.y <= by + half) {
return btn;
}
}
return null;
}
// Helper: get grid position (col, row) for a button or empty box
function getGridPos(obj) {
// Use layoutNumbers grid logic
var cols = 5,
rows = 3;
var btnSpacing = 70;
var gridWidth = cols * btnSize + (cols - 1) * btnSpacing;
var gridHeight = rows * btnSize + (rows - 1) * btnSpacing;
var startX = -gridWidth / 2 + btnSize / 2;
var startY = -gridHeight / 2 + btnSize / 2;
var col = Math.round((obj.x - startX) / (btnSize + btnSpacing));
var row = Math.round((obj.y - startY) / (btnSize + btnSpacing));
return {
col: col,
row: row
};
}
// Helper: get the empty box object
function getEmptyBox() {
for (var i = 0; i < numbersContainer.children.length; i++) {
var child = numbersContainer.children[i];
if (child.alpha && child.alpha < 1) {
return child;
}
}
return null;
}
// Helper: get all buttons in a row or column (excluding empty box)
function getButtonsInLine(type, idx) {
var result = [];
for (var i = 0; i < numberButtons.length; i++) {
var btn = numberButtons[i];
var pos = getGridPos(btn);
if (type === 'row' && pos.row === idx || type === 'col' && pos.col === idx) {
result.push(btn);
}
}
return result;
}
// Only allow sliding if game is playing
game.down = function (x, y, obj) {
if (!isPlaying) return;
// Convert to numbersContainer local
var local = numbersContainer.toLocal({
x: x,
y: y
});
var btn = getButtonAtPoint(x, y);
if (btn && btn.isActive) {
dragButton = btn;
dragStartX = x;
dragStartY = y;
dragBtnStartX = btn.x;
dragBtnStartY = btn.y;
// Determine if we can slide row or column (must contain empty box)
var emptyBox = getEmptyBox();
var btnPos = getGridPos(btn);
var emptyPos = getGridPos(emptyBox);
if (btnPos.row === emptyPos.row) {
dragRowOrCol = {
type: 'row',
idx: btnPos.row
};
dragGroup = getButtonsInLine('row', btnPos.row);
} else if (btnPos.col === emptyPos.col) {
dragRowOrCol = {
type: 'col',
idx: btnPos.col
};
dragGroup = getButtonsInLine('col', btnPos.col);
} else {
dragRowOrCol = null;
dragGroup = [];
dragButton = null;
return;
}
dragEmptyBox = emptyBox;
dragEmptyStartX = emptyBox.x;
dragEmptyStartY = emptyBox.y;
}
};
game.move = function (x, y, obj) {
if (!isPlaying) return;
if (!dragButton || !dragRowOrCol) return;
var dx = x - dragStartX;
var dy = y - dragStartY;
// Only allow drag if movement is significant (avoid accidental tap)
if (Math.abs(dx) > 10 || Math.abs(dy) > 10) {
// Move the group visually along the allowed axis
if (dragRowOrCol.type === 'row') {
for (var i = 0; i < dragGroup.length; i++) {
dragGroup[i].x += dx - (dragGroup[i].lastDragDX || 0);
}
dragEmptyBox.x += dx - (dragEmptyBox.lastDragDX || 0);
// Store last drag
for (var i = 0; i < dragGroup.length; i++) {
dragGroup[i].lastDragDX = dx;
}
dragEmptyBox.lastDragDX = dx;
} else if (dragRowOrCol.type === 'col') {
for (var i = 0; i < dragGroup.length; i++) {
dragGroup[i].y += dy - (dragGroup[i].lastDragDY || 0);
}
dragEmptyBox.y += dy - (dragEmptyBox.lastDragDY || 0);
// Store last drag
for (var i = 0; i < dragGroup.length; i++) {
dragGroup[i].lastDragDY = dy;
}
dragEmptyBox.lastDragDY = dy;
}
}
};
game.up = function (x, y, obj) {
if (!dragButton || !dragRowOrCol) {
dragButton = null;
dragRowOrCol = null;
dragGroup = [];
dragEmptyBox = null;
return;
}
// On release, check if drag is enough to swap with empty box
var threshold = btnSize * 0.6;
var moved = false;
if (dragRowOrCol.type === 'row') {
var dx = dragGroup[0].lastDragDX || 0;
if (Math.abs(dx) > threshold) {
// Determine direction: right or left
var dir = dx > 0 ? 1 : -1;
var emptyPos = getGridPos(dragEmptyBox);
// Only allow if empty is adjacent in row
var canMove = false;
for (var i = 0; i < dragGroup.length; i++) {
var pos = getGridPos(dragGroup[i]);
if (Math.abs(pos.col - emptyPos.col) === 1) {
canMove = true;
break;
}
}
if (canMove) {
// Prevent merging: only allow swap if no other button is at the empty box's position
var mergeDetected = false;
for (var j = 0; j < numberButtons.length; j++) {
if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === dragEmptyBox.x && numberButtons[j].y === dragEmptyBox.y) {
mergeDetected = true;
break;
}
}
if (!mergeDetected) {
// Before swapping, ensure no two buttons will end up at the same position
var targetX = dragEmptyBox.x;
var targetY = dragEmptyBox.y;
var collision = false;
for (var j = 0; j < numberButtons.length; j++) {
if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === targetX && numberButtons[j].y === targetY) {
collision = true;
break;
}
}
if (!collision) {
// Swap positions: move all buttons in row toward empty, move empty to button's old pos
for (var i = 0; i < dragGroup.length; i++) {
var btn = dragGroup[i];
var pos = getGridPos(btn);
if (dir === 1 && pos.col < emptyPos.col || dir === -1 && pos.col > emptyPos.col) {
// Move this button to empty
tween(btn, {
x: dragEmptyBox.x,
y: dragEmptyBox.y
}, {
duration: 120,
easing: tween.easeOut
});
dragEmptyBox.x = btn.x;
dragEmptyBox.y = btn.y;
moved = true;
break;
}
}
}
}
}
}
} else if (dragRowOrCol.type === 'col') {
var dy = dragGroup[0].lastDragDY || 0;
if (Math.abs(dy) > threshold) {
// Determine direction: down or up
var dir = dy > 0 ? 1 : -1;
var emptyPos = getGridPos(dragEmptyBox);
// Only allow if empty is adjacent in col
var canMove = false;
for (var i = 0; i < dragGroup.length; i++) {
var pos = getGridPos(dragGroup[i]);
if (Math.abs(pos.row - emptyPos.row) === 1) {
canMove = true;
break;
}
}
if (canMove) {
// Prevent merging: only allow swap if no other button is at the empty box's position
var mergeDetected = false;
for (var j = 0; j < numberButtons.length; j++) {
if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === dragEmptyBox.x && numberButtons[j].y === dragEmptyBox.y) {
mergeDetected = true;
break;
}
}
if (!mergeDetected) {
// Before swapping, ensure no two buttons will end up at the same position
var targetX = dragEmptyBox.x;
var targetY = dragEmptyBox.y;
var collision = false;
for (var j = 0; j < numberButtons.length; j++) {
if (numberButtons[j] !== dragGroup[0] && numberButtons[j].x === targetX && numberButtons[j].y === targetY) {
collision = true;
break;
}
}
if (!collision) {
// Swap positions: move all buttons in col toward empty, move empty to button's old pos
for (var i = 0; i < dragGroup.length; i++) {
var btn = dragGroup[i];
var pos = getGridPos(btn);
if (dir === 1 && pos.row < emptyPos.row || dir === -1 && pos.row > emptyPos.row) {
// Move this button to empty
tween(btn, {
x: dragEmptyBox.x,
y: dragEmptyBox.y
}, {
duration: 120,
easing: tween.easeOut
});
dragEmptyBox.x = btn.x;
dragEmptyBox.y = btn.y;
moved = true;
break;
}
}
}
}
}
}
}
// Snap all to grid if not moved
if (!moved) {
// Snap all buttons in group and empty box back to original
for (var i = 0; i < dragGroup.length; i++) {
var btn = dragGroup[i];
tween(btn, {
x: dragBtnStartX,
y: dragBtnStartY
}, {
duration: 120,
easing: tween.easeOut
});
btn.lastDragDX = 0;
btn.lastDragDY = 0;
}
if (dragEmptyBox) {
tween(dragEmptyBox, {
x: dragEmptyStartX,
y: dragEmptyStartY
}, {
duration: 120,
easing: tween.easeOut
});
dragEmptyBox.lastDragDX = 0;
dragEmptyBox.lastDragDY = 0;
}
}
// Reset drag state
dragButton = null;
dragRowOrCol = null;
dragGroup = [];
dragEmptyBox = null;
};
// --- Storage (for future highscore etc.) ---
// Not implemented in MVP
// --- Music/Sound ---
// Not implemented in MVP
// --- End of file ---