User prompt
Fixa så att man ser hela bakgrunden i spelfältet och gör riktlinjerna smalare
User prompt
Gör så att man ser skuggan av klossen man sätter ut mer tydlig
User prompt
Gör spel planen ännu större
User prompt
Gör spel planen större
User prompt
Fixa så att klossarna passar bättre på spel planen
User prompt
Fix score
User prompt
Change background to dark blue
User prompt
Change background picture to light blue
User prompt
Set background picture to BKR
User prompt
Set background to BKR asset
User prompt
Set background to BKR asset
User prompt
Set background to background asset
User prompt
Fixa så det blir lättare att placera ut klossarna
User prompt
Fix bugs
User prompt
Fixa större klossar
User prompt
Fix bugs
Code edit (1 edits merged)
Please save this source code
User prompt
Color Block Satisfy
Initial prompt
Skapa ett roligt satisfying block pussel spel, blocken skall vara stora, ha flera färger, skall va roligt och lätt att spela
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Block class: a draggable block with a given shape and color
var Block = Container.expand(function () {
var self = Container.call(this);
// Properties
self.shape = null; // {cells, size}
self.color = null; // asset id
self.cellSize = 120;
self.cells = []; // graphical cell assets
self.ghostCells = []; // for ghost preview
self.isDragging = false;
self.gridX = null; // grid position if placed
self.gridY = null;
// Set up block with shape and color
self.setup = function (shape, color) {
self.shape = shape;
self.color = color;
// Remove old cells
for (var i = 0; i < self.cells.length; ++i) self.removeChild(self.cells[i]);
self.cells = [];
// Add new cells
for (var i = 0; i < shape.cells.length; ++i) {
var c = shape.cells[i];
var cell = self.attachAsset(color, {
anchorX: 0.5,
anchorY: 0.5,
x: c[0] * self.cellSize,
y: c[1] * self.cellSize
});
self.cells.push(cell);
}
// Center anchor
var w = shape.size[0] * self.cellSize,
h = shape.size[1] * self.cellSize;
self.pivot.x = w / 2 - self.cellSize / 2;
self.pivot.y = h / 2 - self.cellSize / 2;
};
// Show ghost preview at given grid position
self.showGhost = function (gridX, gridY, grid) {
self.hideGhost();
for (var i = 0; i < self.shape.cells.length; ++i) {
var c = self.shape.cells[i];
var gx = gridX + c[0],
gy = gridY + c[1];
if (gx < 0 || gx >= grid.cols || gy < 0 || gy >= grid.rows) continue;
var ghost = LK.getAsset(self.color, {
anchorX: 0.5,
anchorY: 0.5,
x: grid.gridOriginX + gx * self.cellSize + self.cellSize / 2,
y: grid.gridOriginY + gy * self.cellSize + self.cellSize / 2,
alpha: 0.4
});
self.ghostCells.push(ghost);
grid.addChild(ghost);
}
};
self.hideGhost = function () {
for (var i = 0; i < self.ghostCells.length; ++i) {
if (self.ghostCells[i].parent) self.ghostCells[i].parent.removeChild(self.ghostCells[i]);
}
self.ghostCells = [];
};
// Animate block on placement
self.animatePlace = function () {
for (var i = 0; i < self.cells.length; ++i) {
var cell = self.cells[i];
cell.scaleX = 1.2;
cell.scaleY = 1.2;
tween(cell, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
};
return self;
});
// Grid class: the main play area
var Grid = Container.expand(function () {
var self = Container.call(this);
self.rows = 9;
self.cols = 9;
self.cellSize = 120;
self.grid = []; // 2D array: grid[y][x] = {block: Block, color: assetId}
self.cellNodes = []; // graphical cell backgrounds
self.gridOriginX = 0;
self.gridOriginY = 0;
// Set up grid
self.setup = function () {
// Center grid
var totalW = self.cols * self.cellSize;
var totalH = self.rows * self.cellSize;
self.gridOriginX = Math.floor((2048 - totalW) / 2);
self.gridOriginY = Math.floor((2732 - totalH) / 2);
// Draw cells
for (var y = 0; y < self.rows; ++y) {
self.grid[y] = [];
self.cellNodes[y] = [];
for (var x = 0; x < self.cols; ++x) {
self.grid[y][x] = null;
var cell = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
x: self.gridOriginX + x * self.cellSize + self.cellSize / 2,
y: self.gridOriginY + y * self.cellSize + self.cellSize / 2
});
self.cellNodes[y][x] = cell;
}
}
};
// Check if a block can be placed at gridX,gridY
self.canPlace = function (block, gridX, gridY) {
for (var i = 0; i < block.shape.cells.length; ++i) {
var c = block.shape.cells[i];
var x = gridX + c[0],
y = gridY + c[1];
if (x < 0 || x >= self.cols || y < 0 || y >= self.rows) return false;
if (self.grid[y][x]) return false;
}
return true;
};
// Place a block at gridX,gridY
self.placeBlock = function (block, gridX, gridY) {
for (var i = 0; i < block.shape.cells.length; ++i) {
var c = block.shape.cells[i];
var x = gridX + c[0],
y = gridY + c[1];
self.grid[y][x] = {
color: block.color
};
// Animate cell
var cell = self.cellNodes[y][x];
cell.scaleX = 1.2;
cell.scaleY = 1.2;
cell.tint = block.color;
tween(cell, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
};
// Clear full rows/columns, return number of cleared lines
self.clearLines = function () {
var cleared = 0;
var toClearRows = [];
var toClearCols = [];
// Check rows
for (var y = 0; y < self.rows; ++y) {
var full = true;
for (var x = 0; x < self.cols; ++x) {
if (!self.grid[y][x]) {
full = false;
break;
}
}
if (full) toClearRows.push(y);
}
// Check columns
for (var x = 0; x < self.cols; ++x) {
var full = true;
for (var y = 0; y < self.rows; ++y) {
if (!self.grid[y][x]) {
full = false;
break;
}
}
if (full) toClearCols.push(x);
}
// Clear rows
for (var i = 0; i < toClearRows.length; ++i) {
var y = toClearRows[i];
for (var x = 0; x < self.cols; ++x) {
self.grid[y][x] = null;
var cell = self.cellNodes[y][x];
cell.tint = 0xe0e0e0;
// Animate
cell.alpha = 0.2;
tween(cell, {
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
cleared++;
}
// Clear columns
for (var i = 0; i < toClearCols.length; ++i) {
var x = toClearCols[i];
for (var y = 0; y < self.rows; ++y) {
self.grid[y][x] = null;
var cell = self.cellNodes[y][x];
cell.tint = 0xe0e0e0;
cell.alpha = 0.2;
tween(cell, {
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
cleared++;
}
return cleared;
};
// Check if any of the given blocks can be placed anywhere
self.anyValidPlacement = function (blocks) {
for (var b = 0; b < blocks.length; ++b) {
var block = blocks[b];
for (var y = 0; y <= self.rows - block.shape.size[1]; ++y) {
for (var x = 0; x <= self.cols - block.shape.size[0]; ++x) {
if (self.canPlace(block, x, y)) return true;
}
}
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffffff
});
/****
* Game Code
****/
// Block shapes definition
/*
We use only shapes for blocks and grid cells. Each block color is a unique asset.
Block shapes: 1x1, 1x2, 2x1, 2x2, 1x3, 3x1, L-shape (2x2 with one missing), etc.
Colors: blue, red, green, yellow, purple, orange.
Grid cell: light gray.
*/
// --- Game variables ---
var BLOCK_SHAPES = [
// Each shape: {cells: [[x,y],...], size: [w,h]}
{
cells: [[0, 0]],
size: [1, 1]
},
// single
{
cells: [[0, 0], [1, 0]],
size: [2, 1]
},
// 1x2 horizontal
{
cells: [[0, 0], [0, 1]],
size: [1, 2]
},
// 2x1 vertical
{
cells: [[0, 0], [1, 0], [0, 1], [1, 1]],
size: [2, 2]
},
// 2x2
{
cells: [[0, 0], [1, 0], [2, 0]],
size: [3, 1]
},
// 1x3 horizontal
{
cells: [[0, 0], [0, 1], [0, 2]],
size: [1, 3]
},
// 3x1 vertical
{
cells: [[0, 0], [1, 0], [0, 1]],
size: [2, 2]
},
// L-shape (top-left)
{
cells: [[1, 0], [0, 1], [1, 1]],
size: [2, 2]
},
// L-shape (top-right)
{
cells: [[0, 0], [1, 0], [1, 1]],
size: [2, 2]
},
// L-shape (bottom-right)
{
cells: [[0, 0], [0, 1], [1, 1]],
size: [2, 2]
} // L-shape (bottom-left)
];
// Block colors
var BLOCK_COLORS = ['block_blue', 'block_red', 'block_green', 'block_yellow', 'block_purple', 'block_orange'];
// Utility: pick random element from array
function randArr(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
var grid = new Grid();
grid.setup();
game.addChild(grid);
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Block tray: 3 blocks to choose from
var trayBlocks = [];
var trayY = 2732 - 200;
var trayX0 = 2048 / 2 - 2 * 180;
var traySpacing = 360;
// Drag state
var dragBlock = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Helper: create a new random block
function createRandomBlock() {
var block = new Block();
var shape = randArr(BLOCK_SHAPES);
var color = randArr(BLOCK_COLORS);
block.setup(shape, color);
return block;
}
// Helper: refill tray with up to 3 blocks
function refillTray() {
// Remove old blocks
for (var i = 0; i < trayBlocks.length; ++i) {
if (trayBlocks[i].parent) trayBlocks[i].parent.removeChild(trayBlocks[i]);
}
trayBlocks = [];
for (var i = 0; i < 3; ++i) {
var block = createRandomBlock();
block.x = trayX0 + i * traySpacing;
block.y = trayY;
block.scaleX = block.scaleY = 1.1;
trayBlocks.push(block);
game.addChild(block);
}
}
// Helper: update score display
function updateScore(val) {
score = val;
scoreTxt.setText(score);
}
// Helper: get grid cell under (x, y) in game coordinates
function getGridCellAt(x, y) {
var gx = Math.floor((x - grid.gridOriginX) / grid.cellSize);
var gy = Math.floor((y - grid.gridOriginY) / grid.cellSize);
if (gx < 0 || gx >= grid.cols || gy < 0 || gy >= grid.rows) return null;
return {
x: gx,
y: gy
};
}
// Helper: snap block to tray
function snapBlockToTray(block) {
var idx = trayBlocks.indexOf(block);
if (idx >= 0) {
block.x = trayX0 + idx * traySpacing;
block.y = trayY;
block.scaleX = block.scaleY = 1.1;
block.zIndex = 0;
}
}
// --- Input handlers ---
// Find block in tray under pointer
function blockUnderPointer(x, y) {
for (var i = 0; i < trayBlocks.length; ++i) {
var block = trayBlocks[i];
// Check bounding box
var bx = block.x - block.pivot.x * block.scaleX;
var by = block.y - block.pivot.y * block.scaleY;
var bw = block.shape.size[0] * block.cellSize * block.scaleX;
var bh = block.shape.size[1] * block.cellSize * block.scaleY;
if (x >= bx && x <= bx + bw && y >= by && y <= by + bh) {
return block;
}
}
return null;
}
// Drag start
game.down = function (x, y, obj) {
if (dragBlock) return;
var block = blockUnderPointer(x, y);
if (block) {
dragBlock = block;
dragBlock.isDragging = true;
dragBlock.zIndex = 100;
dragOffsetX = x - dragBlock.x;
dragOffsetY = y - dragBlock.y;
// Animate up
tween(dragBlock, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 80,
easing: tween.easeOut
});
}
};
// Drag move
game.move = function (x, y, obj) {
if (!dragBlock) return;
dragBlock.x = x - dragOffsetX;
dragBlock.y = y - dragOffsetY;
// Show ghost preview if over grid
dragBlock.hideGhost();
var cell = getGridCellAt(x, y);
if (cell) {
var can = grid.canPlace(dragBlock, cell.x, cell.y);
if (can) {
dragBlock.showGhost(cell.x, cell.y, grid);
}
}
};
// Drag end
game.up = function (x, y, obj) {
if (!dragBlock) return;
var cell = getGridCellAt(x, y);
var placed = false;
if (cell && grid.canPlace(dragBlock, cell.x, cell.y)) {
// Place block
grid.placeBlock(dragBlock, cell.x, cell.y);
dragBlock.animatePlace();
dragBlock.hideGhost();
if (dragBlock.parent) dragBlock.parent.removeChild(dragBlock);
var idx = trayBlocks.indexOf(dragBlock);
if (idx >= 0) trayBlocks.splice(idx, 1);
LK.getSound('place').play();
// Clear lines
var cleared = grid.clearLines();
if (cleared > 0) {
updateScore(score + cleared * 10);
LK.getSound('clear').play();
} else {
updateScore(score + 1);
}
placed = true;
// If tray empty, refill
if (trayBlocks.length === 0) {
refillTray();
}
// Check for game over
if (!grid.anyValidPlacement(trayBlocks)) {
LK.getSound('fail').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
if (!placed) {
// Snap back to tray
snapBlockToTray(dragBlock);
dragBlock.hideGhost();
}
// Animate down
tween(dragBlock, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut
});
dragBlock.isDragging = false;
dragBlock = null;
};
// --- Game update loop ---
game.update = function () {
// No per-frame logic needed for now
};
// --- Start game ---
updateScore(0);
refillTray(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,485 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Block class: a draggable block with a given shape and color
+var Block = Container.expand(function () {
+ var self = Container.call(this);
+ // Properties
+ self.shape = null; // {cells, size}
+ self.color = null; // asset id
+ self.cellSize = 120;
+ self.cells = []; // graphical cell assets
+ self.ghostCells = []; // for ghost preview
+ self.isDragging = false;
+ self.gridX = null; // grid position if placed
+ self.gridY = null;
+ // Set up block with shape and color
+ self.setup = function (shape, color) {
+ self.shape = shape;
+ self.color = color;
+ // Remove old cells
+ for (var i = 0; i < self.cells.length; ++i) self.removeChild(self.cells[i]);
+ self.cells = [];
+ // Add new cells
+ for (var i = 0; i < shape.cells.length; ++i) {
+ var c = shape.cells[i];
+ var cell = self.attachAsset(color, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: c[0] * self.cellSize,
+ y: c[1] * self.cellSize
+ });
+ self.cells.push(cell);
+ }
+ // Center anchor
+ var w = shape.size[0] * self.cellSize,
+ h = shape.size[1] * self.cellSize;
+ self.pivot.x = w / 2 - self.cellSize / 2;
+ self.pivot.y = h / 2 - self.cellSize / 2;
+ };
+ // Show ghost preview at given grid position
+ self.showGhost = function (gridX, gridY, grid) {
+ self.hideGhost();
+ for (var i = 0; i < self.shape.cells.length; ++i) {
+ var c = self.shape.cells[i];
+ var gx = gridX + c[0],
+ gy = gridY + c[1];
+ if (gx < 0 || gx >= grid.cols || gy < 0 || gy >= grid.rows) continue;
+ var ghost = LK.getAsset(self.color, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: grid.gridOriginX + gx * self.cellSize + self.cellSize / 2,
+ y: grid.gridOriginY + gy * self.cellSize + self.cellSize / 2,
+ alpha: 0.4
+ });
+ self.ghostCells.push(ghost);
+ grid.addChild(ghost);
+ }
+ };
+ self.hideGhost = function () {
+ for (var i = 0; i < self.ghostCells.length; ++i) {
+ if (self.ghostCells[i].parent) self.ghostCells[i].parent.removeChild(self.ghostCells[i]);
+ }
+ self.ghostCells = [];
+ };
+ // Animate block on placement
+ self.animatePlace = function () {
+ for (var i = 0; i < self.cells.length; ++i) {
+ var cell = self.cells[i];
+ cell.scaleX = 1.2;
+ cell.scaleY = 1.2;
+ tween(cell, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 120,
+ easing: tween.easeOut
+ });
+ }
+ };
+ return self;
+});
+// Grid class: the main play area
+var Grid = Container.expand(function () {
+ var self = Container.call(this);
+ self.rows = 9;
+ self.cols = 9;
+ self.cellSize = 120;
+ self.grid = []; // 2D array: grid[y][x] = {block: Block, color: assetId}
+ self.cellNodes = []; // graphical cell backgrounds
+ self.gridOriginX = 0;
+ self.gridOriginY = 0;
+ // Set up grid
+ self.setup = function () {
+ // Center grid
+ var totalW = self.cols * self.cellSize;
+ var totalH = self.rows * self.cellSize;
+ self.gridOriginX = Math.floor((2048 - totalW) / 2);
+ self.gridOriginY = Math.floor((2732 - totalH) / 2);
+ // Draw cells
+ for (var y = 0; y < self.rows; ++y) {
+ self.grid[y] = [];
+ self.cellNodes[y] = [];
+ for (var x = 0; x < self.cols; ++x) {
+ self.grid[y][x] = null;
+ var cell = self.attachAsset('cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: self.gridOriginX + x * self.cellSize + self.cellSize / 2,
+ y: self.gridOriginY + y * self.cellSize + self.cellSize / 2
+ });
+ self.cellNodes[y][x] = cell;
+ }
+ }
+ };
+ // Check if a block can be placed at gridX,gridY
+ self.canPlace = function (block, gridX, gridY) {
+ for (var i = 0; i < block.shape.cells.length; ++i) {
+ var c = block.shape.cells[i];
+ var x = gridX + c[0],
+ y = gridY + c[1];
+ if (x < 0 || x >= self.cols || y < 0 || y >= self.rows) return false;
+ if (self.grid[y][x]) return false;
+ }
+ return true;
+ };
+ // Place a block at gridX,gridY
+ self.placeBlock = function (block, gridX, gridY) {
+ for (var i = 0; i < block.shape.cells.length; ++i) {
+ var c = block.shape.cells[i];
+ var x = gridX + c[0],
+ y = gridY + c[1];
+ self.grid[y][x] = {
+ color: block.color
+ };
+ // Animate cell
+ var cell = self.cellNodes[y][x];
+ cell.scaleX = 1.2;
+ cell.scaleY = 1.2;
+ cell.tint = block.color;
+ tween(cell, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 120,
+ easing: tween.easeOut
+ });
+ }
+ };
+ // Clear full rows/columns, return number of cleared lines
+ self.clearLines = function () {
+ var cleared = 0;
+ var toClearRows = [];
+ var toClearCols = [];
+ // Check rows
+ for (var y = 0; y < self.rows; ++y) {
+ var full = true;
+ for (var x = 0; x < self.cols; ++x) {
+ if (!self.grid[y][x]) {
+ full = false;
+ break;
+ }
+ }
+ if (full) toClearRows.push(y);
+ }
+ // Check columns
+ for (var x = 0; x < self.cols; ++x) {
+ var full = true;
+ for (var y = 0; y < self.rows; ++y) {
+ if (!self.grid[y][x]) {
+ full = false;
+ break;
+ }
+ }
+ if (full) toClearCols.push(x);
+ }
+ // Clear rows
+ for (var i = 0; i < toClearRows.length; ++i) {
+ var y = toClearRows[i];
+ for (var x = 0; x < self.cols; ++x) {
+ self.grid[y][x] = null;
+ var cell = self.cellNodes[y][x];
+ cell.tint = 0xe0e0e0;
+ // Animate
+ cell.alpha = 0.2;
+ tween(cell, {
+ alpha: 1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ }
+ cleared++;
+ }
+ // Clear columns
+ for (var i = 0; i < toClearCols.length; ++i) {
+ var x = toClearCols[i];
+ for (var y = 0; y < self.rows; ++y) {
+ self.grid[y][x] = null;
+ var cell = self.cellNodes[y][x];
+ cell.tint = 0xe0e0e0;
+ cell.alpha = 0.2;
+ tween(cell, {
+ alpha: 1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ }
+ cleared++;
+ }
+ return cleared;
+ };
+ // Check if any of the given blocks can be placed anywhere
+ self.anyValidPlacement = function (blocks) {
+ for (var b = 0; b < blocks.length; ++b) {
+ var block = blocks[b];
+ for (var y = 0; y <= self.rows - block.shape.size[1]; ++y) {
+ for (var x = 0; x <= self.cols - block.shape.size[0]; ++x) {
+ if (self.canPlace(block, x, y)) return true;
+ }
+ }
+ }
+ return false;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0xffffff
+});
+
+/****
+* Game Code
+****/
+// Block shapes definition
+/*
+We use only shapes for blocks and grid cells. Each block color is a unique asset.
+Block shapes: 1x1, 1x2, 2x1, 2x2, 1x3, 3x1, L-shape (2x2 with one missing), etc.
+Colors: blue, red, green, yellow, purple, orange.
+Grid cell: light gray.
+*/
+// --- Game variables ---
+var BLOCK_SHAPES = [
+// Each shape: {cells: [[x,y],...], size: [w,h]}
+{
+ cells: [[0, 0]],
+ size: [1, 1]
+},
+// single
+{
+ cells: [[0, 0], [1, 0]],
+ size: [2, 1]
+},
+// 1x2 horizontal
+{
+ cells: [[0, 0], [0, 1]],
+ size: [1, 2]
+},
+// 2x1 vertical
+{
+ cells: [[0, 0], [1, 0], [0, 1], [1, 1]],
+ size: [2, 2]
+},
+// 2x2
+{
+ cells: [[0, 0], [1, 0], [2, 0]],
+ size: [3, 1]
+},
+// 1x3 horizontal
+{
+ cells: [[0, 0], [0, 1], [0, 2]],
+ size: [1, 3]
+},
+// 3x1 vertical
+{
+ cells: [[0, 0], [1, 0], [0, 1]],
+ size: [2, 2]
+},
+// L-shape (top-left)
+{
+ cells: [[1, 0], [0, 1], [1, 1]],
+ size: [2, 2]
+},
+// L-shape (top-right)
+{
+ cells: [[0, 0], [1, 0], [1, 1]],
+ size: [2, 2]
+},
+// L-shape (bottom-right)
+{
+ cells: [[0, 0], [0, 1], [1, 1]],
+ size: [2, 2]
+} // L-shape (bottom-left)
+];
+// Block colors
+var BLOCK_COLORS = ['block_blue', 'block_red', 'block_green', 'block_yellow', 'block_purple', 'block_orange'];
+// Utility: pick random element from array
+function randArr(arr) {
+ return arr[Math.floor(Math.random() * arr.length)];
+}
+var grid = new Grid();
+grid.setup();
+game.addChild(grid);
+var score = 0;
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: 0x222222
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Block tray: 3 blocks to choose from
+var trayBlocks = [];
+var trayY = 2732 - 200;
+var trayX0 = 2048 / 2 - 2 * 180;
+var traySpacing = 360;
+// Drag state
+var dragBlock = null;
+var dragOffsetX = 0;
+var dragOffsetY = 0;
+// Helper: create a new random block
+function createRandomBlock() {
+ var block = new Block();
+ var shape = randArr(BLOCK_SHAPES);
+ var color = randArr(BLOCK_COLORS);
+ block.setup(shape, color);
+ return block;
+}
+// Helper: refill tray with up to 3 blocks
+function refillTray() {
+ // Remove old blocks
+ for (var i = 0; i < trayBlocks.length; ++i) {
+ if (trayBlocks[i].parent) trayBlocks[i].parent.removeChild(trayBlocks[i]);
+ }
+ trayBlocks = [];
+ for (var i = 0; i < 3; ++i) {
+ var block = createRandomBlock();
+ block.x = trayX0 + i * traySpacing;
+ block.y = trayY;
+ block.scaleX = block.scaleY = 1.1;
+ trayBlocks.push(block);
+ game.addChild(block);
+ }
+}
+// Helper: update score display
+function updateScore(val) {
+ score = val;
+ scoreTxt.setText(score);
+}
+// Helper: get grid cell under (x, y) in game coordinates
+function getGridCellAt(x, y) {
+ var gx = Math.floor((x - grid.gridOriginX) / grid.cellSize);
+ var gy = Math.floor((y - grid.gridOriginY) / grid.cellSize);
+ if (gx < 0 || gx >= grid.cols || gy < 0 || gy >= grid.rows) return null;
+ return {
+ x: gx,
+ y: gy
+ };
+}
+// Helper: snap block to tray
+function snapBlockToTray(block) {
+ var idx = trayBlocks.indexOf(block);
+ if (idx >= 0) {
+ block.x = trayX0 + idx * traySpacing;
+ block.y = trayY;
+ block.scaleX = block.scaleY = 1.1;
+ block.zIndex = 0;
+ }
+}
+// --- Input handlers ---
+// Find block in tray under pointer
+function blockUnderPointer(x, y) {
+ for (var i = 0; i < trayBlocks.length; ++i) {
+ var block = trayBlocks[i];
+ // Check bounding box
+ var bx = block.x - block.pivot.x * block.scaleX;
+ var by = block.y - block.pivot.y * block.scaleY;
+ var bw = block.shape.size[0] * block.cellSize * block.scaleX;
+ var bh = block.shape.size[1] * block.cellSize * block.scaleY;
+ if (x >= bx && x <= bx + bw && y >= by && y <= by + bh) {
+ return block;
+ }
+ }
+ return null;
+}
+// Drag start
+game.down = function (x, y, obj) {
+ if (dragBlock) return;
+ var block = blockUnderPointer(x, y);
+ if (block) {
+ dragBlock = block;
+ dragBlock.isDragging = true;
+ dragBlock.zIndex = 100;
+ dragOffsetX = x - dragBlock.x;
+ dragOffsetY = y - dragBlock.y;
+ // Animate up
+ tween(dragBlock, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 80,
+ easing: tween.easeOut
+ });
+ }
+};
+// Drag move
+game.move = function (x, y, obj) {
+ if (!dragBlock) return;
+ dragBlock.x = x - dragOffsetX;
+ dragBlock.y = y - dragOffsetY;
+ // Show ghost preview if over grid
+ dragBlock.hideGhost();
+ var cell = getGridCellAt(x, y);
+ if (cell) {
+ var can = grid.canPlace(dragBlock, cell.x, cell.y);
+ if (can) {
+ dragBlock.showGhost(cell.x, cell.y, grid);
+ }
+ }
+};
+// Drag end
+game.up = function (x, y, obj) {
+ if (!dragBlock) return;
+ var cell = getGridCellAt(x, y);
+ var placed = false;
+ if (cell && grid.canPlace(dragBlock, cell.x, cell.y)) {
+ // Place block
+ grid.placeBlock(dragBlock, cell.x, cell.y);
+ dragBlock.animatePlace();
+ dragBlock.hideGhost();
+ if (dragBlock.parent) dragBlock.parent.removeChild(dragBlock);
+ var idx = trayBlocks.indexOf(dragBlock);
+ if (idx >= 0) trayBlocks.splice(idx, 1);
+ LK.getSound('place').play();
+ // Clear lines
+ var cleared = grid.clearLines();
+ if (cleared > 0) {
+ updateScore(score + cleared * 10);
+ LK.getSound('clear').play();
+ } else {
+ updateScore(score + 1);
+ }
+ placed = true;
+ // If tray empty, refill
+ if (trayBlocks.length === 0) {
+ refillTray();
+ }
+ // Check for game over
+ if (!grid.anyValidPlacement(trayBlocks)) {
+ LK.getSound('fail').play();
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ }
+ if (!placed) {
+ // Snap back to tray
+ snapBlockToTray(dragBlock);
+ dragBlock.hideGhost();
+ }
+ // Animate down
+ tween(dragBlock, {
+ scaleX: 1.1,
+ scaleY: 1.1
+ }, {
+ duration: 80,
+ easing: tween.easeOut
+ });
+ dragBlock.isDragging = false;
+ dragBlock = null;
+};
+// --- Game update loop ---
+game.update = function () {
+ // No per-frame logic needed for now
+};
+// --- Start game ---
+updateScore(0);
+refillTray();
\ No newline at end of file