User prompt
12'nin altında bir tane daha kutu olsun
User prompt
altta bir tane daha kutu olsun
User prompt
gerizekalı sayılar birşleşmesin
User prompt
sayılar birleşmesin
User prompt
anlamıyor musun sayılar bir arada toplanmasın
User prompt
sayılar bir sayıda toplanmasın
User prompt
sayılar bir sayıda toplanmasın
User prompt
1'den 15'e kadar bütün sayılar olsun
User prompt
sayıar yok olmasın
User prompt
başka bir sayıya basınca kaybetmesin
User prompt
süre ve sayıyı yok et
User prompt
sayıların rengi değişmesin ve sayılar yok olmasın
User prompt
üstüne tıklayınca otomatik kaysın ama sadece yanında boşluk olanlar
User prompt
elle kaydırıp sayıları sıralama oyunu bu kaydırma yapmak lazı
User prompt
Please fix the bug: 'Uncaught ReferenceError: btnSize is not defined' in or related to this line: 'var half = btnSize / 2;' Line Number: 375
User prompt
mousla veya elle sayıları kaydırabiliyim
User prompt
boş kutunun yri boş olarak dursun
User prompt
boş kutuyu sil
User prompt
bir kutuyla diğer kutuyu yer değiştirebiliyim
User prompt
kuyuları büyüt
User prompt
hepsini aynı boyutta yap
User prompt
bütün kutuları aynı boyda yap
User prompt
ile aynı boyutta yap
User prompt
boş kutuyuda büyüt
User prompt
kutular arasında boşluk bırak
/****
* 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);
};
self.flash = function (color, duration) {
tween(circle, {
tint: color
}, {
duration: duration / 2,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(circle, {
tint: 0x2d9cdb
}, {
duration: duration / 2,
easing: tween.easeOut
});
}
});
};
// Touch/click event
self.down = function (x, y, obj) {
if (!self.isActive) return;
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 timePerLevel = 15000; // ms
var timePenalty = 1500; // ms lost on wrong tap
var timeBonus = 500; // ms gained on perfect level
var maxLevel = 20;
// --- State ---
var numberButtons = [];
var nextNumber = 1;
var timer = null;
var timeLeft = timePerLevel;
var score = 0;
var isPlaying = false;
var lastTapTime = 0;
// --- UI ---
var scoreText = new Text2('Skor: 0', {
size: 90,
fill: "#fff"
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var timerText = new Text2('Süre: 0', {
size: 80,
fill: 0xFFE066
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
var levelText = new Text2('Seviye: 1', {
size: 70,
fill: 0xB8E994
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
// Position GUI elements
scoreText.y = 30;
scoreText.x = LK.gui.top.width / 2;
timerText.y = scoreText.y + scoreText.height + 10;
timerText.x = LK.gui.top.width / 2;
levelText.y = timerText.y + timerText.height + 10;
levelText.x = LK.gui.top.width / 2;
// --- 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);
// 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;
// Shuffle numbers
var nums = [];
for (var i = 1; i <= n; i++) nums.push(i);
shuffleArray(nums);
// Place all numbers inside the single numbersContainer, no per-number backgrounds
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;
}
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 = Math.min(minNumbers + (level - 1) * 2, maxNumbers);
nextNumber = 1;
timeLeft = timePerLevel + Math.max(0, (level - 1) * 500); // Slightly more time for higher levels
levelText.setText('Seviye: ' + level);
layoutNumbers(numbersOnBoard);
isPlaying = true;
updateScoreText();
updateTimerText();
}
function updateScoreText() {
scoreText.setText('Skor: ' + score);
}
function updateTimerText() {
timerText.setText('Süre: ' + Math.ceil(timeLeft / 1000));
}
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;
btn.flash(0x6fcf97, 300);
tween(btn, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
btn.destroy();
}
});
nextNumber++;
score += 10 + Math.max(0, 5 * (level - 1));
updateScoreText();
if (nextNumber > numbersOnBoard) {
// Level complete
isPlaying = false;
// Bonus for perfect
timeLeft += timeBonus;
LK.setTimeout(function () {
if (level >= maxLevel) {
endGame(true);
} else {
startLevel(level + 1);
}
}, 600);
}
} else {
// Wrong
btn.flash(0xeb5757, 400);
timeLeft -= timePenalty;
LK.effects.flashObject(btn, 0xeb5757, 300);
if (timeLeft < 0) {
timeLeft = 0;
}
updateTimerText();
}
}
// --- Game event handlers ---
game.update = function () {
if (!isPlaying) return;
// Timer
timeLeft -= 1000 / 60;
if (timeLeft < 0) timeLeft = 0;
updateTimerText();
if (timeLeft <= 0) {
endGame(false);
}
};
// --- Start game ---
function startGame() {
score = 0;
level = 1;
startLevel(level);
updateScoreText();
updateTimerText();
}
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) {
// 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) {
// 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 --- ===================================================================
--- original.js
+++ change.js
@@ -339,14 +339,19 @@
updateScoreText();
updateTimerText();
}
startGame();
-// --- Touch handling for drag-and-slide of individual number buttons ---
+// --- 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];
@@ -363,8 +368,47 @@
}
}
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
@@ -378,76 +422,184 @@
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) return;
- // Only allow drag if still inside numbersContainer
+ 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 button visually
- dragButton.x = dragBtnStartX + dx;
- dragButton.y = dragBtnStartY + dy;
+ // 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) return;
- // On release, snap to nearest empty box or nearest grid position
- // Find the closest empty box position (the one with alpha < 1 in numbersContainer)
- var minDist = 999999,
- targetX = dragBtnStartX,
- targetY = dragBtnStartY;
- for (var i = 0; i < numbersContainer.children.length; i++) {
- var child = numbersContainer.children[i];
- if (child.alpha && child.alpha < 1) {
- // This is the empty box
- var dx = dragButton.x - child.x;
- var dy = dragButton.y - child.y;
- var dist = dx * dx + dy * dy;
- if (dist < minDist) {
- minDist = dist;
- targetX = child.x;
- targetY = child.y;
+ 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) {
+ // 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;
+ }
+ }
+ }
}
- }
- // If close enough to empty box, swap positions
- if (minDist < btnSize * btnSize) {
- // Animate snap
- var oldX = dragButton.x,
- oldY = dragButton.y;
- tween(dragButton, {
- x: targetX,
- y: targetY
- }, {
- duration: 120,
- easing: tween.easeOut
- });
- // Move empty box to old position
- for (var i = 0; i < numbersContainer.children.length; i++) {
- var child = numbersContainer.children[i];
- if (child.alpha && child.alpha < 1) {
- child.x = dragBtnStartX;
- child.y = dragBtnStartY;
- 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) {
+ // 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;
+ }
+ }
+ }
}
- } else {
- // Snap back to original
- tween(dragButton, {
- x: dragBtnStartX,
- y: dragBtnStartY
- }, {
- duration: 120,
- easing: tween.easeOut
- });
}
+ // 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 ---