User prompt
Puanı ekranın altına al
User prompt
Level yazısının yanına alev koyabilir misin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Daha belirgin hale getir ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ejdere animasyon ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Biraz daha soluklaştır
User prompt
Biraz daha soluklaştır
User prompt
Blokların düşeceği yeri önizle
User prompt
Ejderi 3 cm aşağı al
User prompt
Yukarıya ejderha koy ve blokları o atsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
İçinde gösterilen bloğu oturt karenin içine
User prompt
Biraz daha büyüt
User prompt
Sağ taraftaki kareyi büyüt biraz
User prompt
Şimdi sonraki gelecek bloğu sağ tarafta göster
User prompt
Kenarları daralt
User prompt
Ekranı kapla
Code edit (1 edits merged)
Please save this source code
User prompt
Tetris Yap
Initial prompt
Tetris yap
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Dragon = Container.expand(function () { var self = Container.call(this); self.dragonGraphics = self.attachAsset('dragon', { anchorX: 0.5, anchorY: 0.5 }); // Start idle wing flapping animation self.startIdleAnimation = function () { // Wing flapping - more pronounced scale and rotation changes tween(self.dragonGraphics, { scaleX: 1.3, scaleY: 0.8, rotation: 0.15 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.dragonGraphics, { scaleX: 1.0, scaleY: 1.0, rotation: -0.15 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { // Continue the idle animation loop self.startIdleAnimation(); } }); } }); }; // Start the idle animation immediately self.startIdleAnimation(); self.throwPiece = function (piece) { // Stop idle animation temporarily tween.stop(self.dragonGraphics); // Add throwing animation - more dramatic bounce effect tween(self.dragonGraphics, { scaleY: 0.5, scaleX: 1.5, rotation: 0.25 }, { duration: 80, easing: tween.easeOut }); tween(self, { scaleY: 0.6 }, { duration: 120, easing: tween.easeOut }); tween(self, { scaleY: 1.0 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { // Reset dragon graphics and restart idle animation tween(self.dragonGraphics, { scaleY: 1.0, scaleX: 1.0, rotation: 0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { self.startIdleAnimation(); } }); // After throw animation, animate the piece falling if (piece) { var startY = piece.y; piece.y = self.y + 50; // Start from dragon position tween(piece, { y: startY }, { duration: 800, easing: tween.easeIn }); } } }); }; return self; }); var GhostBlock = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.blockGraphics = self.attachAsset('tetromino' + type, { anchorX: 0, anchorY: 0 }); // Make ghost block more transparent self.blockGraphics.alpha = 0.08; return self; }); var Tetromino = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.blocks = []; self.currentRotation = 0; // Define tetromino shapes and rotations self.shapes = { 'I': [[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]], 'O': [[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]], 'T': [[[0, 1, 0], [1, 1, 1], [0, 0, 0]], [[0, 1, 0], [0, 1, 1], [0, 1, 0]], [[0, 0, 0], [1, 1, 1], [0, 1, 0]], [[0, 1, 0], [1, 1, 0], [0, 1, 0]]], 'S': [[[0, 1, 1], [1, 1, 0], [0, 0, 0]], [[0, 1, 0], [0, 1, 1], [0, 0, 1]], [[0, 0, 0], [0, 1, 1], [1, 1, 0]], [[1, 0, 0], [1, 1, 0], [0, 1, 0]]], 'Z': [[[1, 1, 0], [0, 1, 1], [0, 0, 0]], [[0, 0, 1], [0, 1, 1], [0, 1, 0]], [[0, 0, 0], [1, 1, 0], [0, 1, 1]], [[0, 1, 0], [1, 1, 0], [1, 0, 0]]], 'J': [[[1, 0, 0], [1, 1, 1], [0, 0, 0]], [[0, 1, 1], [0, 1, 0], [0, 1, 0]], [[0, 0, 0], [1, 1, 1], [0, 0, 1]], [[0, 1, 0], [0, 1, 0], [1, 1, 0]]], 'L': [[[0, 0, 1], [1, 1, 1], [0, 0, 0]], [[0, 1, 0], [0, 1, 0], [0, 1, 1]], [[0, 0, 0], [1, 1, 1], [1, 0, 0]], [[1, 1, 0], [0, 1, 0], [0, 1, 0]]] }; self.createBlocks = function () { // Clear existing blocks for (var i = 0; i < self.blocks.length; i++) { self.blocks[i].destroy(); } self.blocks = []; var shape = self.shapes[self.type][self.currentRotation]; for (var row = 0; row < shape.length; row++) { for (var col = 0; col < shape[row].length; col++) { if (shape[row][col] === 1) { var block = new TetrominoBlock(self.type); block.x = col * 100; block.y = row * 100; self.blocks.push(block); self.addChild(block); } } } }; self.rotate = function () { var newRotation = (self.currentRotation + 1) % 4; var oldRotation = self.currentRotation; self.currentRotation = newRotation; self.createBlocks(); // Check if rotation is valid if (!self.isValidPosition()) { // Revert rotation if invalid self.currentRotation = oldRotation; self.createBlocks(); return false; } LK.getSound('rotate').play(); updateGhostPiece(); return true; }; self.isValidPosition = function () { var shape = self.shapes[self.type][self.currentRotation]; var boardX = Math.floor((self.x - boardOffsetX) / 100); var boardY = Math.floor((self.y - boardOffsetY) / 100); for (var row = 0; row < shape.length; row++) { for (var col = 0; col < shape[row].length; col++) { if (shape[row][col] === 1) { var checkX = boardX + col; var checkY = boardY + row; // Check boundaries if (checkX < 0 || checkX >= boardWidth || checkY >= boardHeight) { return false; } // Check collision with placed blocks if (checkY >= 0 && board[checkY] && board[checkY][checkX] !== null) { return false; } } } } return true; }; // Initialize with blocks self.createBlocks(); return self; }); var TetrominoBlock = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.blockGraphics = self.attachAsset('tetromino' + type, { anchorX: 0, anchorY: 0 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111111 }); /**** * Game Code ****/ // Game constants // Tetromino blocks // Board elements // Sound effects var boardWidth = 10; var boardHeight = 20; var blockSize = 100; var boardOffsetX = 524; var boardOffsetY = 200; // Game state var board = []; var currentPiece = null; var nextPiece = null; var nextPieceType = null; var nextPiecePreview = null; var ghostPiece = null; var nextPieces = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; var fallTimer = 0; var fallSpeed = 60; // frames per fall var level = 1; var linesCleared = 0; var isGameOver = false; var dragon = null; // Initialize board function initializeBoard() { board = []; for (var row = 0; row < boardHeight; row++) { board[row] = []; for (var col = 0; col < boardWidth; col++) { board[row][col] = null; } } } // Create next piece preview area function createNextPiecePreview() { var previewX = boardOffsetX + boardWidth * blockSize + 50; var previewY = boardOffsetY + 50; var previewSize = 400; // Preview border var previewBorder = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: 4, height: previewSize }); previewBorder.x = previewX - 4; previewBorder.y = previewY; game.addChild(previewBorder); var previewBorderRight = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: 4, height: previewSize }); previewBorderRight.x = previewX + previewSize; previewBorderRight.y = previewY; game.addChild(previewBorderRight); var previewBorderTop = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: previewSize + 8, height: 4 }); previewBorderTop.x = previewX - 4; previewBorderTop.y = previewY - 4; game.addChild(previewBorderTop); var previewBorderBottom = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: previewSize + 8, height: 4 }); previewBorderBottom.x = previewX - 4; previewBorderBottom.y = previewY + previewSize; game.addChild(previewBorderBottom); // Next piece label var nextLabel = new Text2('NEXT', { size: 40, fill: 0xFFFFFF }); nextLabel.anchor.set(0.5, 1); nextLabel.x = previewX + previewSize / 2; nextLabel.y = previewY - 10; game.addChild(nextLabel); } // Create board borders function createBoardBorders() { // Left border var leftBorder = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: 4, height: boardHeight * blockSize }); leftBorder.x = boardOffsetX - 4; leftBorder.y = boardOffsetY; game.addChild(leftBorder); // Right border var rightBorder = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: 4, height: boardHeight * blockSize }); rightBorder.x = boardOffsetX + boardWidth * blockSize; rightBorder.y = boardOffsetY; game.addChild(rightBorder); // Bottom border var bottomBorder = LK.getAsset('boardBorder', { anchorX: 0, anchorY: 0, width: boardWidth * blockSize + 8, height: 4 }); bottomBorder.x = boardOffsetX - 4; bottomBorder.y = boardOffsetY + boardHeight * blockSize; game.addChild(bottomBorder); } // Generate random piece type function getRandomPieceType() { var types = ['I', 'O', 'T', 'S', 'Z', 'J', 'L']; return types[Math.floor(Math.random() * types.length)]; } // Update next piece preview function updateNextPiecePreview() { // Clear existing preview if (nextPiecePreview) { nextPiecePreview.destroy(); } if (nextPieceType) { var previewX = boardOffsetX + boardWidth * blockSize + 50; var previewY = boardOffsetY + 50; var previewSize = 400; nextPiecePreview = new Tetromino(nextPieceType); // Get piece dimensions to center it properly var shape = nextPiecePreview.shapes[nextPieceType][0]; var pieceWidth = 0; var pieceHeight = shape.length; for (var row = 0; row < shape.length; row++) { pieceWidth = Math.max(pieceWidth, shape[row].length); } // Calculate center position within preview area var piecePixelWidth = pieceWidth * 100; var piecePixelHeight = pieceHeight * 100; var centerX = previewX + (previewSize - piecePixelWidth) / 2; var centerY = previewY + (previewSize - piecePixelHeight) / 2; nextPiecePreview.x = centerX; nextPiecePreview.y = centerY; // Scale down the preview piece nextPiecePreview.scaleX = 1.0; nextPiecePreview.scaleY = 1.0; game.addChild(nextPiecePreview); } } // Update ghost piece preview function updateGhostPiece() { // Clear existing ghost piece if (ghostPiece) { ghostPiece.destroy(); ghostPiece = null; } if (!currentPiece) return; // Create ghost piece container ghostPiece = new Container(); // Get current piece shape var shape = currentPiece.shapes[currentPiece.type][currentPiece.currentRotation]; // Find the lowest valid position for the current piece var testY = currentPiece.y; var validY = currentPiece.y; // Move test position down until it's no longer valid while (true) { testY += blockSize; // Check if this position would be valid var boardX = Math.floor((currentPiece.x - boardOffsetX) / blockSize); var boardY = Math.floor((testY - boardOffsetY) / blockSize); var isValid = true; for (var row = 0; row < shape.length && isValid; row++) { for (var col = 0; col < shape[row].length && isValid; col++) { if (shape[row][col] === 1) { var checkX = boardX + col; var checkY = boardY + row; // Check boundaries and collisions if (checkX < 0 || checkX >= boardWidth || checkY >= boardHeight) { isValid = false; } else if (checkY >= 0 && board[checkY] && board[checkY][checkX] !== null) { isValid = false; } } } } if (!isValid) { break; } validY = testY; } // Only show ghost piece if it's below the current piece if (validY > currentPiece.y) { // Create ghost blocks at the valid position for (var row = 0; row < shape.length; row++) { for (var col = 0; col < shape[row].length; col++) { if (shape[row][col] === 1) { var ghostBlock = new GhostBlock(currentPiece.type); ghostBlock.x = currentPiece.x + col * 100; ghostBlock.y = validY + row * 100; ghostPiece.addChild(ghostBlock); } } } game.addChild(ghostPiece); } } // Spawn new piece function spawnNewPiece() { if (currentPiece) { currentPiece.destroy(); } // Clear ghost piece when spawning new piece if (ghostPiece) { ghostPiece.destroy(); ghostPiece = null; } // Use next piece or generate first piece var pieceType; if (nextPieceType) { pieceType = nextPieceType; } else { pieceType = getRandomPieceType(); } // Generate new next piece nextPieceType = getRandomPieceType(); updateNextPiecePreview(); currentPiece = new Tetromino(pieceType); currentPiece.x = boardOffsetX + Math.floor(boardWidth / 2) * blockSize - blockSize; currentPiece.y = boardOffsetY; game.addChild(currentPiece); // Dragon throws the piece if (dragon) { dragon.throwPiece(currentPiece); } // Update ghost piece for new piece updateGhostPiece(); // Check if game over if (!currentPiece.isValidPosition()) { isGameOver = true; LK.showGameOver(); } } // Move piece down function movePieceDown() { if (!currentPiece) return false; currentPiece.y += blockSize; if (!currentPiece.isValidPosition()) { currentPiece.y -= blockSize; placePiece(); return false; } updateGhostPiece(); return true; } // Move piece left function movePieceLeft() { if (!currentPiece) return; currentPiece.x -= blockSize; if (!currentPiece.isValidPosition()) { currentPiece.x += blockSize; } else { updateGhostPiece(); } } // Move piece right function movePieceRight() { if (!currentPiece) return; currentPiece.x += blockSize; if (!currentPiece.isValidPosition()) { currentPiece.x -= blockSize; } else { updateGhostPiece(); } } // Place piece on board function placePiece() { if (!currentPiece) return; var shape = currentPiece.shapes[currentPiece.type][currentPiece.currentRotation]; var boardX = Math.floor((currentPiece.x - boardOffsetX) / blockSize); var boardY = Math.floor((currentPiece.y - boardOffsetY) / blockSize); // Place blocks on board for (var row = 0; row < shape.length; row++) { for (var col = 0; col < shape[row].length; col++) { if (shape[row][col] === 1) { var placeX = boardX + col; var placeY = boardY + row; if (placeY >= 0 && placeY < boardHeight && placeX >= 0 && placeX < boardWidth) { // Create placed block var placedBlock = new TetrominoBlock(currentPiece.type); placedBlock.x = boardOffsetX + placeX * blockSize; placedBlock.y = boardOffsetY + placeY * blockSize; game.addChild(placedBlock); board[placeY][placeX] = placedBlock; } } } } LK.getSound('pieceLand').play(); // Check for completed lines checkCompletedLines(); // Spawn new piece spawnNewPiece(); } // Check for completed lines function checkCompletedLines() { var completedLines = []; // Find completed lines for (var row = 0; row < boardHeight; row++) { var isComplete = true; for (var col = 0; col < boardWidth; col++) { if (board[row][col] === null) { isComplete = false; break; } } if (isComplete) { completedLines.push(row); } } // Clear completed lines if (completedLines.length > 0) { // Remove blocks from completed lines for (var i = 0; i < completedLines.length; i++) { var row = completedLines[i]; for (var col = 0; col < boardWidth; col++) { if (board[row][col]) { board[row][col].destroy(); board[row][col] = null; } } } // Drop lines above for (var i = completedLines.length - 1; i >= 0; i--) { var clearedRow = completedLines[i]; // Move all rows above down for (var row = clearedRow; row > 0; row--) { for (var col = 0; col < boardWidth; col++) { board[row][col] = board[row - 1][col]; if (board[row][col]) { board[row][col].y += blockSize; } } } // Clear top row for (var col = 0; col < boardWidth; col++) { board[0][col] = null; } // Adjust subsequent cleared rows for (var j = i + 1; j < completedLines.length; j++) { completedLines[j]++; } } // Update score var points = completedLines.length * 100 * level; if (completedLines.length === 4) points *= 2; // Tetris bonus LK.setScore(LK.getScore() + points); scoreTxt.setText(LK.getScore()); linesCleared += completedLines.length; level = Math.floor(linesCleared / 10) + 1; fallSpeed = Math.max(10, 60 - (level - 1) * 5); levelTxt.setText('Level: ' + level); linesTxt.setText('Lines: ' + linesCleared); LK.getSound('lineClear').play(); } } // Touch controls var touchStartX = 0; var touchStartY = 0; var isTouching = false; game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; isTouching = true; }; game.up = function (x, y, obj) { if (!isTouching) return; isTouching = false; var deltaX = x - touchStartX; var deltaY = y - touchStartY; // Swipe down for fast drop if (deltaY > 50 && Math.abs(deltaX) < 30) { while (movePieceDown()) { // Keep dropping until piece lands } return; } // Tap piece to rotate if (Math.abs(deltaX) < 30 && Math.abs(deltaY) < 30) { if (currentPiece) { currentPiece.rotate(); } return; } // Swipe left/right to move if (Math.abs(deltaX) > 30) { if (deltaX > 0) { movePieceRight(); } else { movePieceLeft(); } } }; // Initialize UI var scoreTxt = new Text2('0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 1); scoreTxt.setText(LK.getScore()); LK.gui.bottom.addChild(scoreTxt); var levelTxt = new Text2('Level: 1', { size: 40, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); levelTxt.x = 100; levelTxt.y = 100; LK.gui.topLeft.addChild(levelTxt); // Add flame next to level text var flameGraphics = LK.getAsset('flame', { anchorX: 0.5, anchorY: 0.5 }); flameGraphics.x = levelTxt.x + 200; // Position to the right of level text flameGraphics.y = levelTxt.y + 20; // Center vertically with text LK.gui.topLeft.addChild(flameGraphics); // Add flickering animation to flame function startFlameAnimation() { tween(flameGraphics, { scaleX: 1.2, scaleY: 0.8, alpha: 0.8 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(flameGraphics, { scaleX: 0.9, scaleY: 1.1, alpha: 1.0 }, { duration: 250, easing: tween.easeInOut, onFinish: function onFinish() { startFlameAnimation(); } }); } }); } startFlameAnimation(); var linesTxt = new Text2('Lines: 0', { size: 40, fill: 0xFFFFFF }); linesTxt.anchor.set(0, 0); linesTxt.x = 100; linesTxt.y = 150; LK.gui.topLeft.addChild(linesTxt); // Initialize dragon dragon = new Dragon(); dragon.x = boardOffsetX + boardWidth * blockSize / 2; dragon.y = boardOffsetY - 80; // Position above the game area (moved 120px down from -200 to -80) game.addChild(dragon); // Initialize game initializeBoard(); createBoardBorders(); createNextPiecePreview(); // Generate first next piece nextPieceType = getRandomPieceType(); updateNextPiecePreview(); spawnNewPiece(); // Game update loop game.update = function () { if (isGameOver) return; fallTimer++; if (fallTimer >= fallSpeed) { fallTimer = 0; movePieceDown(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Dragon = Container.expand(function () {
var self = Container.call(this);
self.dragonGraphics = self.attachAsset('dragon', {
anchorX: 0.5,
anchorY: 0.5
});
// Start idle wing flapping animation
self.startIdleAnimation = function () {
// Wing flapping - more pronounced scale and rotation changes
tween(self.dragonGraphics, {
scaleX: 1.3,
scaleY: 0.8,
rotation: 0.15
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.dragonGraphics, {
scaleX: 1.0,
scaleY: 1.0,
rotation: -0.15
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue the idle animation loop
self.startIdleAnimation();
}
});
}
});
};
// Start the idle animation immediately
self.startIdleAnimation();
self.throwPiece = function (piece) {
// Stop idle animation temporarily
tween.stop(self.dragonGraphics);
// Add throwing animation - more dramatic bounce effect
tween(self.dragonGraphics, {
scaleY: 0.5,
scaleX: 1.5,
rotation: 0.25
}, {
duration: 80,
easing: tween.easeOut
});
tween(self, {
scaleY: 0.6
}, {
duration: 120,
easing: tween.easeOut
});
tween(self, {
scaleY: 1.0
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset dragon graphics and restart idle animation
tween(self.dragonGraphics, {
scaleY: 1.0,
scaleX: 1.0,
rotation: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.startIdleAnimation();
}
});
// After throw animation, animate the piece falling
if (piece) {
var startY = piece.y;
piece.y = self.y + 50; // Start from dragon position
tween(piece, {
y: startY
}, {
duration: 800,
easing: tween.easeIn
});
}
}
});
};
return self;
});
var GhostBlock = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.blockGraphics = self.attachAsset('tetromino' + type, {
anchorX: 0,
anchorY: 0
});
// Make ghost block more transparent
self.blockGraphics.alpha = 0.08;
return self;
});
var Tetromino = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.blocks = [];
self.currentRotation = 0;
// Define tetromino shapes and rotations
self.shapes = {
'I': [[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]], [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]],
'O': [[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]],
'T': [[[0, 1, 0], [1, 1, 1], [0, 0, 0]], [[0, 1, 0], [0, 1, 1], [0, 1, 0]], [[0, 0, 0], [1, 1, 1], [0, 1, 0]], [[0, 1, 0], [1, 1, 0], [0, 1, 0]]],
'S': [[[0, 1, 1], [1, 1, 0], [0, 0, 0]], [[0, 1, 0], [0, 1, 1], [0, 0, 1]], [[0, 0, 0], [0, 1, 1], [1, 1, 0]], [[1, 0, 0], [1, 1, 0], [0, 1, 0]]],
'Z': [[[1, 1, 0], [0, 1, 1], [0, 0, 0]], [[0, 0, 1], [0, 1, 1], [0, 1, 0]], [[0, 0, 0], [1, 1, 0], [0, 1, 1]], [[0, 1, 0], [1, 1, 0], [1, 0, 0]]],
'J': [[[1, 0, 0], [1, 1, 1], [0, 0, 0]], [[0, 1, 1], [0, 1, 0], [0, 1, 0]], [[0, 0, 0], [1, 1, 1], [0, 0, 1]], [[0, 1, 0], [0, 1, 0], [1, 1, 0]]],
'L': [[[0, 0, 1], [1, 1, 1], [0, 0, 0]], [[0, 1, 0], [0, 1, 0], [0, 1, 1]], [[0, 0, 0], [1, 1, 1], [1, 0, 0]], [[1, 1, 0], [0, 1, 0], [0, 1, 0]]]
};
self.createBlocks = function () {
// Clear existing blocks
for (var i = 0; i < self.blocks.length; i++) {
self.blocks[i].destroy();
}
self.blocks = [];
var shape = self.shapes[self.type][self.currentRotation];
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col] === 1) {
var block = new TetrominoBlock(self.type);
block.x = col * 100;
block.y = row * 100;
self.blocks.push(block);
self.addChild(block);
}
}
}
};
self.rotate = function () {
var newRotation = (self.currentRotation + 1) % 4;
var oldRotation = self.currentRotation;
self.currentRotation = newRotation;
self.createBlocks();
// Check if rotation is valid
if (!self.isValidPosition()) {
// Revert rotation if invalid
self.currentRotation = oldRotation;
self.createBlocks();
return false;
}
LK.getSound('rotate').play();
updateGhostPiece();
return true;
};
self.isValidPosition = function () {
var shape = self.shapes[self.type][self.currentRotation];
var boardX = Math.floor((self.x - boardOffsetX) / 100);
var boardY = Math.floor((self.y - boardOffsetY) / 100);
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col] === 1) {
var checkX = boardX + col;
var checkY = boardY + row;
// Check boundaries
if (checkX < 0 || checkX >= boardWidth || checkY >= boardHeight) {
return false;
}
// Check collision with placed blocks
if (checkY >= 0 && board[checkY] && board[checkY][checkX] !== null) {
return false;
}
}
}
}
return true;
};
// Initialize with blocks
self.createBlocks();
return self;
});
var TetrominoBlock = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.blockGraphics = self.attachAsset('tetromino' + type, {
anchorX: 0,
anchorY: 0
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
// Game constants
// Tetromino blocks
// Board elements
// Sound effects
var boardWidth = 10;
var boardHeight = 20;
var blockSize = 100;
var boardOffsetX = 524;
var boardOffsetY = 200;
// Game state
var board = [];
var currentPiece = null;
var nextPiece = null;
var nextPieceType = null;
var nextPiecePreview = null;
var ghostPiece = null;
var nextPieces = ['I', 'O', 'T', 'S', 'Z', 'J', 'L'];
var fallTimer = 0;
var fallSpeed = 60; // frames per fall
var level = 1;
var linesCleared = 0;
var isGameOver = false;
var dragon = null;
// Initialize board
function initializeBoard() {
board = [];
for (var row = 0; row < boardHeight; row++) {
board[row] = [];
for (var col = 0; col < boardWidth; col++) {
board[row][col] = null;
}
}
}
// Create next piece preview area
function createNextPiecePreview() {
var previewX = boardOffsetX + boardWidth * blockSize + 50;
var previewY = boardOffsetY + 50;
var previewSize = 400;
// Preview border
var previewBorder = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: 4,
height: previewSize
});
previewBorder.x = previewX - 4;
previewBorder.y = previewY;
game.addChild(previewBorder);
var previewBorderRight = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: 4,
height: previewSize
});
previewBorderRight.x = previewX + previewSize;
previewBorderRight.y = previewY;
game.addChild(previewBorderRight);
var previewBorderTop = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: previewSize + 8,
height: 4
});
previewBorderTop.x = previewX - 4;
previewBorderTop.y = previewY - 4;
game.addChild(previewBorderTop);
var previewBorderBottom = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: previewSize + 8,
height: 4
});
previewBorderBottom.x = previewX - 4;
previewBorderBottom.y = previewY + previewSize;
game.addChild(previewBorderBottom);
// Next piece label
var nextLabel = new Text2('NEXT', {
size: 40,
fill: 0xFFFFFF
});
nextLabel.anchor.set(0.5, 1);
nextLabel.x = previewX + previewSize / 2;
nextLabel.y = previewY - 10;
game.addChild(nextLabel);
}
// Create board borders
function createBoardBorders() {
// Left border
var leftBorder = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: 4,
height: boardHeight * blockSize
});
leftBorder.x = boardOffsetX - 4;
leftBorder.y = boardOffsetY;
game.addChild(leftBorder);
// Right border
var rightBorder = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: 4,
height: boardHeight * blockSize
});
rightBorder.x = boardOffsetX + boardWidth * blockSize;
rightBorder.y = boardOffsetY;
game.addChild(rightBorder);
// Bottom border
var bottomBorder = LK.getAsset('boardBorder', {
anchorX: 0,
anchorY: 0,
width: boardWidth * blockSize + 8,
height: 4
});
bottomBorder.x = boardOffsetX - 4;
bottomBorder.y = boardOffsetY + boardHeight * blockSize;
game.addChild(bottomBorder);
}
// Generate random piece type
function getRandomPieceType() {
var types = ['I', 'O', 'T', 'S', 'Z', 'J', 'L'];
return types[Math.floor(Math.random() * types.length)];
}
// Update next piece preview
function updateNextPiecePreview() {
// Clear existing preview
if (nextPiecePreview) {
nextPiecePreview.destroy();
}
if (nextPieceType) {
var previewX = boardOffsetX + boardWidth * blockSize + 50;
var previewY = boardOffsetY + 50;
var previewSize = 400;
nextPiecePreview = new Tetromino(nextPieceType);
// Get piece dimensions to center it properly
var shape = nextPiecePreview.shapes[nextPieceType][0];
var pieceWidth = 0;
var pieceHeight = shape.length;
for (var row = 0; row < shape.length; row++) {
pieceWidth = Math.max(pieceWidth, shape[row].length);
}
// Calculate center position within preview area
var piecePixelWidth = pieceWidth * 100;
var piecePixelHeight = pieceHeight * 100;
var centerX = previewX + (previewSize - piecePixelWidth) / 2;
var centerY = previewY + (previewSize - piecePixelHeight) / 2;
nextPiecePreview.x = centerX;
nextPiecePreview.y = centerY;
// Scale down the preview piece
nextPiecePreview.scaleX = 1.0;
nextPiecePreview.scaleY = 1.0;
game.addChild(nextPiecePreview);
}
}
// Update ghost piece preview
function updateGhostPiece() {
// Clear existing ghost piece
if (ghostPiece) {
ghostPiece.destroy();
ghostPiece = null;
}
if (!currentPiece) return;
// Create ghost piece container
ghostPiece = new Container();
// Get current piece shape
var shape = currentPiece.shapes[currentPiece.type][currentPiece.currentRotation];
// Find the lowest valid position for the current piece
var testY = currentPiece.y;
var validY = currentPiece.y;
// Move test position down until it's no longer valid
while (true) {
testY += blockSize;
// Check if this position would be valid
var boardX = Math.floor((currentPiece.x - boardOffsetX) / blockSize);
var boardY = Math.floor((testY - boardOffsetY) / blockSize);
var isValid = true;
for (var row = 0; row < shape.length && isValid; row++) {
for (var col = 0; col < shape[row].length && isValid; col++) {
if (shape[row][col] === 1) {
var checkX = boardX + col;
var checkY = boardY + row;
// Check boundaries and collisions
if (checkX < 0 || checkX >= boardWidth || checkY >= boardHeight) {
isValid = false;
} else if (checkY >= 0 && board[checkY] && board[checkY][checkX] !== null) {
isValid = false;
}
}
}
}
if (!isValid) {
break;
}
validY = testY;
}
// Only show ghost piece if it's below the current piece
if (validY > currentPiece.y) {
// Create ghost blocks at the valid position
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col] === 1) {
var ghostBlock = new GhostBlock(currentPiece.type);
ghostBlock.x = currentPiece.x + col * 100;
ghostBlock.y = validY + row * 100;
ghostPiece.addChild(ghostBlock);
}
}
}
game.addChild(ghostPiece);
}
}
// Spawn new piece
function spawnNewPiece() {
if (currentPiece) {
currentPiece.destroy();
}
// Clear ghost piece when spawning new piece
if (ghostPiece) {
ghostPiece.destroy();
ghostPiece = null;
}
// Use next piece or generate first piece
var pieceType;
if (nextPieceType) {
pieceType = nextPieceType;
} else {
pieceType = getRandomPieceType();
}
// Generate new next piece
nextPieceType = getRandomPieceType();
updateNextPiecePreview();
currentPiece = new Tetromino(pieceType);
currentPiece.x = boardOffsetX + Math.floor(boardWidth / 2) * blockSize - blockSize;
currentPiece.y = boardOffsetY;
game.addChild(currentPiece);
// Dragon throws the piece
if (dragon) {
dragon.throwPiece(currentPiece);
}
// Update ghost piece for new piece
updateGhostPiece();
// Check if game over
if (!currentPiece.isValidPosition()) {
isGameOver = true;
LK.showGameOver();
}
}
// Move piece down
function movePieceDown() {
if (!currentPiece) return false;
currentPiece.y += blockSize;
if (!currentPiece.isValidPosition()) {
currentPiece.y -= blockSize;
placePiece();
return false;
}
updateGhostPiece();
return true;
}
// Move piece left
function movePieceLeft() {
if (!currentPiece) return;
currentPiece.x -= blockSize;
if (!currentPiece.isValidPosition()) {
currentPiece.x += blockSize;
} else {
updateGhostPiece();
}
}
// Move piece right
function movePieceRight() {
if (!currentPiece) return;
currentPiece.x += blockSize;
if (!currentPiece.isValidPosition()) {
currentPiece.x -= blockSize;
} else {
updateGhostPiece();
}
}
// Place piece on board
function placePiece() {
if (!currentPiece) return;
var shape = currentPiece.shapes[currentPiece.type][currentPiece.currentRotation];
var boardX = Math.floor((currentPiece.x - boardOffsetX) / blockSize);
var boardY = Math.floor((currentPiece.y - boardOffsetY) / blockSize);
// Place blocks on board
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col] === 1) {
var placeX = boardX + col;
var placeY = boardY + row;
if (placeY >= 0 && placeY < boardHeight && placeX >= 0 && placeX < boardWidth) {
// Create placed block
var placedBlock = new TetrominoBlock(currentPiece.type);
placedBlock.x = boardOffsetX + placeX * blockSize;
placedBlock.y = boardOffsetY + placeY * blockSize;
game.addChild(placedBlock);
board[placeY][placeX] = placedBlock;
}
}
}
}
LK.getSound('pieceLand').play();
// Check for completed lines
checkCompletedLines();
// Spawn new piece
spawnNewPiece();
}
// Check for completed lines
function checkCompletedLines() {
var completedLines = [];
// Find completed lines
for (var row = 0; row < boardHeight; row++) {
var isComplete = true;
for (var col = 0; col < boardWidth; col++) {
if (board[row][col] === null) {
isComplete = false;
break;
}
}
if (isComplete) {
completedLines.push(row);
}
}
// Clear completed lines
if (completedLines.length > 0) {
// Remove blocks from completed lines
for (var i = 0; i < completedLines.length; i++) {
var row = completedLines[i];
for (var col = 0; col < boardWidth; col++) {
if (board[row][col]) {
board[row][col].destroy();
board[row][col] = null;
}
}
}
// Drop lines above
for (var i = completedLines.length - 1; i >= 0; i--) {
var clearedRow = completedLines[i];
// Move all rows above down
for (var row = clearedRow; row > 0; row--) {
for (var col = 0; col < boardWidth; col++) {
board[row][col] = board[row - 1][col];
if (board[row][col]) {
board[row][col].y += blockSize;
}
}
}
// Clear top row
for (var col = 0; col < boardWidth; col++) {
board[0][col] = null;
}
// Adjust subsequent cleared rows
for (var j = i + 1; j < completedLines.length; j++) {
completedLines[j]++;
}
}
// Update score
var points = completedLines.length * 100 * level;
if (completedLines.length === 4) points *= 2; // Tetris bonus
LK.setScore(LK.getScore() + points);
scoreTxt.setText(LK.getScore());
linesCleared += completedLines.length;
level = Math.floor(linesCleared / 10) + 1;
fallSpeed = Math.max(10, 60 - (level - 1) * 5);
levelTxt.setText('Level: ' + level);
linesTxt.setText('Lines: ' + linesCleared);
LK.getSound('lineClear').play();
}
}
// Touch controls
var touchStartX = 0;
var touchStartY = 0;
var isTouching = false;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
isTouching = true;
};
game.up = function (x, y, obj) {
if (!isTouching) return;
isTouching = false;
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
// Swipe down for fast drop
if (deltaY > 50 && Math.abs(deltaX) < 30) {
while (movePieceDown()) {
// Keep dropping until piece lands
}
return;
}
// Tap piece to rotate
if (Math.abs(deltaX) < 30 && Math.abs(deltaY) < 30) {
if (currentPiece) {
currentPiece.rotate();
}
return;
}
// Swipe left/right to move
if (Math.abs(deltaX) > 30) {
if (deltaX > 0) {
movePieceRight();
} else {
movePieceLeft();
}
}
};
// Initialize UI
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 1);
scoreTxt.setText(LK.getScore());
LK.gui.bottom.addChild(scoreTxt);
var levelTxt = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 100;
levelTxt.y = 100;
LK.gui.topLeft.addChild(levelTxt);
// Add flame next to level text
var flameGraphics = LK.getAsset('flame', {
anchorX: 0.5,
anchorY: 0.5
});
flameGraphics.x = levelTxt.x + 200; // Position to the right of level text
flameGraphics.y = levelTxt.y + 20; // Center vertically with text
LK.gui.topLeft.addChild(flameGraphics);
// Add flickering animation to flame
function startFlameAnimation() {
tween(flameGraphics, {
scaleX: 1.2,
scaleY: 0.8,
alpha: 0.8
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(flameGraphics, {
scaleX: 0.9,
scaleY: 1.1,
alpha: 1.0
}, {
duration: 250,
easing: tween.easeInOut,
onFinish: function onFinish() {
startFlameAnimation();
}
});
}
});
}
startFlameAnimation();
var linesTxt = new Text2('Lines: 0', {
size: 40,
fill: 0xFFFFFF
});
linesTxt.anchor.set(0, 0);
linesTxt.x = 100;
linesTxt.y = 150;
LK.gui.topLeft.addChild(linesTxt);
// Initialize dragon
dragon = new Dragon();
dragon.x = boardOffsetX + boardWidth * blockSize / 2;
dragon.y = boardOffsetY - 80; // Position above the game area (moved 120px down from -200 to -80)
game.addChild(dragon);
// Initialize game
initializeBoard();
createBoardBorders();
createNextPiecePreview();
// Generate first next piece
nextPieceType = getRandomPieceType();
updateNextPiecePreview();
spawnNewPiece();
// Game update loop
game.update = function () {
if (isGameOver) return;
fallTimer++;
if (fallTimer >= fallSpeed) {
fallTimer = 0;
movePieceDown();
}
};