User prompt
60ms yap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hala çok uzun sürüyor ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Satır temizlemeyi biraz hızlandır ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Satır temizle parçalanma efecti ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Parmagımı ortada basılı tuttugumda blok hızlıca yere insin
User prompt
Bloklar hala bozuk geliyor
User prompt
Blokların şekli tutarlı değil
User prompt
Hala bir sürü geliyor
User prompt
Lütfen düzelt
User prompt
Blokların geliş sıklıgı çok kısa
User prompt
Bloklar TEK TEK GELSİN
User prompt
Bloklar sırayla tek tek gelsin biri yere degmeddn başka blok gelmesin
User prompt
Bir blok yere degmeden başka gelmesin
User prompt
Ekranı kapla
User prompt
Tetris oyunu yap
User prompt
Block Drop Puzzle
Initial prompt
Tetris
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Block = Container.expand(function (blockType) { var self = Container.call(this); self.blockType = blockType || 'block_I'; self.gridX = 0; self.gridY = 0; var blockGraphics = self.attachAsset(self.blockType, { anchorX: 0, anchorY: 0 }); self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = GRID_OFFSET_X + gridX * BLOCK_SIZE; self.y = GRID_OFFSET_Y + gridY * BLOCK_SIZE; }; return self; }); var Tetromino = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'I'; self.rotation = 0; self.gridX = 7; // Start in middle of board self.gridY = 0; self.blocks = []; self.fallTimer = 0; self.fallSpeed = 40; // Frames until next fall (faster falling speed) self.isPlaced = false; // Prevent multiple placement calls // Tetromino shapes and rotations self.shapes = { 'I': [[[1, 1, 1, 1]], [[1], [1], [1], [1]], [[1, 1, 1, 1]], [[1], [1], [1], [1]]], 'O': [[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]], 'T': [[[0, 1, 0], [1, 1, 1]], [[1, 0], [1, 1], [1, 0]], [[1, 1, 1], [0, 1, 0]], [[0, 1], [1, 1], [0, 1]]], 'S': [[[0, 1, 1], [1, 1, 0]], [[1, 0], [1, 1], [0, 1]], [[0, 1, 1], [1, 1, 0]], [[1, 0], [1, 1], [0, 1]]], 'Z': [[[1, 1, 0], [0, 1, 1]], [[0, 1], [1, 1], [1, 0]], [[1, 1, 0], [0, 1, 1]], [[0, 1], [1, 1], [1, 0]]], 'J': [[[1, 0, 0], [1, 1, 1]], [[1, 1], [1, 0], [1, 0]], [[1, 1, 1], [0, 0, 1]], [[0, 1], [0, 1], [1, 1]]], 'L': [[[0, 0, 1], [1, 1, 1]], [[1, 0], [1, 0], [1, 1]], [[1, 1, 1], [1, 0, 0]], [[1, 1], [0, 1], [0, 1]]] }; self.getBlockType = function () { // Map each tetromino type to its corresponding block asset var blockTypeMap = { 'I': 'block_I', 'O': 'block_O', 'T': 'block_T', 'S': 'block_S', 'Z': 'block_Z', 'J': 'block_J', 'L': 'block_L' }; return blockTypeMap[self.type] || 'block_I'; }; self.createBlocks = function () { // Clear existing blocks for (var i = 0; i < self.blocks.length; i++) { self.blocks[i].destroy(); } self.blocks = []; // Ensure we have a valid shape for this type if (!self.shapes[self.type]) { console.error('Invalid tetromino type:', self.type); return; } var shape = self.shapes[self.type][self.rotation]; var blockType = self.getBlockType(); for (var y = 0; y < shape.length; y++) { for (var x = 0; x < shape[y].length; x++) { if (shape[y][x] === 1) { var block = new Block(blockType); block.setGridPosition(self.gridX + x, self.gridY + y); self.blocks.push(block); game.addChild(block); } } } }; self.updatePosition = function () { var shape = self.shapes[self.type][self.rotation]; var blockIndex = 0; for (var y = 0; y < shape.length; y++) { for (var x = 0; x < shape[y].length; x++) { if (shape[y][x] === 1) { if (blockIndex < self.blocks.length) { self.blocks[blockIndex].setGridPosition(self.gridX + x, self.gridY + y); } blockIndex++; } } } }; self.canMoveTo = function (newX, newY, newRotation) { var testRotation = newRotation !== undefined ? newRotation : self.rotation; var shape = self.shapes[self.type][testRotation]; for (var y = 0; y < shape.length; y++) { for (var x = 0; x < shape[y].length; x++) { if (shape[y][x] === 1) { var checkX = newX + x; var checkY = newY + y; // Check bounds if (checkX < 0 || checkX >= GRID_WIDTH || checkY >= GRID_HEIGHT) { return false; } // Check collision with placed blocks if (checkY >= 0 && gameGrid[checkY] && gameGrid[checkY][checkX]) { return false; } } } } return true; }; self.move = function (deltaX, deltaY) { if (self.canMoveTo(self.gridX + deltaX, self.gridY + deltaY)) { self.gridX += deltaX; self.gridY += deltaY; self.updatePosition(); return true; } return false; }; self.rotate = function () { var newRotation = (self.rotation + 1) % 4; if (self.canMoveTo(self.gridX, self.gridY, newRotation)) { self.rotation = newRotation; self.updatePosition(); // Create sparkle effect for rotation for (var i = 0; i < self.blocks.length; i++) { var block = self.blocks[i]; var sparkleCount = 8; for (var j = 0; j < sparkleCount; j++) { var sparkle = LK.getAsset('grid_border', { x: block.x + BLOCK_SIZE / 2, y: block.y + BLOCK_SIZE / 2, scaleX: 5, scaleY: 5, alpha: 1.5, tint: 0xFFFFFF }); game.addChild(sparkle); // Random sparkle position around block var angle = j / sparkleCount * Math.PI * 2; var distance = BLOCK_SIZE * 1.0; var targetX = sparkle.x + Math.cos(angle) * distance; var targetY = sparkle.y + Math.sin(angle) * distance; // Animate sparkle outward and fade tween(sparkle, { x: targetX, y: targetY, alpha: 0.3, scaleX: 0.3, scaleY: 0.3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { if (sparkle && sparkle.destroy) { sparkle.destroy(); } } }); } } LK.getSound('sparkle_effect').play(); LK.getSound('piece_rotate').play(); return true; } return false; }; self.update = function () { self.fallTimer++; if (self.fallTimer >= self.fallSpeed) { self.fallTimer = 0; if (!self.move(0, 1)) { // Piece has landed self.placePiece(); } } }; self.placePiece = function () { // Prevent multiple calls if (self.isPlaced) return; self.isPlaced = true; // Add blocks to grid and create sparkle effects for (var i = 0; i < self.blocks.length; i++) { var block = self.blocks[i]; if (block.gridY >= 0) { if (!gameGrid[block.gridY]) gameGrid[block.gridY] = []; gameGrid[block.gridY][block.gridX] = block; // Create sparkle effect around the block var sparkleCount = 8; for (var j = 0; j < sparkleCount; j++) { var sparkle = LK.getAsset('grid_border', { x: block.x + BLOCK_SIZE / 2, y: block.y + BLOCK_SIZE / 2, scaleX: 8, scaleY: 8, alpha: 1.5, tint: 0xFFFFFF }); game.addChild(sparkle); // Random sparkle position around block var angle = j / sparkleCount * Math.PI * 2; var distance = BLOCK_SIZE * 1.0; var targetX = sparkle.x + Math.cos(angle) * distance; var targetY = sparkle.y + Math.sin(angle) * distance; // Animate sparkle outward and fade tween(sparkle, { x: targetX, y: targetY, alpha: 0.3, scaleX: 0.3, scaleY: 0.3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { if (sparkle && sparkle.destroy) { sparkle.destroy(); } } }); } } } // Remove blocks from this tetromino since they're now part of the grid self.blocks = []; LK.getSound('sparkle_effect').play(); LK.getSound('piece_drop').play(); checkCompleteLines(); // Clear current piece reference first currentPiece = null; // Spawn new piece with a small delay to ensure proper sequencing LK.setTimeout(function () { spawnNewPiece(); }, 50); }; self.destroy = function () { // Clean up all blocks when tetromino is destroyed for (var i = 0; i < self.blocks.length; i++) { if (self.blocks[i] && self.blocks[i].destroy) { self.blocks[i].destroy(); } } self.blocks = []; // Call parent destroy Container.prototype.destroy.call(self); }; return self; }); /**** * Initialize Game ****/ // Game constants var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Orange // Blue // Red // Green // Purple // Yellow // Cyan // Tetromino blocks - using different colors for each piece type // Game constants var GRID_WIDTH = 14; var GRID_HEIGHT = 24; var BLOCK_SIZE = 100; var GRID_OFFSET_X = (2048 - GRID_WIDTH * BLOCK_SIZE) / 2; var GRID_OFFSET_Y = 100; // Game variables var gameGrid = []; var currentPiece = null; var nextPieceType = null; var gameLevel = 1; var linesCleared = 0; var lastMoveTime = 0; var moveDelay = 100; // Milliseconds between moves // Initialize grid for (var y = 0; y < GRID_HEIGHT; y++) { gameGrid[y] = []; for (var x = 0; x < GRID_WIDTH; x++) { gameGrid[y][x] = null; } } // Tetromino types var pieceTypes = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; function getRandomPieceType() { return pieceTypes[Math.floor(Math.random() * pieceTypes.length)]; } function spawnNewPiece() { // Don't spawn if there's already an active piece or if one is being placed if (currentPiece && !currentPiece.isPlaced) { return; } if (!nextPieceType) { nextPieceType = getRandomPieceType(); } // Create new piece and set as current immediately to prevent double spawning var newPiece = new Tetromino(nextPieceType); currentPiece = newPiece; game.addChild(currentPiece); currentPiece.createBlocks(); nextPieceType = getRandomPieceType(); // Check game over if (!currentPiece.canMoveTo(currentPiece.gridX, currentPiece.gridY)) { LK.showGameOver(); return; } } function checkCompleteLines() { var completedLines = []; // Find completed lines for (var y = 0; y < GRID_HEIGHT; y++) { var lineComplete = true; for (var x = 0; x < GRID_WIDTH; x++) { if (!gameGrid[y][x]) { lineComplete = false; break; } } if (lineComplete) { completedLines.push(y); } } if (completedLines.length > 0) { // Sort completed lines from bottom to top (highest Y to lowest Y) // This ensures we process lines from bottom up, keeping indices valid completedLines.sort(function (a, b) { return b - a; }); // Remove completed lines for (var i = 0; i < completedLines.length; i++) { var lineY = completedLines[i]; // Create particle explosion effect for this line for (var x = 0; x < GRID_WIDTH; x++) { if (gameGrid[lineY][x]) { var block = gameGrid[lineY][x]; // Create sparkle effect for cleared line blocks var sparkleCount = 8; //{2X_new} for (var j = 0; j < sparkleCount; j++) { //{2X_new2} var sparkle = LK.getAsset('grid_border', { //{2X_new3} x: block.x + BLOCK_SIZE / 2, //{2X_new4} y: block.y + BLOCK_SIZE / 2, //{2X_new5} scaleX: 5, //{2X_new6} scaleY: 5, //{2X_new7} alpha: 1.5, //{2X_new8} tint: 0xFFFFFF //{2X_new9} }); //{2X_new10} game.addChild(sparkle); //{2X_new11} // Random sparkle position around block//{2X_new12} var angle = j / sparkleCount * Math.PI * 2; //{2X_new13} var distance = BLOCK_SIZE * 1.0; //{2X_new14} var targetX = sparkle.x + Math.cos(angle) * distance; //{2X_new15} var targetY = sparkle.y + Math.sin(angle) * distance; //{2X_new16} // Animate sparkle outward and fade//{2X_new17} tween(sparkle, { //{2X_new18} x: targetX, //{2X_new19} y: targetY, //{2X_new20} alpha: 0.3, //{2X_new21} scaleX: 0.3, //{2X_new22} scaleY: 0.3 //{2X_new23} }, { //{2X_new24} duration: 200, //{2X_new25} easing: tween.easeOut, //{2X_new26} onFinish: function onFinish() { //{2X_new27} if (sparkle && sparkle.destroy) { //{2X_new28} sparkle.destroy(); //{2X_new29} } //{2X_new30} } //{2X_new31} }); //{2X_new32} } //{2X_new33} // Create explosion effect before destroying var originalX = block.x; var originalY = block.y; var originalScaleX = block.scaleX; var originalScaleY = block.scaleY; var originalAlpha = block.alpha; // Random direction for explosion var randomX = originalX + (Math.random() - 0.5) * 400; var randomY = originalY + (Math.random() - 0.5) * 200; // Animate block flying away and fading tween(block, { x: randomX, y: randomY, scaleX: originalScaleX * 0.2, scaleY: originalScaleY * 0.2, alpha: 0, rotation: (Math.random() - 0.5) * Math.PI * 2 }, { duration: 30, easing: tween.easeOut, onFinish: function onFinish() { if (block && block.destroy) { block.destroy(); } } }); gameGrid[lineY][x] = null; } } // Move lines down for (var y = lineY; y > 0; y--) { for (var x = 0; x < GRID_WIDTH; x++) { gameGrid[y][x] = gameGrid[y - 1][x]; if (gameGrid[y][x]) { gameGrid[y][x].setGridPosition(x, y); } } } // Clear top line for (var x = 0; x < GRID_WIDTH; x++) { gameGrid[0][x] = null; } } // Update score linesCleared += completedLines.length; var points = 0; switch (completedLines.length) { case 1: points = 100; break; case 2: points = 300; break; case 3: points = 500; break; case 4: points = 800; break; } LK.setScore(LK.getScore() + points * gameLevel); // Level up every 10 lines var newLevel = Math.floor(linesCleared / 10) + 1; if (newLevel > gameLevel) { gameLevel = newLevel; } // Create border sparkle effect using line clear sparkles when lines are cleared var borderSparkles = []; // Left border sparkles for (var i = 0; i < 10; i++) { var sparkle = LK.getAsset('grid_border', { x: GRID_OFFSET_X - 20, y: GRID_OFFSET_Y + i * (GRID_HEIGHT * BLOCK_SIZE / 10), scaleX: 5, scaleY: 5, alpha: 1.5, tint: 0xFFFFFF }); game.addChild(sparkle); borderSparkles.push(sparkle); // Random sparkle position for border effect//{3K_new} var angle = i / 10 * Math.PI * 2; //{3K_new2} var distance = 50; //{3K_new3} var targetX = sparkle.x + Math.cos(angle) * distance; //{3K_new4} var targetY = sparkle.y + Math.sin(angle) * distance; //{3K_new5} // Animate sparkle outward and fade//{3K_new6} tween(sparkle, { //{3K_new7} x: targetX, //{3K_new8} y: targetY, //{3K_new9} alpha: 0.3, //{3K_new10} scaleX: 0.3, //{3K_new11} scaleY: 0.3 //{3K_new12} }, { //{3K_new13} duration: 200, //{3K_new14} easing: tween.easeOut, //{3K_new15} onFinish: function onFinish() { //{3K_new16} if (sparkle && sparkle.destroy) { //{3K_new17} sparkle.destroy(); //{3K_new18} } //{3K_new19} } //{3K_new20} }); //{3K_new21} } // Right border sparkles for (var i = 0; i < 10; i++) { var sparkle = LK.getAsset('grid_border', { x: GRID_OFFSET_X + GRID_WIDTH * BLOCK_SIZE + 20, y: GRID_OFFSET_Y + i * (GRID_HEIGHT * BLOCK_SIZE / 10), scaleX: 5, scaleY: 5, alpha: 1.5, tint: 0xFFFFFF }); game.addChild(sparkle); borderSparkles.push(sparkle); // Random sparkle position for border effect//{3V_new} var angle = i / 10 * Math.PI * 2; //{3V_new2} var distance = 50; //{3V_new3} var targetX = sparkle.x + Math.cos(angle) * distance; //{3V_new4} var targetY = sparkle.y + Math.sin(angle) * distance; //{3V_new5} // Animate sparkle outward and fade//{3V_new6} tween(sparkle, { //{3V_new7} x: targetX, //{3V_new8} y: targetY, //{3V_new9} alpha: 0.3, //{3V_new10} scaleX: 0.3, //{3V_new11} scaleY: 0.3 //{3V_new12} }, { //{3V_new13} duration: 200, //{3V_new14} easing: tween.easeOut, //{3V_new15} onFinish: function onFinish() { //{3V_new16} if (sparkle && sparkle.destroy) { //{3V_new17} sparkle.destroy(); //{3V_new18} } //{3V_new19} } //{3V_new20} }); //{3V_new21} } LK.getSound('sparkle_effect').play(); //{3j_new} LK.getSound('line_clear').play(); } } // Create score display var scoreText = new Text2('Score: 0', { size: 40, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); scoreText.x = -50; LK.gui.topRight.addChild(scoreText); var levelText = new Text2('Level: 1', { size: 40, fill: 0xFFFFFF }); levelText.anchor.set(1, 0); levelText.x = -50; levelText.y = 60; LK.gui.topRight.addChild(levelText); var linesText = new Text2('Lines: 0', { size: 40, fill: 0xFFFFFF }); linesText.anchor.set(1, 0); linesText.x = -50; linesText.y = 120; LK.gui.topRight.addChild(linesText); // Add background color asset var backgroundColorAsset = LK.getAsset('background_color', { x: 0, y: 0 }); game.addChild(backgroundColorAsset); // Draw grid borders - vertical lines only for game area height for (var x = 0; x <= GRID_WIDTH; x++) { if (x === 0 || x === GRID_WIDTH) { var border = LK.getAsset('grid_border', { x: GRID_OFFSET_X + x * BLOCK_SIZE - 4, y: GRID_OFFSET_Y, scaleX: 1, scaleY: GRID_HEIGHT * BLOCK_SIZE / 8 }); game.addChild(border); } } for (var y = GRID_HEIGHT; y <= GRID_HEIGHT; y++) { for (var x = 0; x < GRID_WIDTH; x++) { var border = LK.getAsset('grid_border', { x: GRID_OFFSET_X + x * BLOCK_SIZE, y: GRID_OFFSET_Y + y * BLOCK_SIZE, scaleX: BLOCK_SIZE / 8, scaleY: 1 }); game.addChild(border); } } // Spawn first piece spawnNewPiece(); // Start background music LK.playMusic('tetris_theme'); game.down = function (x, y, obj) { if (!currentPiece) return; var now = Date.now(); if (now - lastMoveTime < moveDelay) return; lastMoveTime = now; // Divide screen into zones for controls var leftZone = 2048 * 0.25; var rightZone = 2048 * 0.75; var rotateZone = 2732 * 0.7; if (x < leftZone) { // Left movement currentPiece.move(-1, 0); } else if (x > rightZone) { // Right movement currentPiece.move(1, 0); } else if (y > rotateZone) { // Drop piece faster currentPiece.move(0, 1); } else { // Rotate piece currentPiece.rotate(); } }; game.update = function () { if (currentPiece) { // Update fall speed based on level currentPiece.fallSpeed = Math.max(10, 40 - (gameLevel - 1) * 5); } // Update UI scoreText.setText('Score: ' + LK.getScore()); levelText.setText('Level: ' + gameLevel); linesText.setText('Lines: ' + linesCleared); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Block = Container.expand(function (blockType) {
var self = Container.call(this);
self.blockType = blockType || 'block_I';
self.gridX = 0;
self.gridY = 0;
var blockGraphics = self.attachAsset(self.blockType, {
anchorX: 0,
anchorY: 0
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_OFFSET_X + gridX * BLOCK_SIZE;
self.y = GRID_OFFSET_Y + gridY * BLOCK_SIZE;
};
return self;
});
var Tetromino = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'I';
self.rotation = 0;
self.gridX = 7; // Start in middle of board
self.gridY = 0;
self.blocks = [];
self.fallTimer = 0;
self.fallSpeed = 40; // Frames until next fall (faster falling speed)
self.isPlaced = false; // Prevent multiple placement calls
// Tetromino shapes and rotations
self.shapes = {
'I': [[[1, 1, 1, 1]], [[1], [1], [1], [1]], [[1, 1, 1, 1]], [[1], [1], [1], [1]]],
'O': [[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]],
'T': [[[0, 1, 0], [1, 1, 1]], [[1, 0], [1, 1], [1, 0]], [[1, 1, 1], [0, 1, 0]], [[0, 1], [1, 1], [0, 1]]],
'S': [[[0, 1, 1], [1, 1, 0]], [[1, 0], [1, 1], [0, 1]], [[0, 1, 1], [1, 1, 0]], [[1, 0], [1, 1], [0, 1]]],
'Z': [[[1, 1, 0], [0, 1, 1]], [[0, 1], [1, 1], [1, 0]], [[1, 1, 0], [0, 1, 1]], [[0, 1], [1, 1], [1, 0]]],
'J': [[[1, 0, 0], [1, 1, 1]], [[1, 1], [1, 0], [1, 0]], [[1, 1, 1], [0, 0, 1]], [[0, 1], [0, 1], [1, 1]]],
'L': [[[0, 0, 1], [1, 1, 1]], [[1, 0], [1, 0], [1, 1]], [[1, 1, 1], [1, 0, 0]], [[1, 1], [0, 1], [0, 1]]]
};
self.getBlockType = function () {
// Map each tetromino type to its corresponding block asset
var blockTypeMap = {
'I': 'block_I',
'O': 'block_O',
'T': 'block_T',
'S': 'block_S',
'Z': 'block_Z',
'J': 'block_J',
'L': 'block_L'
};
return blockTypeMap[self.type] || 'block_I';
};
self.createBlocks = function () {
// Clear existing blocks
for (var i = 0; i < self.blocks.length; i++) {
self.blocks[i].destroy();
}
self.blocks = [];
// Ensure we have a valid shape for this type
if (!self.shapes[self.type]) {
console.error('Invalid tetromino type:', self.type);
return;
}
var shape = self.shapes[self.type][self.rotation];
var blockType = self.getBlockType();
for (var y = 0; y < shape.length; y++) {
for (var x = 0; x < shape[y].length; x++) {
if (shape[y][x] === 1) {
var block = new Block(blockType);
block.setGridPosition(self.gridX + x, self.gridY + y);
self.blocks.push(block);
game.addChild(block);
}
}
}
};
self.updatePosition = function () {
var shape = self.shapes[self.type][self.rotation];
var blockIndex = 0;
for (var y = 0; y < shape.length; y++) {
for (var x = 0; x < shape[y].length; x++) {
if (shape[y][x] === 1) {
if (blockIndex < self.blocks.length) {
self.blocks[blockIndex].setGridPosition(self.gridX + x, self.gridY + y);
}
blockIndex++;
}
}
}
};
self.canMoveTo = function (newX, newY, newRotation) {
var testRotation = newRotation !== undefined ? newRotation : self.rotation;
var shape = self.shapes[self.type][testRotation];
for (var y = 0; y < shape.length; y++) {
for (var x = 0; x < shape[y].length; x++) {
if (shape[y][x] === 1) {
var checkX = newX + x;
var checkY = newY + y;
// Check bounds
if (checkX < 0 || checkX >= GRID_WIDTH || checkY >= GRID_HEIGHT) {
return false;
}
// Check collision with placed blocks
if (checkY >= 0 && gameGrid[checkY] && gameGrid[checkY][checkX]) {
return false;
}
}
}
}
return true;
};
self.move = function (deltaX, deltaY) {
if (self.canMoveTo(self.gridX + deltaX, self.gridY + deltaY)) {
self.gridX += deltaX;
self.gridY += deltaY;
self.updatePosition();
return true;
}
return false;
};
self.rotate = function () {
var newRotation = (self.rotation + 1) % 4;
if (self.canMoveTo(self.gridX, self.gridY, newRotation)) {
self.rotation = newRotation;
self.updatePosition();
// Create sparkle effect for rotation
for (var i = 0; i < self.blocks.length; i++) {
var block = self.blocks[i];
var sparkleCount = 8;
for (var j = 0; j < sparkleCount; j++) {
var sparkle = LK.getAsset('grid_border', {
x: block.x + BLOCK_SIZE / 2,
y: block.y + BLOCK_SIZE / 2,
scaleX: 5,
scaleY: 5,
alpha: 1.5,
tint: 0xFFFFFF
});
game.addChild(sparkle);
// Random sparkle position around block
var angle = j / sparkleCount * Math.PI * 2;
var distance = BLOCK_SIZE * 1.0;
var targetX = sparkle.x + Math.cos(angle) * distance;
var targetY = sparkle.y + Math.sin(angle) * distance;
// Animate sparkle outward and fade
tween(sparkle, {
x: targetX,
y: targetY,
alpha: 0.3,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (sparkle && sparkle.destroy) {
sparkle.destroy();
}
}
});
}
}
LK.getSound('sparkle_effect').play();
LK.getSound('piece_rotate').play();
return true;
}
return false;
};
self.update = function () {
self.fallTimer++;
if (self.fallTimer >= self.fallSpeed) {
self.fallTimer = 0;
if (!self.move(0, 1)) {
// Piece has landed
self.placePiece();
}
}
};
self.placePiece = function () {
// Prevent multiple calls
if (self.isPlaced) return;
self.isPlaced = true;
// Add blocks to grid and create sparkle effects
for (var i = 0; i < self.blocks.length; i++) {
var block = self.blocks[i];
if (block.gridY >= 0) {
if (!gameGrid[block.gridY]) gameGrid[block.gridY] = [];
gameGrid[block.gridY][block.gridX] = block;
// Create sparkle effect around the block
var sparkleCount = 8;
for (var j = 0; j < sparkleCount; j++) {
var sparkle = LK.getAsset('grid_border', {
x: block.x + BLOCK_SIZE / 2,
y: block.y + BLOCK_SIZE / 2,
scaleX: 8,
scaleY: 8,
alpha: 1.5,
tint: 0xFFFFFF
});
game.addChild(sparkle);
// Random sparkle position around block
var angle = j / sparkleCount * Math.PI * 2;
var distance = BLOCK_SIZE * 1.0;
var targetX = sparkle.x + Math.cos(angle) * distance;
var targetY = sparkle.y + Math.sin(angle) * distance;
// Animate sparkle outward and fade
tween(sparkle, {
x: targetX,
y: targetY,
alpha: 0.3,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (sparkle && sparkle.destroy) {
sparkle.destroy();
}
}
});
}
}
}
// Remove blocks from this tetromino since they're now part of the grid
self.blocks = [];
LK.getSound('sparkle_effect').play();
LK.getSound('piece_drop').play();
checkCompleteLines();
// Clear current piece reference first
currentPiece = null;
// Spawn new piece with a small delay to ensure proper sequencing
LK.setTimeout(function () {
spawnNewPiece();
}, 50);
};
self.destroy = function () {
// Clean up all blocks when tetromino is destroyed
for (var i = 0; i < self.blocks.length; i++) {
if (self.blocks[i] && self.blocks[i].destroy) {
self.blocks[i].destroy();
}
}
self.blocks = [];
// Call parent destroy
Container.prototype.destroy.call(self);
};
return self;
});
/****
* Initialize Game
****/
// Game constants
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Orange
// Blue
// Red
// Green
// Purple
// Yellow
// Cyan
// Tetromino blocks - using different colors for each piece type
// Game constants
var GRID_WIDTH = 14;
var GRID_HEIGHT = 24;
var BLOCK_SIZE = 100;
var GRID_OFFSET_X = (2048 - GRID_WIDTH * BLOCK_SIZE) / 2;
var GRID_OFFSET_Y = 100;
// Game variables
var gameGrid = [];
var currentPiece = null;
var nextPieceType = null;
var gameLevel = 1;
var linesCleared = 0;
var lastMoveTime = 0;
var moveDelay = 100; // Milliseconds between moves
// Initialize grid
for (var y = 0; y < GRID_HEIGHT; y++) {
gameGrid[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
gameGrid[y][x] = null;
}
}
// Tetromino types
var pieceTypes = ['I', 'O', 'T', 'S', 'Z', 'J', 'L'];
function getRandomPieceType() {
return pieceTypes[Math.floor(Math.random() * pieceTypes.length)];
}
function spawnNewPiece() {
// Don't spawn if there's already an active piece or if one is being placed
if (currentPiece && !currentPiece.isPlaced) {
return;
}
if (!nextPieceType) {
nextPieceType = getRandomPieceType();
}
// Create new piece and set as current immediately to prevent double spawning
var newPiece = new Tetromino(nextPieceType);
currentPiece = newPiece;
game.addChild(currentPiece);
currentPiece.createBlocks();
nextPieceType = getRandomPieceType();
// Check game over
if (!currentPiece.canMoveTo(currentPiece.gridX, currentPiece.gridY)) {
LK.showGameOver();
return;
}
}
function checkCompleteLines() {
var completedLines = [];
// Find completed lines
for (var y = 0; y < GRID_HEIGHT; y++) {
var lineComplete = true;
for (var x = 0; x < GRID_WIDTH; x++) {
if (!gameGrid[y][x]) {
lineComplete = false;
break;
}
}
if (lineComplete) {
completedLines.push(y);
}
}
if (completedLines.length > 0) {
// Sort completed lines from bottom to top (highest Y to lowest Y)
// This ensures we process lines from bottom up, keeping indices valid
completedLines.sort(function (a, b) {
return b - a;
});
// Remove completed lines
for (var i = 0; i < completedLines.length; i++) {
var lineY = completedLines[i];
// Create particle explosion effect for this line
for (var x = 0; x < GRID_WIDTH; x++) {
if (gameGrid[lineY][x]) {
var block = gameGrid[lineY][x];
// Create sparkle effect for cleared line blocks
var sparkleCount = 8; //{2X_new}
for (var j = 0; j < sparkleCount; j++) {
//{2X_new2}
var sparkle = LK.getAsset('grid_border', {
//{2X_new3}
x: block.x + BLOCK_SIZE / 2,
//{2X_new4}
y: block.y + BLOCK_SIZE / 2,
//{2X_new5}
scaleX: 5,
//{2X_new6}
scaleY: 5,
//{2X_new7}
alpha: 1.5,
//{2X_new8}
tint: 0xFFFFFF //{2X_new9}
}); //{2X_new10}
game.addChild(sparkle); //{2X_new11}
// Random sparkle position around block//{2X_new12}
var angle = j / sparkleCount * Math.PI * 2; //{2X_new13}
var distance = BLOCK_SIZE * 1.0; //{2X_new14}
var targetX = sparkle.x + Math.cos(angle) * distance; //{2X_new15}
var targetY = sparkle.y + Math.sin(angle) * distance; //{2X_new16}
// Animate sparkle outward and fade//{2X_new17}
tween(sparkle, {
//{2X_new18}
x: targetX,
//{2X_new19}
y: targetY,
//{2X_new20}
alpha: 0.3,
//{2X_new21}
scaleX: 0.3,
//{2X_new22}
scaleY: 0.3 //{2X_new23}
}, {
//{2X_new24}
duration: 200,
//{2X_new25}
easing: tween.easeOut,
//{2X_new26}
onFinish: function onFinish() {
//{2X_new27}
if (sparkle && sparkle.destroy) {
//{2X_new28}
sparkle.destroy(); //{2X_new29}
} //{2X_new30}
} //{2X_new31}
}); //{2X_new32}
} //{2X_new33}
// Create explosion effect before destroying
var originalX = block.x;
var originalY = block.y;
var originalScaleX = block.scaleX;
var originalScaleY = block.scaleY;
var originalAlpha = block.alpha;
// Random direction for explosion
var randomX = originalX + (Math.random() - 0.5) * 400;
var randomY = originalY + (Math.random() - 0.5) * 200;
// Animate block flying away and fading
tween(block, {
x: randomX,
y: randomY,
scaleX: originalScaleX * 0.2,
scaleY: originalScaleY * 0.2,
alpha: 0,
rotation: (Math.random() - 0.5) * Math.PI * 2
}, {
duration: 30,
easing: tween.easeOut,
onFinish: function onFinish() {
if (block && block.destroy) {
block.destroy();
}
}
});
gameGrid[lineY][x] = null;
}
}
// Move lines down
for (var y = lineY; y > 0; y--) {
for (var x = 0; x < GRID_WIDTH; x++) {
gameGrid[y][x] = gameGrid[y - 1][x];
if (gameGrid[y][x]) {
gameGrid[y][x].setGridPosition(x, y);
}
}
}
// Clear top line
for (var x = 0; x < GRID_WIDTH; x++) {
gameGrid[0][x] = null;
}
}
// Update score
linesCleared += completedLines.length;
var points = 0;
switch (completedLines.length) {
case 1:
points = 100;
break;
case 2:
points = 300;
break;
case 3:
points = 500;
break;
case 4:
points = 800;
break;
}
LK.setScore(LK.getScore() + points * gameLevel);
// Level up every 10 lines
var newLevel = Math.floor(linesCleared / 10) + 1;
if (newLevel > gameLevel) {
gameLevel = newLevel;
}
// Create border sparkle effect using line clear sparkles when lines are cleared
var borderSparkles = [];
// Left border sparkles
for (var i = 0; i < 10; i++) {
var sparkle = LK.getAsset('grid_border', {
x: GRID_OFFSET_X - 20,
y: GRID_OFFSET_Y + i * (GRID_HEIGHT * BLOCK_SIZE / 10),
scaleX: 5,
scaleY: 5,
alpha: 1.5,
tint: 0xFFFFFF
});
game.addChild(sparkle);
borderSparkles.push(sparkle);
// Random sparkle position for border effect//{3K_new}
var angle = i / 10 * Math.PI * 2; //{3K_new2}
var distance = 50; //{3K_new3}
var targetX = sparkle.x + Math.cos(angle) * distance; //{3K_new4}
var targetY = sparkle.y + Math.sin(angle) * distance; //{3K_new5}
// Animate sparkle outward and fade//{3K_new6}
tween(sparkle, {
//{3K_new7}
x: targetX,
//{3K_new8}
y: targetY,
//{3K_new9}
alpha: 0.3,
//{3K_new10}
scaleX: 0.3,
//{3K_new11}
scaleY: 0.3 //{3K_new12}
}, {
//{3K_new13}
duration: 200,
//{3K_new14}
easing: tween.easeOut,
//{3K_new15}
onFinish: function onFinish() {
//{3K_new16}
if (sparkle && sparkle.destroy) {
//{3K_new17}
sparkle.destroy(); //{3K_new18}
} //{3K_new19}
} //{3K_new20}
}); //{3K_new21}
}
// Right border sparkles
for (var i = 0; i < 10; i++) {
var sparkle = LK.getAsset('grid_border', {
x: GRID_OFFSET_X + GRID_WIDTH * BLOCK_SIZE + 20,
y: GRID_OFFSET_Y + i * (GRID_HEIGHT * BLOCK_SIZE / 10),
scaleX: 5,
scaleY: 5,
alpha: 1.5,
tint: 0xFFFFFF
});
game.addChild(sparkle);
borderSparkles.push(sparkle);
// Random sparkle position for border effect//{3V_new}
var angle = i / 10 * Math.PI * 2; //{3V_new2}
var distance = 50; //{3V_new3}
var targetX = sparkle.x + Math.cos(angle) * distance; //{3V_new4}
var targetY = sparkle.y + Math.sin(angle) * distance; //{3V_new5}
// Animate sparkle outward and fade//{3V_new6}
tween(sparkle, {
//{3V_new7}
x: targetX,
//{3V_new8}
y: targetY,
//{3V_new9}
alpha: 0.3,
//{3V_new10}
scaleX: 0.3,
//{3V_new11}
scaleY: 0.3 //{3V_new12}
}, {
//{3V_new13}
duration: 200,
//{3V_new14}
easing: tween.easeOut,
//{3V_new15}
onFinish: function onFinish() {
//{3V_new16}
if (sparkle && sparkle.destroy) {
//{3V_new17}
sparkle.destroy(); //{3V_new18}
} //{3V_new19}
} //{3V_new20}
}); //{3V_new21}
}
LK.getSound('sparkle_effect').play(); //{3j_new}
LK.getSound('line_clear').play();
}
}
// Create score display
var scoreText = new Text2('Score: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -50;
LK.gui.topRight.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
levelText.x = -50;
levelText.y = 60;
LK.gui.topRight.addChild(levelText);
var linesText = new Text2('Lines: 0', {
size: 40,
fill: 0xFFFFFF
});
linesText.anchor.set(1, 0);
linesText.x = -50;
linesText.y = 120;
LK.gui.topRight.addChild(linesText);
// Add background color asset
var backgroundColorAsset = LK.getAsset('background_color', {
x: 0,
y: 0
});
game.addChild(backgroundColorAsset);
// Draw grid borders - vertical lines only for game area height
for (var x = 0; x <= GRID_WIDTH; x++) {
if (x === 0 || x === GRID_WIDTH) {
var border = LK.getAsset('grid_border', {
x: GRID_OFFSET_X + x * BLOCK_SIZE - 4,
y: GRID_OFFSET_Y,
scaleX: 1,
scaleY: GRID_HEIGHT * BLOCK_SIZE / 8
});
game.addChild(border);
}
}
for (var y = GRID_HEIGHT; y <= GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
var border = LK.getAsset('grid_border', {
x: GRID_OFFSET_X + x * BLOCK_SIZE,
y: GRID_OFFSET_Y + y * BLOCK_SIZE,
scaleX: BLOCK_SIZE / 8,
scaleY: 1
});
game.addChild(border);
}
}
// Spawn first piece
spawnNewPiece();
// Start background music
LK.playMusic('tetris_theme');
game.down = function (x, y, obj) {
if (!currentPiece) return;
var now = Date.now();
if (now - lastMoveTime < moveDelay) return;
lastMoveTime = now;
// Divide screen into zones for controls
var leftZone = 2048 * 0.25;
var rightZone = 2048 * 0.75;
var rotateZone = 2732 * 0.7;
if (x < leftZone) {
// Left movement
currentPiece.move(-1, 0);
} else if (x > rightZone) {
// Right movement
currentPiece.move(1, 0);
} else if (y > rotateZone) {
// Drop piece faster
currentPiece.move(0, 1);
} else {
// Rotate piece
currentPiece.rotate();
}
};
game.update = function () {
if (currentPiece) {
// Update fall speed based on level
currentPiece.fallSpeed = Math.max(10, 40 - (gameLevel - 1) * 5);
}
// Update UI
scoreText.setText('Score: ' + LK.getScore());
levelText.setText('Level: ' + gameLevel);
linesText.setText('Lines: ' + linesCleared);
};