/****
* Classes
****/
var Block = Container.expand(function (board) {
var self = Container.call(this);
var hsvToRgb = function hsvToRgb(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v, g = t, b = p;
break;
case 1:
r = q, g = v, b = p;
break;
case 2:
r = p, g = v, b = t;
break;
case 3:
r = p, g = q, b = v;
break;
case 4:
r = t, g = p, b = v;
break;
case 5:
r = v, g = p, b = q;
break;
}
return (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255);
};
var ShapeTypes = {
SINGLE: [[1]],
TRI: [[1, 1, 1]],
QUAD: [[1, 1, 1, 1]],
LSHAPE: [[1, 0, 0], [1, 0, 0], [1, 1, 1]],
BLOCK: [[1, 1], [1, 1]],
SMALLLSHAPE: [[1, 0], [1, 1]]
};
var shapes = Object.values(ShapeTypes);
var offset = Math.floor(Math.random() * shapes.length);
self.shape = shapes[offset];
var hue = offset % shapes.length / shapes.length;
self.color = hsvToRgb(hue, 0.6, 1);
self.rotateShapeRandomly = function () {
var rotations = Math.floor(Math.random() * 4);
for (var r = 0; r < rotations; r++) {
self.shape = self.shape[0].map(function (val, index) {
return self.shape.map(function (row) {
return row[index];
}).reverse();
});
}
};
self.rotateShapeRandomly();
self.blocks = [];
var background = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.alpha = 0;
var blockSize = 160;
background.width = 4 * blockSize;
background.height = 4 * blockSize;
self.addChild(background);
self.offsetX = 0;
self.offsetY = 0;
var blockOffsetX = (background.width / 2 - self.shape[0].length * blockSize) / 2 - blockSize / 2;
var blockOffsetY = (background.height / 2 - self.shape.length * blockSize) / 2 - blockSize / 2;
for (var i = 0; i < self.shape.length; i++) {
for (var j = 0; j < self.shape[i].length; j++) {
if (self.shape[i][j] === 1) {
var block = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
block.tint = self.color;
block.width = blockSize;
block.height = blockSize;
block.x = j * blockSize + blockOffsetX;
block.y = i * blockSize + blockOffsetY;
self.blocks.push(block);
self.addChild(block);
}
}
}
self.startX = 0;
self.startY = 0;
self.moveTowardsHomePosition = function () {
var dx = self.startX - self.x;
var dy = self.startY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 1) {
self.x += dx * 0.3;
self.y += dy * 0.3;
} else {
self.x = self.startX;
self.y = self.startY;
}
};
var currentX = 0;
var currentY = 0;
self.moveToDragTarget = function () {
var ox = -this.targetX;
var oy = (LK.is.mobile ? 400 : 0) - this.targetY;
this.targetX += ox / 5;
this.targetY += oy / 5;
this.x = currentX - this.targetX;
this.y = currentY - this.targetY;
};
self._move_migrated = function (x, y) {
currentX = x;
currentY = y;
self.x = x - this.targetX;
self.y = y - this.targetY;
};
self.setStartPosition = function (x, y) {
self.startX = x;
self.startY = y;
};
self.getOverlappingCells = function () {
var cells = [];
var boardPos = {
x: -board.x + self.x + 160 * 4 + blockOffsetX + 160,
y: -board.y + self.y + 160 * 4 + blockOffsetY + 160
};
var startX = Math.floor(boardPos.x / 160);
var startY = Math.floor(boardPos.y / 160);
for (var i = 0; i < self.shape.length; i++) {
for (var j = 0; j < self.shape[i].length; j++) {
if (self.shape[i][j] === 1) {
var cell = board.grid && board.grid[startY + i] && board.grid[startY + i][startX + j];
if (cell && !cell.filled) {
cells.push(cell);
} else {
return null;
}
}
}
}
return cells;
};
self.showOverlap = function () {
var cells = self.getOverlappingCells();
if (cells) {
for (var a = 0; a < cells.length; a++) {
var cell = cells[a];
cell.setTint(self.color);
// Add gentle glow effect by scaling up slightly and fading back
if (typeof tween !== "undefined") {
cell.scale.x = cell.scale.y = 1.12;
tween.to(cell.scale, {
x: 1,
y: 1
}, 180, {
easing: tween.Easing.Cubic.Out
});
// Gentle highlight pulse on cell background
if (cell.children && cell.children.length > 0) {
var cellBg = cell.children[0];
if (cellBg && cellBg.alpha !== undefined) {
var origAlpha = cellBg.alpha;
cellBg.alpha = 1;
tween.to(cellBg, {
alpha: origAlpha
}, 180, {
easing: tween.Easing.Cubic.Out
});
}
}
}
}
}
};
self.rotateShapeRandomly = function () {
var rotations = Math.floor(Math.random() * 4);
for (var r = 0; r < rotations; r++) {
self.shape = self.shape[0].map(function (val, index) {
return self.shape.map(function (row) {
return row[index];
}).reverse();
});
}
};
});
var Board = Container.expand(function () {
var self = Container.call(this);
self.particles = [];
Board.prototype.spawnParticles = function (x, y, tint) {
for (var i = 0; i < 10; i++) {
var particle = new Particle(tint);
particle.x = x;
particle.y = y;
this.particles.push(particle);
this.addChild(particle);
}
};
var background = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.y = -20;
background.alpha = .4;
background.blendMode = 1;
self.grid = new Array(10).fill(null).map(function () {
return new Array(10).fill(null);
});
var size = 158;
var totalWidth = 10 * size;
var totalHeight = 10 * size;
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
var cell = new Cell();
cell.x = i * size - totalWidth / 2 + size / 2;
cell.y = j * size - totalHeight / 2 + size / 2;
self.grid[j][i] = cell;
self.addChild(cell);
}
}
self.removeTint = function () {
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (!self.grid[i][j].filled) {
self.grid[i][j].setTint(0xffffff);
}
}
}
};
self.checkLines = function () {
var rowsRemoved = 0;
for (var i = 0; i < 10; i++) {
var rowFilled = true;
var colFilled = true;
for (var j = 0; j < 10; j++) {
if (!self.grid[i][j].filled) {
rowFilled = false;
}
if (!self.grid[j][i].filled) {
colFilled = false;
}
}
if (rowFilled || colFilled) {
// Play disruption sound when a line is completed
LK.getSound('disruption').play();
rowsRemoved += (rowFilled ? 1 : 0) + (colFilled ? 1 : 0);
// Gentle shake animation for board
if (typeof tween !== "undefined") {
var origX = self.x,
origY = self.y;
tween.to(self, {
x: origX + 20
}, 60).onComplete(function () {
tween.to(self, {
x: origX - 20
}, 60).onComplete(function () {
tween.to(self, {
x: origX
}, 60);
});
});
}
for (var j = 0; j < 10; j++) {
if (rowFilled) {
self.grid[i][j].setFill(false);
self.spawnParticles(self.grid[i][j].x, self.grid[i][j].y, self.grid[i][j].getTint());
}
if (colFilled) {
self.grid[j][i].setFill(false);
self.spawnParticles(self.grid[j][i].x, self.grid[j][i].y, self.grid[j][i].getTint());
}
}
// Slide blocks down if a row was completed
if (rowFilled) {
for (var row = i; row > 0; row--) {
for (var col = 0; col < 10; col++) {
self.grid[row][col].setFill(self.grid[row - 1][col].filled);
self.grid[row][col].setTint(self.grid[row - 1][col].getTint());
}
}
// Clear the top row
for (var col = 0; col < 10; col++) {
self.grid[0][col].setFill(false);
self.grid[0][col].setTint(0xffffff);
}
}
}
}
return rowsRemoved;
};
self.tick = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
if (particle) {
particle.tick();
if (particle.alpha <= 0) {
self.particles.splice(i, 1);
}
}
}
};
self.placeBlock = function () {};
});
var Cell = Container.expand(function () {
var self = Container.call(this);
self.filled = false;
var empty = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
empty.alpha = .8;
var filled = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
empty.y = 2;
self.setFill = function (isFilled) {
self.filled = isFilled;
empty.visible = !self.filled;
filled.visible = self.filled;
};
self.getTint = function () {
return filled.tint;
};
self.setTint = function (tint) {
empty.tint = filled.tint = tint;
};
self.setFill(false);
});
var Particle = Container.expand(function (tint) {
var self = Container.call(this);
self.tint = tint;
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particleGraphics.rotation = Math.random() * Math.PI * 2;
particleGraphics.tint = self.tint;
self.vx = Math.random() * 4 - 2;
self.vy = Math.random() * 4 - 2;
self.alpha = 1;
self.lifetime = 60;
self.tick = function () {
self.x += self.vx;
self.y += self.vy;
self.alpha -= 1 / self.lifetime;
if (self.alpha <= 0) {
self.destroy();
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var gameBackground = game.attachAsset('gameBackground', {
anchorX: 0.5,
anchorY: 0.5
});
gameBackground.x = 2048 / 2;
gameBackground.y = 2732 / 2;
// Gentle fade-in for background
if (typeof tween !== "undefined") {
gameBackground.alpha = 0;
tween.to(gameBackground, {
alpha: 1
}, 900, {
easing: tween.Easing.Cubic.Out
});
}
var tilesBackground = game.attachAsset('tileBackground', {
anchorX: 0.5,
anchorY: 0.5
});
tilesBackground.y = -20;
tilesBackground.alpha = .4;
tilesBackground.blendMode = 1;
var blocks = [];
var dragTarget;
var board = game.addChild(new Board());
board.x = 2048 / 2;
board.y = 2732 / 2 - 250 + 30;
tilesBackground.x = 2048 / 2;
tilesBackground.y = 2732 - 300;
var targetOffset;
game.createBlock = function (index) {
var block = new Block(board);
// Set initial position above the screen
block.x = 2048 / 2 + (index - 1) * (block.width + 30);
block.y = -block.height;
// Set the home position where the block should land
var homeY = 2732 - block.height / 2 - 30;
block.setStartPosition(block.x, homeY);
blocks.push(block);
game.addChild(block);
// Animate the block falling down to its home position
if (typeof tween !== "undefined") {
tween.to(block, {
y: homeY
}, 700, {
easing: tween.Easing.Cubic.Out
});
} else {
block.y = homeY;
}
// Animate block pop-in
if (typeof tween !== "undefined") {
block.scale.x = block.scale.y = 0.1;
tween.to(block.scale, {
x: 1,
y: 1
}, 250, {
easing: tween.Easing.Back.Out
});
}
block.on('down', function (x, y, obj) {
dragTarget = this;
var pos = this.toLocal(obj.global);
var targetPos = game.toLocal(obj.global);
this.targetX = pos.x;
this.targetY = pos.y;
dragTarget._move_migrated(targetPos.x, targetPos.y);
});
};
game.on('move', function (x, y, obj) {
if (dragTarget) {
board.removeTint();
var pos = game.toLocal(obj.global);
dragTarget._move_migrated(pos.x, pos.y);
dragTarget.showOverlap();
}
});
game.on('up', function (x, y, obj) {
if (dragTarget) {
var cells = dragTarget.getOverlappingCells();
if (cells) {
for (var a = 0; a < cells.length; a++) {
cells[a].setFill(true);
cells[a].setTint(dragTarget.color);
// Always use the default filled asset for placed squares
// Add a subtle particle effect when a block is placed
if (typeof board.spawnParticles === "function") {
board.spawnParticles(cells[a].x, cells[a].y, dragTarget.color);
}
// Subtle scale pulse effect on placed cell
if (typeof tween !== "undefined") {
cells[a].scale.x = cells[a].scale.y = 1.2;
tween.to(cells[a].scale, {
x: 1,
y: 1
}, 180, {
easing: tween.Easing.Back.Out
});
}
}
blocks[blocks.indexOf(dragTarget)] = undefined;
dragTarget.destroy();
// Gentle pulse on score text when a block is placed
if (typeof tween !== "undefined") {
tween.to(scoreTxt.scale, {
x: 1.15,
y: 1.15
}, 100).onComplete(function () {
tween.to(scoreTxt.scale, {
x: 1,
y: 1
}, 120);
});
}
// Soft highlight effect on board
if (typeof tween !== "undefined") {
var origAlpha = board.alpha;
board.alpha = 0.7;
tween.to(board, {
alpha: origAlpha
}, 200);
// Gentle pulse on board background
if (board.children && board.children.length > 0) {
var bg = board.children[0];
if (bg && bg.scale) {
bg.scale.x = bg.scale.y = 1.08;
tween.to(bg.scale, {
x: 1,
y: 1
}, 220, {
easing: tween.Easing.Back.Out
});
}
}
}
if (!blocks.some(function (block) {
return block;
})) {
game.createBlocks();
}
var pointsToAdd = board.checkLines();
if (pointsToAdd) {
score += Math.pow(pointsToAdd, 2) * 10;
scoreTxt.setText(score);
// Animate scoreTxt: scale up and back to normal
if (typeof tween !== "undefined") {
tween.to(scoreTxt.scale, {
x: 1.3,
y: 1.3
}, 120).onComplete(function () {
tween.to(scoreTxt.scale, {
x: 1,
y: 1
}, 180);
});
// Flash scoreTxt color
var origFill = scoreTxt.style.fill;
scoreTxt.style.fill = 0xffe066;
LK.setTimeout(function () {
scoreTxt.style.fill = origFill;
}, 200);
}
// Show combo/multiplier text if more than 1 line cleared
if (pointsToAdd > 1) {
var comboTxt = new Text2('x' + pointsToAdd, {
size: 120,
fill: 0xffa500,
font: 'Impact',
dropShadow: true,
dropShadowColor: '#2a636e'
});
comboTxt.anchor.set(.5, .5);
comboTxt.x = scoreTxt.x;
comboTxt.y = scoreTxt.y + scoreTxt.height + 30;
LK.gui.top.addChild(comboTxt);
// Gentle pop-in scale effect
if (typeof tween !== "undefined") {
comboTxt.alpha = 0;
comboTxt.scale.x = comboTxt.scale.y = 0.7;
tween.to(comboTxt, {
alpha: 1,
y: comboTxt.y - 40
}, 350, {
easing: tween.Easing.Cubic.Out
}).onComplete(function () {
tween.to(comboTxt, {
alpha: 0,
y: comboTxt.y - 40
}, 500).onComplete(function () {
comboTxt.destroy();
});
});
tween.to(comboTxt.scale, {
x: 1,
y: 1
}, 200, {
easing: tween.Easing.Back.Out
});
} else {
// fallback: just destroy after 1s
LK.setTimeout(function () {
comboTxt.destroy();
}, 1000);
}
}
}
}
board.removeTint();
dragTarget = undefined;
}
});
game.createBlocks = function () {
for (var i = 0; i < 3; i++) {
game.createBlock(i);
}
isGameOver = false;
};
var score = 0;
game.createBlocks();
// Play fragmentation music throughout the game
LK.playMusic('fragmentation', {
loop: true
});
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF,
font: 'Impact',
dropShadow: true,
dropShadowColor: '#2a636e'
});
scoreTxt.anchor.set(.5, 0);
LK.gui.top.addChild(scoreTxt);
game.isMovePossible = function () {
for (var a = 0; a < blocks.length; a++) {
if (blocks[a]) {
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (board.grid[i][j].filled) {
continue;
}
var canPlace = true;
for (var k = 0; k < blocks[a].shape.length; k++) {
for (var l = 0; l < blocks[a].shape[k].length; l++) {
if (blocks[a].shape[k][l] === 1) {
if (i + k < 0 || i + k >= 10 || j + l < 0 || j + l >= 10 || board.grid[i + k][j + l].filled) {
canPlace = false;
break;
}
}
}
if (!canPlace) {
break;
}
}
if (canPlace) {
return true;
}
}
}
}
}
return false;
};
var isGameOver = false;
LK.on('tick', function () {
board.tick();
if (!isGameOver && !game.isMovePossible()) {
isGameOver = true;
LK.effects.flashScreen(0xffffff, 1000);
LK.showGameOver();
}
for (var a = blocks.length - 1; a >= 0; a--) {
if (blocks[a]) {
if (blocks[a] != dragTarget) {
blocks[a].moveTowardsHomePosition();
// Gentle floating animation for idle blocks
if (!blocks[a].floatingPhase) blocks[a].floatingPhase = Math.random() * Math.PI * 2;
blocks[a].floatingPhase += 0.04;
var floatY = Math.sin(blocks[a].floatingPhase) * 8;
blocks[a].y = blocks[a].startY + floatY;
} else {
blocks[a].moveToDragTarget();
}
}
}
}); /****
* Classes
****/
var Block = Container.expand(function (board) {
var self = Container.call(this);
var hsvToRgb = function hsvToRgb(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v, g = t, b = p;
break;
case 1:
r = q, g = v, b = p;
break;
case 2:
r = p, g = v, b = t;
break;
case 3:
r = p, g = q, b = v;
break;
case 4:
r = t, g = p, b = v;
break;
case 5:
r = v, g = p, b = q;
break;
}
return (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255);
};
var ShapeTypes = {
SINGLE: [[1]],
TRI: [[1, 1, 1]],
QUAD: [[1, 1, 1, 1]],
LSHAPE: [[1, 0, 0], [1, 0, 0], [1, 1, 1]],
BLOCK: [[1, 1], [1, 1]],
SMALLLSHAPE: [[1, 0], [1, 1]]
};
var shapes = Object.values(ShapeTypes);
var offset = Math.floor(Math.random() * shapes.length);
self.shape = shapes[offset];
var hue = offset % shapes.length / shapes.length;
self.color = hsvToRgb(hue, 0.6, 1);
self.rotateShapeRandomly = function () {
var rotations = Math.floor(Math.random() * 4);
for (var r = 0; r < rotations; r++) {
self.shape = self.shape[0].map(function (val, index) {
return self.shape.map(function (row) {
return row[index];
}).reverse();
});
}
};
self.rotateShapeRandomly();
self.blocks = [];
var background = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.alpha = 0;
var blockSize = 160;
background.width = 4 * blockSize;
background.height = 4 * blockSize;
self.addChild(background);
self.offsetX = 0;
self.offsetY = 0;
var blockOffsetX = (background.width / 2 - self.shape[0].length * blockSize) / 2 - blockSize / 2;
var blockOffsetY = (background.height / 2 - self.shape.length * blockSize) / 2 - blockSize / 2;
for (var i = 0; i < self.shape.length; i++) {
for (var j = 0; j < self.shape[i].length; j++) {
if (self.shape[i][j] === 1) {
var block = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
block.tint = self.color;
block.width = blockSize;
block.height = blockSize;
block.x = j * blockSize + blockOffsetX;
block.y = i * blockSize + blockOffsetY;
self.blocks.push(block);
self.addChild(block);
}
}
}
self.startX = 0;
self.startY = 0;
self.moveTowardsHomePosition = function () {
var dx = self.startX - self.x;
var dy = self.startY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 1) {
self.x += dx * 0.3;
self.y += dy * 0.3;
} else {
self.x = self.startX;
self.y = self.startY;
}
};
var currentX = 0;
var currentY = 0;
self.moveToDragTarget = function () {
var ox = -this.targetX;
var oy = (LK.is.mobile ? 400 : 0) - this.targetY;
this.targetX += ox / 5;
this.targetY += oy / 5;
this.x = currentX - this.targetX;
this.y = currentY - this.targetY;
};
self._move_migrated = function (x, y) {
currentX = x;
currentY = y;
self.x = x - this.targetX;
self.y = y - this.targetY;
};
self.setStartPosition = function (x, y) {
self.startX = x;
self.startY = y;
};
self.getOverlappingCells = function () {
var cells = [];
var boardPos = {
x: -board.x + self.x + 160 * 4 + blockOffsetX + 160,
y: -board.y + self.y + 160 * 4 + blockOffsetY + 160
};
var startX = Math.floor(boardPos.x / 160);
var startY = Math.floor(boardPos.y / 160);
for (var i = 0; i < self.shape.length; i++) {
for (var j = 0; j < self.shape[i].length; j++) {
if (self.shape[i][j] === 1) {
var cell = board.grid && board.grid[startY + i] && board.grid[startY + i][startX + j];
if (cell && !cell.filled) {
cells.push(cell);
} else {
return null;
}
}
}
}
return cells;
};
self.showOverlap = function () {
var cells = self.getOverlappingCells();
if (cells) {
for (var a = 0; a < cells.length; a++) {
var cell = cells[a];
cell.setTint(self.color);
// Add gentle glow effect by scaling up slightly and fading back
if (typeof tween !== "undefined") {
cell.scale.x = cell.scale.y = 1.12;
tween.to(cell.scale, {
x: 1,
y: 1
}, 180, {
easing: tween.Easing.Cubic.Out
});
// Gentle highlight pulse on cell background
if (cell.children && cell.children.length > 0) {
var cellBg = cell.children[0];
if (cellBg && cellBg.alpha !== undefined) {
var origAlpha = cellBg.alpha;
cellBg.alpha = 1;
tween.to(cellBg, {
alpha: origAlpha
}, 180, {
easing: tween.Easing.Cubic.Out
});
}
}
}
}
}
};
self.rotateShapeRandomly = function () {
var rotations = Math.floor(Math.random() * 4);
for (var r = 0; r < rotations; r++) {
self.shape = self.shape[0].map(function (val, index) {
return self.shape.map(function (row) {
return row[index];
}).reverse();
});
}
};
});
var Board = Container.expand(function () {
var self = Container.call(this);
self.particles = [];
Board.prototype.spawnParticles = function (x, y, tint) {
for (var i = 0; i < 10; i++) {
var particle = new Particle(tint);
particle.x = x;
particle.y = y;
this.particles.push(particle);
this.addChild(particle);
}
};
var background = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.y = -20;
background.alpha = .4;
background.blendMode = 1;
self.grid = new Array(10).fill(null).map(function () {
return new Array(10).fill(null);
});
var size = 158;
var totalWidth = 10 * size;
var totalHeight = 10 * size;
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
var cell = new Cell();
cell.x = i * size - totalWidth / 2 + size / 2;
cell.y = j * size - totalHeight / 2 + size / 2;
self.grid[j][i] = cell;
self.addChild(cell);
}
}
self.removeTint = function () {
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (!self.grid[i][j].filled) {
self.grid[i][j].setTint(0xffffff);
}
}
}
};
self.checkLines = function () {
var rowsRemoved = 0;
for (var i = 0; i < 10; i++) {
var rowFilled = true;
var colFilled = true;
for (var j = 0; j < 10; j++) {
if (!self.grid[i][j].filled) {
rowFilled = false;
}
if (!self.grid[j][i].filled) {
colFilled = false;
}
}
if (rowFilled || colFilled) {
// Play disruption sound when a line is completed
LK.getSound('disruption').play();
rowsRemoved += (rowFilled ? 1 : 0) + (colFilled ? 1 : 0);
// Gentle shake animation for board
if (typeof tween !== "undefined") {
var origX = self.x,
origY = self.y;
tween.to(self, {
x: origX + 20
}, 60).onComplete(function () {
tween.to(self, {
x: origX - 20
}, 60).onComplete(function () {
tween.to(self, {
x: origX
}, 60);
});
});
}
for (var j = 0; j < 10; j++) {
if (rowFilled) {
self.grid[i][j].setFill(false);
self.spawnParticles(self.grid[i][j].x, self.grid[i][j].y, self.grid[i][j].getTint());
}
if (colFilled) {
self.grid[j][i].setFill(false);
self.spawnParticles(self.grid[j][i].x, self.grid[j][i].y, self.grid[j][i].getTint());
}
}
// Slide blocks down if a row was completed
if (rowFilled) {
for (var row = i; row > 0; row--) {
for (var col = 0; col < 10; col++) {
self.grid[row][col].setFill(self.grid[row - 1][col].filled);
self.grid[row][col].setTint(self.grid[row - 1][col].getTint());
}
}
// Clear the top row
for (var col = 0; col < 10; col++) {
self.grid[0][col].setFill(false);
self.grid[0][col].setTint(0xffffff);
}
}
}
}
return rowsRemoved;
};
self.tick = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
if (particle) {
particle.tick();
if (particle.alpha <= 0) {
self.particles.splice(i, 1);
}
}
}
};
self.placeBlock = function () {};
});
var Cell = Container.expand(function () {
var self = Container.call(this);
self.filled = false;
var empty = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
empty.alpha = .8;
var filled = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
empty.y = 2;
self.setFill = function (isFilled) {
self.filled = isFilled;
empty.visible = !self.filled;
filled.visible = self.filled;
};
self.getTint = function () {
return filled.tint;
};
self.setTint = function (tint) {
empty.tint = filled.tint = tint;
};
self.setFill(false);
});
var Particle = Container.expand(function (tint) {
var self = Container.call(this);
self.tint = tint;
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particleGraphics.rotation = Math.random() * Math.PI * 2;
particleGraphics.tint = self.tint;
self.vx = Math.random() * 4 - 2;
self.vy = Math.random() * 4 - 2;
self.alpha = 1;
self.lifetime = 60;
self.tick = function () {
self.x += self.vx;
self.y += self.vy;
self.alpha -= 1 / self.lifetime;
if (self.alpha <= 0) {
self.destroy();
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var gameBackground = game.attachAsset('gameBackground', {
anchorX: 0.5,
anchorY: 0.5
});
gameBackground.x = 2048 / 2;
gameBackground.y = 2732 / 2;
// Gentle fade-in for background
if (typeof tween !== "undefined") {
gameBackground.alpha = 0;
tween.to(gameBackground, {
alpha: 1
}, 900, {
easing: tween.Easing.Cubic.Out
});
}
var tilesBackground = game.attachAsset('tileBackground', {
anchorX: 0.5,
anchorY: 0.5
});
tilesBackground.y = -20;
tilesBackground.alpha = .4;
tilesBackground.blendMode = 1;
var blocks = [];
var dragTarget;
var board = game.addChild(new Board());
board.x = 2048 / 2;
board.y = 2732 / 2 - 250 + 30;
tilesBackground.x = 2048 / 2;
tilesBackground.y = 2732 - 300;
var targetOffset;
game.createBlock = function (index) {
var block = new Block(board);
// Set initial position above the screen
block.x = 2048 / 2 + (index - 1) * (block.width + 30);
block.y = -block.height;
// Set the home position where the block should land
var homeY = 2732 - block.height / 2 - 30;
block.setStartPosition(block.x, homeY);
blocks.push(block);
game.addChild(block);
// Animate the block falling down to its home position
if (typeof tween !== "undefined") {
tween.to(block, {
y: homeY
}, 700, {
easing: tween.Easing.Cubic.Out
});
} else {
block.y = homeY;
}
// Animate block pop-in
if (typeof tween !== "undefined") {
block.scale.x = block.scale.y = 0.1;
tween.to(block.scale, {
x: 1,
y: 1
}, 250, {
easing: tween.Easing.Back.Out
});
}
block.on('down', function (x, y, obj) {
dragTarget = this;
var pos = this.toLocal(obj.global);
var targetPos = game.toLocal(obj.global);
this.targetX = pos.x;
this.targetY = pos.y;
dragTarget._move_migrated(targetPos.x, targetPos.y);
});
};
game.on('move', function (x, y, obj) {
if (dragTarget) {
board.removeTint();
var pos = game.toLocal(obj.global);
dragTarget._move_migrated(pos.x, pos.y);
dragTarget.showOverlap();
}
});
game.on('up', function (x, y, obj) {
if (dragTarget) {
var cells = dragTarget.getOverlappingCells();
if (cells) {
for (var a = 0; a < cells.length; a++) {
cells[a].setFill(true);
cells[a].setTint(dragTarget.color);
// Always use the default filled asset for placed squares
// Add a subtle particle effect when a block is placed
if (typeof board.spawnParticles === "function") {
board.spawnParticles(cells[a].x, cells[a].y, dragTarget.color);
}
// Subtle scale pulse effect on placed cell
if (typeof tween !== "undefined") {
cells[a].scale.x = cells[a].scale.y = 1.2;
tween.to(cells[a].scale, {
x: 1,
y: 1
}, 180, {
easing: tween.Easing.Back.Out
});
}
}
blocks[blocks.indexOf(dragTarget)] = undefined;
dragTarget.destroy();
// Gentle pulse on score text when a block is placed
if (typeof tween !== "undefined") {
tween.to(scoreTxt.scale, {
x: 1.15,
y: 1.15
}, 100).onComplete(function () {
tween.to(scoreTxt.scale, {
x: 1,
y: 1
}, 120);
});
}
// Soft highlight effect on board
if (typeof tween !== "undefined") {
var origAlpha = board.alpha;
board.alpha = 0.7;
tween.to(board, {
alpha: origAlpha
}, 200);
// Gentle pulse on board background
if (board.children && board.children.length > 0) {
var bg = board.children[0];
if (bg && bg.scale) {
bg.scale.x = bg.scale.y = 1.08;
tween.to(bg.scale, {
x: 1,
y: 1
}, 220, {
easing: tween.Easing.Back.Out
});
}
}
}
if (!blocks.some(function (block) {
return block;
})) {
game.createBlocks();
}
var pointsToAdd = board.checkLines();
if (pointsToAdd) {
score += Math.pow(pointsToAdd, 2) * 10;
scoreTxt.setText(score);
// Animate scoreTxt: scale up and back to normal
if (typeof tween !== "undefined") {
tween.to(scoreTxt.scale, {
x: 1.3,
y: 1.3
}, 120).onComplete(function () {
tween.to(scoreTxt.scale, {
x: 1,
y: 1
}, 180);
});
// Flash scoreTxt color
var origFill = scoreTxt.style.fill;
scoreTxt.style.fill = 0xffe066;
LK.setTimeout(function () {
scoreTxt.style.fill = origFill;
}, 200);
}
// Show combo/multiplier text if more than 1 line cleared
if (pointsToAdd > 1) {
var comboTxt = new Text2('x' + pointsToAdd, {
size: 120,
fill: 0xffa500,
font: 'Impact',
dropShadow: true,
dropShadowColor: '#2a636e'
});
comboTxt.anchor.set(.5, .5);
comboTxt.x = scoreTxt.x;
comboTxt.y = scoreTxt.y + scoreTxt.height + 30;
LK.gui.top.addChild(comboTxt);
// Gentle pop-in scale effect
if (typeof tween !== "undefined") {
comboTxt.alpha = 0;
comboTxt.scale.x = comboTxt.scale.y = 0.7;
tween.to(comboTxt, {
alpha: 1,
y: comboTxt.y - 40
}, 350, {
easing: tween.Easing.Cubic.Out
}).onComplete(function () {
tween.to(comboTxt, {
alpha: 0,
y: comboTxt.y - 40
}, 500).onComplete(function () {
comboTxt.destroy();
});
});
tween.to(comboTxt.scale, {
x: 1,
y: 1
}, 200, {
easing: tween.Easing.Back.Out
});
} else {
// fallback: just destroy after 1s
LK.setTimeout(function () {
comboTxt.destroy();
}, 1000);
}
}
}
}
board.removeTint();
dragTarget = undefined;
}
});
game.createBlocks = function () {
for (var i = 0; i < 3; i++) {
game.createBlock(i);
}
isGameOver = false;
};
var score = 0;
game.createBlocks();
// Play fragmentation music throughout the game
LK.playMusic('fragmentation', {
loop: true
});
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF,
font: 'Impact',
dropShadow: true,
dropShadowColor: '#2a636e'
});
scoreTxt.anchor.set(.5, 0);
LK.gui.top.addChild(scoreTxt);
game.isMovePossible = function () {
for (var a = 0; a < blocks.length; a++) {
if (blocks[a]) {
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (board.grid[i][j].filled) {
continue;
}
var canPlace = true;
for (var k = 0; k < blocks[a].shape.length; k++) {
for (var l = 0; l < blocks[a].shape[k].length; l++) {
if (blocks[a].shape[k][l] === 1) {
if (i + k < 0 || i + k >= 10 || j + l < 0 || j + l >= 10 || board.grid[i + k][j + l].filled) {
canPlace = false;
break;
}
}
}
if (!canPlace) {
break;
}
}
if (canPlace) {
return true;
}
}
}
}
}
return false;
};
var isGameOver = false;
LK.on('tick', function () {
board.tick();
if (!isGameOver && !game.isMovePossible()) {
isGameOver = true;
LK.effects.flashScreen(0xffffff, 1000);
LK.showGameOver();
}
for (var a = blocks.length - 1; a >= 0; a--) {
if (blocks[a]) {
if (blocks[a] != dragTarget) {
blocks[a].moveTowardsHomePosition();
// Gentle floating animation for idle blocks
if (!blocks[a].floatingPhase) blocks[a].floatingPhase = Math.random() * Math.PI * 2;
blocks[a].floatingPhase += 0.04;
var floatY = Math.sin(blocks[a].floatingPhase) * 8;
blocks[a].y = blocks[a].startY + floatY;
} else {
blocks[a].moveToDragTarget();
}
}
}
});
White square with round corners, flat shaded, hyper casual game. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Background for relaxing puzzle game. Pastel colors, flat shaded, vector art. Flowers. Blocks. Relaxing. Clouds Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
funny square. In-Game asset. 2d. High contrast. No shadows
sad square. In-Game asset. 2d. High contrast. No shadows