/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
coins: 0,
level: 1,
totalLinesCleared: 0,
totalBlocksPlaced: 0,
maxCombo: 0,
gamesPlayed: 0,
totalPlayTime: 0,
dailyRewardDay: 0,
dailyRewardClaimed: false,
currentTheme: "classic",
unlockedThemes: "classic",
soundEnabled: true,
musicEnabled: true,
vibrationEnabled: true,
tutorialCompleted: false
});
/****
* Classes
****/
var DraggingBlock = Container.expand(function () {
var self = Container.call(this);
self.blockType = 0;
self.selectedGrid = null;
self.blockGraphics = null;
self.setBlockType = function (type) {
self.blockType = type;
if (self.blockGraphics) {
self.removeChild(self.blockGraphics);
}
var assetIds = currentTheme.blockColors;
self.blockGraphics = self.attachAsset(assetIds[type % assetIds.length], {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {};
return self;
});
var GamePanel = Container.expand(function () {
var self = Container.call(this);
self.panelBg = self.attachAsset('panelBg', {
anchorX: 0.5,
anchorY: 0.5
});
self.title = new Text2('Panel Title', {
size: 80,
fill: '#FFFFFF'
});
self.title.anchor.set(0.5, 0);
self.title.x = 0;
self.title.y = -250;
self.addChild(self.title);
self.setTitle = function (text) {
self.title.setText(text);
};
self.update = function () {};
return self;
});
var GridBlock = Container.expand(function () {
var self = Container.call(this);
self.blockType = 0;
self.gridX = 0;
self.gridY = 0;
self.isMatched = false;
self.blockGraphics = null;
self.setBlockType = function (type) {
self.blockType = type;
if (self.blockGraphics) {
self.removeChild(self.blockGraphics);
}
var assetIds = currentTheme.blockColors;
self.blockGraphics = self.attachAsset(assetIds[type % assetIds.length], {
anchorX: 0.5,
anchorY: 0.5
});
};
self.getBlockAssetId = function () {
var assetIds = currentTheme.blockColors;
return assetIds[self.blockType % assetIds.length];
};
self.update = function () {};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 0;
self.maxLifetime = 1000;
self.particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += 0.15;
self.lifetime += 16;
self.particleGraphics.alpha = 1 - self.lifetime / self.maxLifetime;
};
return self;
});
var UIButton = Container.expand(function () {
var self = Container.call(this);
self.onPressed = null;
self.isHovered = false;
self.originalScale = 1;
self.buttonGraphics = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
self.setLabel = function (text) {
if (self.labelText) {
self.removeChild(self.labelText);
}
self.labelText = new Text2(text, {
size: 50,
fill: '#FFFFFF'
});
self.labelText.anchor.set(0.5, 0.5);
self.labelText.x = 0;
self.labelText.y = 0;
self.addChild(self.labelText);
};
self.setColor = function (color) {
self.buttonGraphics.tint = color;
};
self.down = function (x, y, obj) {
if (self.onPressed) {
self.onPressed();
LK.getSound('buttonClick').play();
}
tween(self, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
self.move = function (x, y, obj) {
if (!self.isHovered) {
self.isHovered = true;
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150
});
}
};
self.up = function (x, y, obj) {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
};
self.update = function () {};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// UI Elements
// Tema Dark
// Tema Neon
// Game variables
var GRID_WIDTH = 6;
var GRID_HEIGHT = 6;
var CELL_SIZE = 80;
var GRID_START_X = (2048 - GRID_WIDTH * CELL_SIZE) / 2;
var GRID_START_Y = 400;
var currentLevel = storage.level || 1;
var score = 0;
var gridBlocks = [];
var particles = [];
var nextBlockType = 0;
var isDragging = false;
var dragBlock = null;
var selectedGridCell = null;
var gameState = 'menu'; // menu, playing, paused, gameOver
var currentCombo = 0;
var maxComboThisGame = 0;
var linesCleared = 0;
var blocksPlaced = 0;
var sessionStartTime = 0;
// Theme system
var themes = {
classic: {
blockColors: ['block', 'blockBlue', 'blockGreen', 'blockOrange', 'blockPurple', 'blockYellow'],
gridColor: 0x2c3e50,
bgColor: 0x1A1A2E
},
neon: {
blockColors: ['blockNeonRed', 'blockNeonBlue', 'blockNeonGreen', 'blockNeonPurple', 'blockNeonYellow', 'blockNeonCyan'],
gridColor: 0x0a0a0a,
bgColor: 0x000000
},
dark: {
blockColors: ['blockDarkRed', 'blockDarkBlue', 'blockDarkGreen', 'blockDarkPurple', 'blockDarkYellow', 'blockDarkOrange'],
gridColor: 0x1a1a1a,
bgColor: 0x0d0d0d
}
};
var currentTheme = themes[storage.currentTheme] || themes.classic;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 2048 / 2;
scoreText.y = 50;
scoreText.visible = false;
game.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 60,
fill: '#4ECDC4'
});
levelText.anchor.set(0.5, 0);
levelText.x = 300;
levelText.y = 180;
levelText.visible = false;
game.addChild(levelText);
var comboText = new Text2('Combo: 0', {
size: 60,
fill: '#FFD700'
});
comboText.anchor.set(0.5, 0);
comboText.x = 1748;
comboText.y = 180;
comboText.visible = false;
game.addChild(comboText);
// Menu UI
var menuPanel = game.addChild(new Container());
var menuTitle = new Text2('BLOCKEY', {
size: 180,
fill: '#4ECDC4'
});
menuTitle.anchor.set(0.5, 0.5);
menuTitle.x = 2048 / 2;
menuTitle.y = 400;
menuPanel.addChild(menuTitle);
var playButton = menuPanel.addChild(new UIButton());
playButton.x = 2048 / 2;
playButton.y = 900;
playButton.setLabel('PLAY');
playButton.setColor(0x4ecdc4);
playButton.onPressed = function () {
startGame();
};
var shopButton = menuPanel.addChild(new UIButton());
shopButton.x = 2048 / 2;
shopButton.y = 1050;
shopButton.setLabel('SHOP');
shopButton.setColor(0xff6b6b);
shopButton.onPressed = function () {
showShop();
};
var statsButton = menuPanel.addChild(new UIButton());
statsButton.x = 2048 / 2;
statsButton.y = 1200;
statsButton.setLabel('STATS');
statsButton.setColor(0x9b59b6);
statsButton.onPressed = function () {
showStats();
};
var settingsButton = menuPanel.addChild(new UIButton());
settingsButton.x = 2048 / 2;
settingsButton.y = 1350;
settingsButton.setLabel('SETTINGS');
settingsButton.setColor(0xe74c3c);
settingsButton.onPressed = function () {
showSettings();
};
var coinsDisplay = new Text2('Coins: ' + storage.coins, {
size: 60,
fill: '#FFD700'
});
coinsDisplay.anchor.set(0.5, 0);
coinsDisplay.x = 2048 / 2;
coinsDisplay.y = 1600;
menuPanel.addChild(coinsDisplay);
// Shop function
function showShop() {
gameState = 'shop';
menuPanel.visible = false;
var shopPanel = game.addChild(new GamePanel());
shopPanel.x = 2048 / 2;
shopPanel.y = 2732 / 2;
shopPanel.setTitle('SHOP');
var themeNames = ['classic', 'neon', 'dark'];
var themePrices = [0, 500, 1000];
for (var t = 0; t < themeNames.length; t++) {
var themeName = themeNames[t];
var price = themePrices[t];
var unlockedThemes = storage.unlockedThemes ? storage.unlockedThemes.split(',') : ['classic'];
var isUnlocked = unlockedThemes.indexOf(themeName) !== -1;
var themeButton = shopPanel.addChild(new UIButton());
themeButton.x = 0;
themeButton.y = -100 + t * 150;
themeButton.setLabel(themeName.toUpperCase() + (isUnlocked ? ' ✓' : ' ' + price));
themeButton.setColor(0x4ecdc4);
themeButton.onPressed = function () {
if (!isUnlocked && storage.coins >= price) {
storage.coins -= price;
var newUnlocked = unlockedThemes.join(',') + ',' + themeName;
storage.unlockedThemes = newUnlocked;
isUnlocked = true;
themeButton.setLabel(themeName.toUpperCase() + ' ✓');
} else if (isUnlocked) {
storage.currentTheme = themeName;
currentTheme = themes[themeName];
}
};
}
var backButton = shopPanel.addChild(new UIButton());
backButton.x = 0;
backButton.y = 250;
backButton.setLabel('BACK');
backButton.setColor(0xe74c3c);
backButton.onPressed = function () {
shopPanel.destroy();
gameState = 'menu';
menuPanel.visible = true;
};
}
// Stats function
function showStats() {
var statsPanel = game.addChild(new GamePanel());
statsPanel.x = 2048 / 2;
statsPanel.y = 2732 / 2;
statsPanel.setTitle('STATISTICS');
var statText = new Text2('High Score: ' + storage.highScore + '\n' + 'Games Played: ' + (storage.gamesPlayed || 0) + '\n' + 'Total Lines: ' + (storage.totalLinesCleared || 0) + '\n' + 'Max Combo: ' + (storage.maxCombo || 0) + '\n' + 'Total Time: ' + Math.floor((storage.totalPlayTime || 0) / 60) + 'min', {
size: 50,
fill: '#FFFFFF'
});
statText.anchor.set(0.5, 0);
statText.x = 0;
statText.y = -150;
statsPanel.addChild(statText);
var backButton = statsPanel.addChild(new UIButton());
backButton.x = 0;
backButton.y = 200;
backButton.setLabel('BACK');
backButton.setColor(0xe74c3c);
backButton.onPressed = function () {
statsPanel.destroy();
};
}
// Settings function
function showSettings() {
var settingsPanel = game.addChild(new GamePanel());
settingsPanel.x = 2048 / 2;
settingsPanel.y = 2732 / 2;
settingsPanel.setTitle('SETTINGS');
var musicButton = settingsPanel.addChild(new UIButton());
musicButton.x = 0;
musicButton.y = -100;
musicButton.setLabel('Music: ' + (storage.musicEnabled !== false ? 'ON' : 'OFF'));
musicButton.setColor(0x4ecdc4);
musicButton.onPressed = function () {
storage.musicEnabled = !storage.musicEnabled;
musicButton.setLabel('Music: ' + (storage.musicEnabled ? 'ON' : 'OFF'));
};
var soundButton = settingsPanel.addChild(new UIButton());
soundButton.x = 0;
soundButton.y = 50;
soundButton.setLabel('Sound: ' + (storage.soundEnabled !== false ? 'ON' : 'OFF'));
soundButton.setColor(0x4ecdc4);
soundButton.onPressed = function () {
storage.soundEnabled = !storage.soundEnabled;
soundButton.setLabel('Sound: ' + (storage.soundEnabled ? 'ON' : 'OFF'));
};
var backButton = settingsPanel.addChild(new UIButton());
backButton.x = 0;
backButton.y = 250;
backButton.setLabel('BACK');
backButton.setColor(0xe74c3c);
backButton.onPressed = function () {
settingsPanel.destroy();
};
}
// Initialize grid
function initializeGrid() {
for (var y = 0; y < GRID_HEIGHT; y++) {
gridBlocks[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
gridBlocks[y][x] = null;
}
}
}
// Start game function
function startGame() {
if (gameState === 'menu') {
gameState = 'playing';
sessionStartTime = Date.now();
score = 0;
currentCombo = 0;
maxComboThisGame = 0;
linesCleared = 0;
blocksPlaced = 0;
gridBlocks = [];
initializeGrid();
particles = [];
dragBlock = null;
selectedGridCell = null;
// Hide menu
menuPanel.visible = false;
// Show game UI
scoreText.visible = true;
levelText.visible = true;
comboText.visible = true;
scoreText.setText('Score: 0');
// Clear and redraw game
for (var child = game.children.length - 1; child >= 0; child--) {
var c = game.children[child];
if (c !== scoreText && c !== levelText && c !== comboText && c !== menuPanel) {
if (c.destroy) c.destroy();
game.removeChild(c);
}
}
drawGridBackground();
generateNextBlock();
if (storage.musicEnabled) {
LK.playMusic('bgmusic');
}
}
}
initializeGrid();
// Draw grid cells background
function drawGridBackground() {
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
var gridCell = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
gridCell.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
gridCell.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
gridCell.alpha = 0.3;
game.addChild(gridCell);
}
}
}
drawGridBackground();
// Generate next block in preview area
function generateNextBlock() {
nextBlockType = Math.floor(Math.random() * 6);
currentCombo = 0;
comboText.setText('Combo: 0');
if (!dragBlock) {
dragBlock = game.addChild(new DraggingBlock());
dragBlock.setBlockType(nextBlockType);
dragBlock.x = 2048 / 2;
dragBlock.y = 300;
dragBlock.blockGraphics.alpha = 0.8;
tween(dragBlock, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 300,
easing: tween.easeInOut
});
}
}
generateNextBlock();
// Get grid cell position from screen coordinates
function getGridCellFromPosition(x, y) {
var gridX = Math.floor((x - GRID_START_X) / CELL_SIZE);
var gridY = Math.floor((y - GRID_START_Y) / CELL_SIZE);
if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT) {
return {
x: gridX,
y: gridY
};
}
return null;
}
// Check if placement is valid
function isValidPlacement(gridX, gridY) {
if (gridX < 0 || gridX >= GRID_WIDTH || gridY < 0 || gridY >= GRID_HEIGHT) {
return false;
}
return gridBlocks[gridY][gridX] === null;
}
// Place block on grid
function placeBlock(gridX, gridY, blockType) {
if (!isValidPlacement(gridX, gridY)) {
return false;
}
var block = game.addChild(new GridBlock());
block.setBlockType(blockType);
block.gridX = gridX;
block.gridY = gridY;
block.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
block.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
blocksPlaced++;
gridBlocks[gridY][gridX] = block;
if (storage.soundEnabled !== false) {
LK.getSound('blockPlace').play();
}
tween(block, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100
});
return true;
}
// Find matches in grid
function findMatches() {
var matchedBlocks = [];
var matchedMap = {};
// Check horizontal matches
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
if (gridBlocks[y][x] === null) continue;
var currentType = gridBlocks[y][x].blockType;
var matchLength = 1;
for (var checkX = x + 1; checkX < GRID_WIDTH; checkX++) {
if (gridBlocks[y][checkX] === null || gridBlocks[y][checkX].blockType !== currentType) {
break;
}
matchLength++;
}
if (matchLength >= 3) {
for (var i = 0; i < matchLength; i++) {
var block = gridBlocks[y][x + i];
var key = x + i + '_' + y;
if (!matchedMap[key]) {
matchedBlocks.push(block);
matchedMap[key] = true;
}
}
}
}
}
// Check vertical matches
for (var x = 0; x < GRID_WIDTH; x++) {
for (var y = 0; y < GRID_HEIGHT; y++) {
if (gridBlocks[y][x] === null) continue;
var currentType = gridBlocks[y][x].blockType;
var matchLength = 1;
for (var checkY = y + 1; checkY < GRID_HEIGHT; checkY++) {
if (gridBlocks[checkY][x] === null || gridBlocks[checkY][x].blockType !== currentType) {
break;
}
matchLength++;
}
if (matchLength >= 3) {
for (var i = 0; i < matchLength; i++) {
var block = gridBlocks[y + i][x];
var key = x + '_' + (y + i);
if (!matchedMap[key]) {
matchedBlocks.push(block);
matchedMap[key] = true;
}
}
}
}
}
return matchedBlocks;
}
// Clear matched blocks
function clearMatches() {
var matchedBlocks = findMatches();
if (matchedBlocks.length > 0) {
LK.getSound('match').play();
currentCombo++;
if (currentCombo > maxComboThisGame) {
maxComboThisGame = currentCombo;
}
var basePoints = matchedBlocks.length * 10;
var comboMultiplier = 1 + currentCombo * 0.1;
var pointsEarned = Math.floor(basePoints * comboMultiplier);
score += pointsEarned;
scoreText.setText('Score: ' + score);
comboText.setText('Combo: ' + currentCombo + 'x');
linesCleared += matchedBlocks.length;
if (currentCombo > 1) {
LK.getSound('combo').play();
}
for (var i = 0; i < matchedBlocks.length; i++) {
var block = matchedBlocks[i];
LK.effects.flashObject(block, 0xFFFF00, 300);
// Create particles
for (var p = 0; p < 5; p++) {
var particle = game.addChild(new Particle());
particle.x = block.x;
particle.y = block.y;
particle.velocityX = (Math.random() - 0.5) * 4;
particle.velocityY = (Math.random() - 0.5) * 4;
particles.push(particle);
}
gridBlocks[block.gridY][block.gridX] = null;
block.destroy();
}
LK.setTimeout(function () {
applyGravity();
}, 300);
return true;
}
return false;
}
// Apply gravity to blocks
function applyGravity() {
for (var x = 0; x < GRID_WIDTH; x++) {
var writeY = GRID_HEIGHT - 1;
for (var y = GRID_HEIGHT - 1; y >= 0; y--) {
if (gridBlocks[y][x] !== null) {
var block = gridBlocks[y][x];
gridBlocks[y][x] = null;
gridBlocks[writeY][x] = block;
block.gridY = writeY;
var targetY = GRID_START_Y + writeY * CELL_SIZE + CELL_SIZE / 2;
tween(block, {
y: targetY
}, {
duration: 300,
easing: tween.easeIn
});
writeY--;
}
}
}
LK.setTimeout(function () {
if (!clearMatches()) {
checkGameOver();
}
}, 350);
}
// Check for game over condition
function checkGameOver() {
var hasValidMove = false;
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
if (gridBlocks[y][x] === null) {
hasValidMove = true;
break;
}
}
if (hasValidMove) break;
}
if (!hasValidMove) {
gameState = 'gameOver';
currentCombo = 0;
var sessionDuration = Math.floor((Date.now() - sessionStartTime) / 1000);
var coinsEarned = Math.floor(score / 100) + 10;
storage.coins += coinsEarned;
storage.totalPlayTime += sessionDuration;
storage.totalBlocksPlaced += blocksPlaced;
storage.totalLinesCleared += linesCleared;
if (storage.maxCombo === undefined || maxComboThisGame > storage.maxCombo) {
storage.maxCombo = maxComboThisGame;
}
if (score > storage.highScore) {
storage.highScore = score;
LK.getSound('levelUp').play();
}
storage.gamesPlayed = (storage.gamesPlayed || 0) + 1;
LK.showGameOver();
}
}
// Game event handlers
var dragStartX = 0;
var dragStartY = 0;
game.down = function (x, y, obj) {
isDragging = true;
dragStartX = x;
dragStartY = y;
if (dragBlock) {
dragBlock.blockGraphics.alpha = 0.6;
}
};
game.move = function (x, y, obj) {
if (isDragging && dragBlock) {
dragBlock.x = x;
dragBlock.y = y;
var gridCell = getGridCellFromPosition(x, y);
if (gridCell && isValidPlacement(gridCell.x, gridCell.y)) {
selectedGridCell = gridCell;
} else {
selectedGridCell = null;
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
if (dragBlock && selectedGridCell) {
if (placeBlock(selectedGridCell.x, selectedGridCell.y, dragBlock.blockType)) {
dragBlock.destroy();
dragBlock = null;
selectedGridCell = null;
LK.setTimeout(function () {
clearMatches();
}, 100);
LK.setTimeout(function () {
generateNextBlock();
}, 500);
}
} else if (dragBlock) {
dragBlock.blockGraphics.alpha = 0.8;
tween(dragBlock, {
x: 2048 / 2,
y: 300
}, {
duration: 200
});
}
selectedGridCell = null;
};
// Main game update loop
game.update = function () {
if (gameState === 'playing') {
levelText.setText('Level: ' + currentLevel);
levelText.visible = true;
scoreText.visible = true;
comboText.visible = true;
// Update particles
for (var p = particles.length - 1; p >= 0; p--) {
var particle = particles[p];
if (particle.lifetime >= particle.maxLifetime) {
particle.destroy();
particles.splice(p, 1);
}
}
} else {
levelText.visible = false;
scoreText.visible = false;
comboText.visible = false;
}
};
// Store current level and theme
storage.level = currentLevel;
storage.currentTheme = storage.currentTheme || 'classic'; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
coins: 0,
level: 1,
totalLinesCleared: 0,
totalBlocksPlaced: 0,
maxCombo: 0,
gamesPlayed: 0,
totalPlayTime: 0,
dailyRewardDay: 0,
dailyRewardClaimed: false,
currentTheme: "classic",
unlockedThemes: "classic",
soundEnabled: true,
musicEnabled: true,
vibrationEnabled: true,
tutorialCompleted: false
});
/****
* Classes
****/
var DraggingBlock = Container.expand(function () {
var self = Container.call(this);
self.blockType = 0;
self.selectedGrid = null;
self.blockGraphics = null;
self.setBlockType = function (type) {
self.blockType = type;
if (self.blockGraphics) {
self.removeChild(self.blockGraphics);
}
var assetIds = currentTheme.blockColors;
self.blockGraphics = self.attachAsset(assetIds[type % assetIds.length], {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {};
return self;
});
var GamePanel = Container.expand(function () {
var self = Container.call(this);
self.panelBg = self.attachAsset('panelBg', {
anchorX: 0.5,
anchorY: 0.5
});
self.title = new Text2('Panel Title', {
size: 80,
fill: '#FFFFFF'
});
self.title.anchor.set(0.5, 0);
self.title.x = 0;
self.title.y = -250;
self.addChild(self.title);
self.setTitle = function (text) {
self.title.setText(text);
};
self.update = function () {};
return self;
});
var GridBlock = Container.expand(function () {
var self = Container.call(this);
self.blockType = 0;
self.gridX = 0;
self.gridY = 0;
self.isMatched = false;
self.blockGraphics = null;
self.setBlockType = function (type) {
self.blockType = type;
if (self.blockGraphics) {
self.removeChild(self.blockGraphics);
}
var assetIds = currentTheme.blockColors;
self.blockGraphics = self.attachAsset(assetIds[type % assetIds.length], {
anchorX: 0.5,
anchorY: 0.5
});
};
self.getBlockAssetId = function () {
var assetIds = currentTheme.blockColors;
return assetIds[self.blockType % assetIds.length];
};
self.update = function () {};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 0;
self.maxLifetime = 1000;
self.particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += 0.15;
self.lifetime += 16;
self.particleGraphics.alpha = 1 - self.lifetime / self.maxLifetime;
};
return self;
});
var UIButton = Container.expand(function () {
var self = Container.call(this);
self.onPressed = null;
self.isHovered = false;
self.originalScale = 1;
self.buttonGraphics = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
self.setLabel = function (text) {
if (self.labelText) {
self.removeChild(self.labelText);
}
self.labelText = new Text2(text, {
size: 50,
fill: '#FFFFFF'
});
self.labelText.anchor.set(0.5, 0.5);
self.labelText.x = 0;
self.labelText.y = 0;
self.addChild(self.labelText);
};
self.setColor = function (color) {
self.buttonGraphics.tint = color;
};
self.down = function (x, y, obj) {
if (self.onPressed) {
self.onPressed();
LK.getSound('buttonClick').play();
}
tween(self, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
self.move = function (x, y, obj) {
if (!self.isHovered) {
self.isHovered = true;
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150
});
}
};
self.up = function (x, y, obj) {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
};
self.update = function () {};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// UI Elements
// Tema Dark
// Tema Neon
// Game variables
var GRID_WIDTH = 6;
var GRID_HEIGHT = 6;
var CELL_SIZE = 80;
var GRID_START_X = (2048 - GRID_WIDTH * CELL_SIZE) / 2;
var GRID_START_Y = 400;
var currentLevel = storage.level || 1;
var score = 0;
var gridBlocks = [];
var particles = [];
var nextBlockType = 0;
var isDragging = false;
var dragBlock = null;
var selectedGridCell = null;
var gameState = 'menu'; // menu, playing, paused, gameOver
var currentCombo = 0;
var maxComboThisGame = 0;
var linesCleared = 0;
var blocksPlaced = 0;
var sessionStartTime = 0;
// Theme system
var themes = {
classic: {
blockColors: ['block', 'blockBlue', 'blockGreen', 'blockOrange', 'blockPurple', 'blockYellow'],
gridColor: 0x2c3e50,
bgColor: 0x1A1A2E
},
neon: {
blockColors: ['blockNeonRed', 'blockNeonBlue', 'blockNeonGreen', 'blockNeonPurple', 'blockNeonYellow', 'blockNeonCyan'],
gridColor: 0x0a0a0a,
bgColor: 0x000000
},
dark: {
blockColors: ['blockDarkRed', 'blockDarkBlue', 'blockDarkGreen', 'blockDarkPurple', 'blockDarkYellow', 'blockDarkOrange'],
gridColor: 0x1a1a1a,
bgColor: 0x0d0d0d
}
};
var currentTheme = themes[storage.currentTheme] || themes.classic;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 2048 / 2;
scoreText.y = 50;
scoreText.visible = false;
game.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 60,
fill: '#4ECDC4'
});
levelText.anchor.set(0.5, 0);
levelText.x = 300;
levelText.y = 180;
levelText.visible = false;
game.addChild(levelText);
var comboText = new Text2('Combo: 0', {
size: 60,
fill: '#FFD700'
});
comboText.anchor.set(0.5, 0);
comboText.x = 1748;
comboText.y = 180;
comboText.visible = false;
game.addChild(comboText);
// Menu UI
var menuPanel = game.addChild(new Container());
var menuTitle = new Text2('BLOCKEY', {
size: 180,
fill: '#4ECDC4'
});
menuTitle.anchor.set(0.5, 0.5);
menuTitle.x = 2048 / 2;
menuTitle.y = 400;
menuPanel.addChild(menuTitle);
var playButton = menuPanel.addChild(new UIButton());
playButton.x = 2048 / 2;
playButton.y = 900;
playButton.setLabel('PLAY');
playButton.setColor(0x4ecdc4);
playButton.onPressed = function () {
startGame();
};
var shopButton = menuPanel.addChild(new UIButton());
shopButton.x = 2048 / 2;
shopButton.y = 1050;
shopButton.setLabel('SHOP');
shopButton.setColor(0xff6b6b);
shopButton.onPressed = function () {
showShop();
};
var statsButton = menuPanel.addChild(new UIButton());
statsButton.x = 2048 / 2;
statsButton.y = 1200;
statsButton.setLabel('STATS');
statsButton.setColor(0x9b59b6);
statsButton.onPressed = function () {
showStats();
};
var settingsButton = menuPanel.addChild(new UIButton());
settingsButton.x = 2048 / 2;
settingsButton.y = 1350;
settingsButton.setLabel('SETTINGS');
settingsButton.setColor(0xe74c3c);
settingsButton.onPressed = function () {
showSettings();
};
var coinsDisplay = new Text2('Coins: ' + storage.coins, {
size: 60,
fill: '#FFD700'
});
coinsDisplay.anchor.set(0.5, 0);
coinsDisplay.x = 2048 / 2;
coinsDisplay.y = 1600;
menuPanel.addChild(coinsDisplay);
// Shop function
function showShop() {
gameState = 'shop';
menuPanel.visible = false;
var shopPanel = game.addChild(new GamePanel());
shopPanel.x = 2048 / 2;
shopPanel.y = 2732 / 2;
shopPanel.setTitle('SHOP');
var themeNames = ['classic', 'neon', 'dark'];
var themePrices = [0, 500, 1000];
for (var t = 0; t < themeNames.length; t++) {
var themeName = themeNames[t];
var price = themePrices[t];
var unlockedThemes = storage.unlockedThemes ? storage.unlockedThemes.split(',') : ['classic'];
var isUnlocked = unlockedThemes.indexOf(themeName) !== -1;
var themeButton = shopPanel.addChild(new UIButton());
themeButton.x = 0;
themeButton.y = -100 + t * 150;
themeButton.setLabel(themeName.toUpperCase() + (isUnlocked ? ' ✓' : ' ' + price));
themeButton.setColor(0x4ecdc4);
themeButton.onPressed = function () {
if (!isUnlocked && storage.coins >= price) {
storage.coins -= price;
var newUnlocked = unlockedThemes.join(',') + ',' + themeName;
storage.unlockedThemes = newUnlocked;
isUnlocked = true;
themeButton.setLabel(themeName.toUpperCase() + ' ✓');
} else if (isUnlocked) {
storage.currentTheme = themeName;
currentTheme = themes[themeName];
}
};
}
var backButton = shopPanel.addChild(new UIButton());
backButton.x = 0;
backButton.y = 250;
backButton.setLabel('BACK');
backButton.setColor(0xe74c3c);
backButton.onPressed = function () {
shopPanel.destroy();
gameState = 'menu';
menuPanel.visible = true;
};
}
// Stats function
function showStats() {
var statsPanel = game.addChild(new GamePanel());
statsPanel.x = 2048 / 2;
statsPanel.y = 2732 / 2;
statsPanel.setTitle('STATISTICS');
var statText = new Text2('High Score: ' + storage.highScore + '\n' + 'Games Played: ' + (storage.gamesPlayed || 0) + '\n' + 'Total Lines: ' + (storage.totalLinesCleared || 0) + '\n' + 'Max Combo: ' + (storage.maxCombo || 0) + '\n' + 'Total Time: ' + Math.floor((storage.totalPlayTime || 0) / 60) + 'min', {
size: 50,
fill: '#FFFFFF'
});
statText.anchor.set(0.5, 0);
statText.x = 0;
statText.y = -150;
statsPanel.addChild(statText);
var backButton = statsPanel.addChild(new UIButton());
backButton.x = 0;
backButton.y = 200;
backButton.setLabel('BACK');
backButton.setColor(0xe74c3c);
backButton.onPressed = function () {
statsPanel.destroy();
};
}
// Settings function
function showSettings() {
var settingsPanel = game.addChild(new GamePanel());
settingsPanel.x = 2048 / 2;
settingsPanel.y = 2732 / 2;
settingsPanel.setTitle('SETTINGS');
var musicButton = settingsPanel.addChild(new UIButton());
musicButton.x = 0;
musicButton.y = -100;
musicButton.setLabel('Music: ' + (storage.musicEnabled !== false ? 'ON' : 'OFF'));
musicButton.setColor(0x4ecdc4);
musicButton.onPressed = function () {
storage.musicEnabled = !storage.musicEnabled;
musicButton.setLabel('Music: ' + (storage.musicEnabled ? 'ON' : 'OFF'));
};
var soundButton = settingsPanel.addChild(new UIButton());
soundButton.x = 0;
soundButton.y = 50;
soundButton.setLabel('Sound: ' + (storage.soundEnabled !== false ? 'ON' : 'OFF'));
soundButton.setColor(0x4ecdc4);
soundButton.onPressed = function () {
storage.soundEnabled = !storage.soundEnabled;
soundButton.setLabel('Sound: ' + (storage.soundEnabled ? 'ON' : 'OFF'));
};
var backButton = settingsPanel.addChild(new UIButton());
backButton.x = 0;
backButton.y = 250;
backButton.setLabel('BACK');
backButton.setColor(0xe74c3c);
backButton.onPressed = function () {
settingsPanel.destroy();
};
}
// Initialize grid
function initializeGrid() {
for (var y = 0; y < GRID_HEIGHT; y++) {
gridBlocks[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
gridBlocks[y][x] = null;
}
}
}
// Start game function
function startGame() {
if (gameState === 'menu') {
gameState = 'playing';
sessionStartTime = Date.now();
score = 0;
currentCombo = 0;
maxComboThisGame = 0;
linesCleared = 0;
blocksPlaced = 0;
gridBlocks = [];
initializeGrid();
particles = [];
dragBlock = null;
selectedGridCell = null;
// Hide menu
menuPanel.visible = false;
// Show game UI
scoreText.visible = true;
levelText.visible = true;
comboText.visible = true;
scoreText.setText('Score: 0');
// Clear and redraw game
for (var child = game.children.length - 1; child >= 0; child--) {
var c = game.children[child];
if (c !== scoreText && c !== levelText && c !== comboText && c !== menuPanel) {
if (c.destroy) c.destroy();
game.removeChild(c);
}
}
drawGridBackground();
generateNextBlock();
if (storage.musicEnabled) {
LK.playMusic('bgmusic');
}
}
}
initializeGrid();
// Draw grid cells background
function drawGridBackground() {
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
var gridCell = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
gridCell.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
gridCell.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
gridCell.alpha = 0.3;
game.addChild(gridCell);
}
}
}
drawGridBackground();
// Generate next block in preview area
function generateNextBlock() {
nextBlockType = Math.floor(Math.random() * 6);
currentCombo = 0;
comboText.setText('Combo: 0');
if (!dragBlock) {
dragBlock = game.addChild(new DraggingBlock());
dragBlock.setBlockType(nextBlockType);
dragBlock.x = 2048 / 2;
dragBlock.y = 300;
dragBlock.blockGraphics.alpha = 0.8;
tween(dragBlock, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 300,
easing: tween.easeInOut
});
}
}
generateNextBlock();
// Get grid cell position from screen coordinates
function getGridCellFromPosition(x, y) {
var gridX = Math.floor((x - GRID_START_X) / CELL_SIZE);
var gridY = Math.floor((y - GRID_START_Y) / CELL_SIZE);
if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT) {
return {
x: gridX,
y: gridY
};
}
return null;
}
// Check if placement is valid
function isValidPlacement(gridX, gridY) {
if (gridX < 0 || gridX >= GRID_WIDTH || gridY < 0 || gridY >= GRID_HEIGHT) {
return false;
}
return gridBlocks[gridY][gridX] === null;
}
// Place block on grid
function placeBlock(gridX, gridY, blockType) {
if (!isValidPlacement(gridX, gridY)) {
return false;
}
var block = game.addChild(new GridBlock());
block.setBlockType(blockType);
block.gridX = gridX;
block.gridY = gridY;
block.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
block.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
blocksPlaced++;
gridBlocks[gridY][gridX] = block;
if (storage.soundEnabled !== false) {
LK.getSound('blockPlace').play();
}
tween(block, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100
});
return true;
}
// Find matches in grid
function findMatches() {
var matchedBlocks = [];
var matchedMap = {};
// Check horizontal matches
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
if (gridBlocks[y][x] === null) continue;
var currentType = gridBlocks[y][x].blockType;
var matchLength = 1;
for (var checkX = x + 1; checkX < GRID_WIDTH; checkX++) {
if (gridBlocks[y][checkX] === null || gridBlocks[y][checkX].blockType !== currentType) {
break;
}
matchLength++;
}
if (matchLength >= 3) {
for (var i = 0; i < matchLength; i++) {
var block = gridBlocks[y][x + i];
var key = x + i + '_' + y;
if (!matchedMap[key]) {
matchedBlocks.push(block);
matchedMap[key] = true;
}
}
}
}
}
// Check vertical matches
for (var x = 0; x < GRID_WIDTH; x++) {
for (var y = 0; y < GRID_HEIGHT; y++) {
if (gridBlocks[y][x] === null) continue;
var currentType = gridBlocks[y][x].blockType;
var matchLength = 1;
for (var checkY = y + 1; checkY < GRID_HEIGHT; checkY++) {
if (gridBlocks[checkY][x] === null || gridBlocks[checkY][x].blockType !== currentType) {
break;
}
matchLength++;
}
if (matchLength >= 3) {
for (var i = 0; i < matchLength; i++) {
var block = gridBlocks[y + i][x];
var key = x + '_' + (y + i);
if (!matchedMap[key]) {
matchedBlocks.push(block);
matchedMap[key] = true;
}
}
}
}
}
return matchedBlocks;
}
// Clear matched blocks
function clearMatches() {
var matchedBlocks = findMatches();
if (matchedBlocks.length > 0) {
LK.getSound('match').play();
currentCombo++;
if (currentCombo > maxComboThisGame) {
maxComboThisGame = currentCombo;
}
var basePoints = matchedBlocks.length * 10;
var comboMultiplier = 1 + currentCombo * 0.1;
var pointsEarned = Math.floor(basePoints * comboMultiplier);
score += pointsEarned;
scoreText.setText('Score: ' + score);
comboText.setText('Combo: ' + currentCombo + 'x');
linesCleared += matchedBlocks.length;
if (currentCombo > 1) {
LK.getSound('combo').play();
}
for (var i = 0; i < matchedBlocks.length; i++) {
var block = matchedBlocks[i];
LK.effects.flashObject(block, 0xFFFF00, 300);
// Create particles
for (var p = 0; p < 5; p++) {
var particle = game.addChild(new Particle());
particle.x = block.x;
particle.y = block.y;
particle.velocityX = (Math.random() - 0.5) * 4;
particle.velocityY = (Math.random() - 0.5) * 4;
particles.push(particle);
}
gridBlocks[block.gridY][block.gridX] = null;
block.destroy();
}
LK.setTimeout(function () {
applyGravity();
}, 300);
return true;
}
return false;
}
// Apply gravity to blocks
function applyGravity() {
for (var x = 0; x < GRID_WIDTH; x++) {
var writeY = GRID_HEIGHT - 1;
for (var y = GRID_HEIGHT - 1; y >= 0; y--) {
if (gridBlocks[y][x] !== null) {
var block = gridBlocks[y][x];
gridBlocks[y][x] = null;
gridBlocks[writeY][x] = block;
block.gridY = writeY;
var targetY = GRID_START_Y + writeY * CELL_SIZE + CELL_SIZE / 2;
tween(block, {
y: targetY
}, {
duration: 300,
easing: tween.easeIn
});
writeY--;
}
}
}
LK.setTimeout(function () {
if (!clearMatches()) {
checkGameOver();
}
}, 350);
}
// Check for game over condition
function checkGameOver() {
var hasValidMove = false;
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
if (gridBlocks[y][x] === null) {
hasValidMove = true;
break;
}
}
if (hasValidMove) break;
}
if (!hasValidMove) {
gameState = 'gameOver';
currentCombo = 0;
var sessionDuration = Math.floor((Date.now() - sessionStartTime) / 1000);
var coinsEarned = Math.floor(score / 100) + 10;
storage.coins += coinsEarned;
storage.totalPlayTime += sessionDuration;
storage.totalBlocksPlaced += blocksPlaced;
storage.totalLinesCleared += linesCleared;
if (storage.maxCombo === undefined || maxComboThisGame > storage.maxCombo) {
storage.maxCombo = maxComboThisGame;
}
if (score > storage.highScore) {
storage.highScore = score;
LK.getSound('levelUp').play();
}
storage.gamesPlayed = (storage.gamesPlayed || 0) + 1;
LK.showGameOver();
}
}
// Game event handlers
var dragStartX = 0;
var dragStartY = 0;
game.down = function (x, y, obj) {
isDragging = true;
dragStartX = x;
dragStartY = y;
if (dragBlock) {
dragBlock.blockGraphics.alpha = 0.6;
}
};
game.move = function (x, y, obj) {
if (isDragging && dragBlock) {
dragBlock.x = x;
dragBlock.y = y;
var gridCell = getGridCellFromPosition(x, y);
if (gridCell && isValidPlacement(gridCell.x, gridCell.y)) {
selectedGridCell = gridCell;
} else {
selectedGridCell = null;
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
if (dragBlock && selectedGridCell) {
if (placeBlock(selectedGridCell.x, selectedGridCell.y, dragBlock.blockType)) {
dragBlock.destroy();
dragBlock = null;
selectedGridCell = null;
LK.setTimeout(function () {
clearMatches();
}, 100);
LK.setTimeout(function () {
generateNextBlock();
}, 500);
}
} else if (dragBlock) {
dragBlock.blockGraphics.alpha = 0.8;
tween(dragBlock, {
x: 2048 / 2,
y: 300
}, {
duration: 200
});
}
selectedGridCell = null;
};
// Main game update loop
game.update = function () {
if (gameState === 'playing') {
levelText.setText('Level: ' + currentLevel);
levelText.visible = true;
scoreText.visible = true;
comboText.visible = true;
// Update particles
for (var p = particles.length - 1; p >= 0; p--) {
var particle = particles[p];
if (particle.lifetime >= particle.maxLifetime) {
particle.destroy();
particles.splice(p, 1);
}
}
} else {
levelText.visible = false;
scoreText.visible = false;
comboText.visible = false;
}
};
// Store current level and theme
storage.level = currentLevel;
storage.currentTheme = storage.currentTheme || 'classic';