/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Tetromino class
var Tetromino = Container.expand(function () {
var self = Container.call(this);
// Properties
self.type = null;
self.shape = null; // array of [x,y]
self.rotation = 0;
self.blocks = [];
self.x = 0; // board col
self.y = 0; // board row
self.isPowerup = false;
self.powerupType = null;
// Initialize tetromino
self.init = function (type, isPowerup) {
self.type = type;
self.isPowerup = !!isPowerup;
self.rotation = 0;
self.shape = [];
// Copy shape
if (type === 'I') {
// Use the first variant for I block
var base = TETROMINO_SHAPES[type][0];
for (var i = 0; i < base.length; i++) {
self.shape.push([base[i][0], base[i][1]]);
}
} else {
var base = TETROMINO_SHAPES[type][0];
for (var i = 0; i < base.length; i++) {
self.shape.push([base[i][0], base[i][1]]);
}
}
self.blocks = [];
self.removeChildren();
// Special handling for I block: use a single image asset for the whole tetromino
if (self.type === 'I') {
var block = self.attachAsset('I', {
anchorX: 0.5,
anchorY: 0.5,
width: CELL_SIZE * 4,
height: CELL_SIZE
});
self.blocks.push(block);
// Overlay grid lines for I block
var gridOverlay = new Container();
for (var i = 0; i <= 4; i++) {
var vline = LK.getAsset('O', {
anchorX: 0.5,
anchorY: 0,
width: 4,
height: CELL_SIZE,
color: 0x222222 // match board grid color
});
vline.x = -CELL_SIZE * 2 + i * CELL_SIZE;
vline.y = -CELL_SIZE / 2;
vline.alpha = 0.25;
gridOverlay.addChild(vline);
}
var hline = LK.getAsset('O', {
anchorX: 0,
anchorY: 0.5,
width: CELL_SIZE * 4,
height: 4,
color: 0x222222 // match board grid color
});
hline.x = -CELL_SIZE * 2;
hline.y = 0;
hline.alpha = 0.25;
gridOverlay.addChild(hline);
var hline2 = LK.getAsset('O', {
anchorX: 0,
anchorY: 0.5,
width: CELL_SIZE * 4,
height: 4,
color: 0x222222 // match board grid color
});
hline2.x = -CELL_SIZE * 2;
hline2.y = CELL_SIZE / 2;
hline2.alpha = 0.25;
gridOverlay.addChild(hline2);
self.addChild(gridOverlay);
} else {
for (var i = 0; i < self.shape.length; i++) {
var block;
if (self.isPowerup && i === 0) {
block = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
width: CELL_SIZE,
height: CELL_SIZE
});
self.powerupType = 'clearLine'; // Only one powerup for MVP
} else {
block = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5,
width: CELL_SIZE,
height: CELL_SIZE
});
}
self.blocks.push(block);
// Overlay grid lines for each block
var gridOverlay = new Container();
var vlineL = LK.getAsset('O', {
anchorX: 0.5,
anchorY: 0,
width: 4,
height: CELL_SIZE,
color: 0x222222 // match board grid color
});
vlineL.x = -CELL_SIZE / 2;
vlineL.y = -CELL_SIZE / 2;
vlineL.alpha = 0.25;
gridOverlay.addChild(vlineL);
var vlineR = LK.getAsset('O', {
anchorX: 0.5,
anchorY: 0,
width: 4,
height: CELL_SIZE,
color: 0x222222 // match board grid color
});
vlineR.x = CELL_SIZE / 2;
vlineR.y = -CELL_SIZE / 2;
vlineR.alpha = 0.25;
gridOverlay.addChild(vlineR);
var hlineT = LK.getAsset('O', {
anchorX: 0,
anchorY: 0.5,
width: CELL_SIZE,
height: 4,
color: 0x222222 // match board grid color
});
hlineT.x = -CELL_SIZE / 2;
hlineT.y = -CELL_SIZE / 2;
hlineT.alpha = 0.25;
gridOverlay.addChild(hlineT);
var hlineB = LK.getAsset('O', {
anchorX: 0,
anchorY: 0.5,
width: CELL_SIZE,
height: 4,
color: 0x222222 // match board grid color
});
hlineB.x = -CELL_SIZE / 2;
hlineB.y = CELL_SIZE / 2;
hlineB.alpha = 0.25;
gridOverlay.addChild(hlineB);
block.addChild(gridOverlay);
}
}
self.x = Math.floor(BOARD_COLS / 2) - 2;
self.y = 0;
self.updateBlockPositions();
};
// Update block positions
self.updateBlockPositions = function () {
if (self.type === 'I') {
// Center the I block image over the 4 cells
// Find min/max x/y for the I shape
var minX = 99,
maxX = -99,
minY = 99,
maxY = -99;
for (var i = 0; i < self.shape.length; i++) {
if (self.shape[i][0] < minX) {
minX = self.shape[i][0];
}
if (self.shape[i][0] > maxX) {
maxX = self.shape[i][0];
}
if (self.shape[i][1] < minY) {
minY = self.shape[i][1];
}
if (self.shape[i][1] > maxY) {
maxY = self.shape[i][1];
}
}
// The I block is always 4 wide, 1 tall
// Place the image so its center matches the center of the 4 cells
var centerX = 0,
centerY = 0;
for (var i = 0; i < self.shape.length; i++) {
centerX += self.x + self.shape[i][0];
centerY += self.y + self.shape[i][1];
}
centerX = centerX / self.shape.length;
centerY = centerY / self.shape.length;
self.blocks[0].x = centerX * CELL_SIZE + CELL_SIZE / 2;
self.blocks[0].y = centerY * CELL_SIZE + CELL_SIZE / 2;
} else {
for (var i = 0; i < self.shape.length; i++) {
var pos = self.shape[i];
self.blocks[i].x = (self.x + pos[0]) * CELL_SIZE + CELL_SIZE / 2;
self.blocks[i].y = (self.y + pos[1]) * CELL_SIZE + CELL_SIZE / 2;
}
}
};
// Try move
self.tryMove = function (dx, dy, board) {
if (self.canMove(dx, dy, self.shape, board)) {
self.x += dx;
self.y += dy;
self.updateBlockPositions();
return true;
}
return false;
};
// Try rotate
self.tryRotate = function (board) {
// For I block, use predefined shape variants for rotation
if (self.type === 'I') {
var shapeVariants = TETROMINO_SHAPES['I'];
var nextRotation = (self.rotation + 1) % shapeVariants.length;
var rotated = [];
for (var i = 0; i < shapeVariants[nextRotation].length; i++) {
rotated.push([shapeVariants[nextRotation][i][0], shapeVariants[nextRotation][i][1]]);
}
if (self.canMove(0, 0, rotated, board)) {
self.shape = rotated;
self.rotation = nextRotation;
self.updateBlockPositions();
return true;
}
return false;
} else {
var rotated = rotateShape(self.shape);
if (self.canMove(0, 0, rotated, board)) {
self.shape = rotated;
self.updateBlockPositions();
return true;
}
return false;
}
};
// Can move/rotate
self.canMove = function (dx, dy, shape, board) {
for (var i = 0; i < shape.length; i++) {
var nx = self.x + shape[i][0] + dx;
var ny = self.y + shape[i][1] + dy;
if (nx < 0 || nx >= BOARD_COLS || ny < 0 || ny >= BOARD_ROWS) {
return false;
}
if (board[ny][nx]) {
return false;
}
}
return true;
};
// Lock tetromino into board
self.lockToBoard = function (board, blockRefs) {
if (self.type === 'I') {
for (var i = 0; i < self.shape.length; i++) {
var nx = self.x + self.shape[i][0];
var ny = self.y + self.shape[i][1];
board[ny][nx] = self.type;
blockRefs[ny][nx] = self.blocks[0];
}
} else {
for (var i = 0; i < self.shape.length; i++) {
var nx = self.x + self.shape[i][0];
var ny = self.y + self.shape[i][1];
board[ny][nx] = self.isPowerup && i === 0 ? 'powerup' : self.type;
blockRefs[ny][nx] = self.blocks[i];
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Always backgroundColor is black
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Board state: 2D array [row][col], 0 = empty, else type string
// Tetromino shapes (classic + new)
// Colors for each tetromino type
// New shapes
// Power-up block
// Power-up effect
// Tetromino definitions (relative coordinates for each block in the tetromino)
var TETROMINO_SHAPES = {
I: [[[1, 0], [1, 1], [1, 2], [1, 3]],
// vertical (tall)
[[0, 1], [1, 1], [2, 1], [3, 1]] // horizontal
],
O: [[[1, 0], [2, 0], [1, 1], [2, 1]]],
T: [[[1, 0], [0, 1], [1, 1], [2, 1]]],
S: [[[1, 0], [2, 0], [0, 1], [1, 1]]],
Z: [[[0, 0], [1, 0], [1, 1], [2, 1]]],
J: [[[0, 0], [0, 1], [1, 1], [2, 1]]],
L: [[[2, 0], [0, 1], [1, 1], [2, 1]]],
U: [[[0, 0], [2, 0], [0, 1], [1, 1], [2, 1]]],
P: [[[0, 0], [1, 0], [0, 1], [1, 1], [0, 2]]],
Dot: [[[1, 1]]]
};
var TETROMINO_TYPES = ['I', 'O', 'T', 'S', 'Z', 'J', 'L', 'U', 'P'];
var POWERUP_CHANCE = 0.08; // 8% chance for a powerup block
// Board settings
var BOARD_COLS = 8; // Reduced width for fewer columns, block size unchanged
var BOARD_ROWS = 20;
var CELL_SIZE = 90; // px, fits well on 2048x2732
var BOARD_OFFSET_X = Math.floor((2048 - BOARD_COLS * CELL_SIZE) / 2) - 80; // Shift left to make space for preview
var BOARD_OFFSET_Y = 300;
// Helper: rotate a shape (array of [x,y]) 90deg clockwise
function rotateShape(shape) {
var maxX = 0,
maxY = 0;
for (var i = 0; i < shape.length; i++) {
if (shape[i][0] > maxX) {
maxX = shape[i][0];
}
if (shape[i][1] > maxY) {
maxY = shape[i][1];
}
}
var rotated = [];
for (var i = 0; i < shape.length; i++) {
var x = shape[i][0],
y = shape[i][1];
rotated.push([maxY - y, x]);
}
return rotated;
}
var board = [];
var blockRefs = []; // 2D array of block display objects
for (var r = 0; r < BOARD_ROWS; r++) {
board[r] = [];
blockRefs[r] = [];
for (var c = 0; c < BOARD_COLS; c++) {
board[r][c] = 0;
blockRefs[r][c] = null;
}
}
// Score and level
var score = 0;
var level = 1;
var linesCleared = 0;
var fallInterval = 1000; // ms, decreases with level
// GUI
var scoreTxt = new Text2('0', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var levelTxt = new Text2('Lv.1', {
size: 60,
fill: "#fff"
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 110;
// Next tetromino preview
var nextTetrominoType = null;
var nextTetrominoPreview = new Container();
game.addChild(nextTetrominoPreview);
// Current falling tetromino
var currentTetromino = null;
// Game state
var isGameOver = false;
var isDropping = false;
var dropTimer = null;
var moveTimer = null;
var moveDir = 0; // -1 left, 1 right, 0 none
// Helper: spawn new tetromino
function spawnTetromino() {
var type = nextTetrominoType;
if (!type) {
type = TETROMINO_TYPES[Math.floor(Math.random() * TETROMINO_TYPES.length)];
}
var isPowerup = Math.random() < POWERUP_CHANCE;
var tetro = new Tetromino();
tetro.init(type, isPowerup);
game.addChild(tetro);
currentTetromino = tetro;
// Next
nextTetrominoType = TETROMINO_TYPES[Math.floor(Math.random() * TETROMINO_TYPES.length)];
updateNextPreview();
// Flash effect on next preview
if (nextTetrominoPreview.children && nextTetrominoPreview.children.length > 0) {
for (var i = 0; i < nextTetrominoPreview.children.length; i++) {
LK.effects.flashObject(nextTetrominoPreview.children[i], 0xffffff, 180);
}
}
// If cannot place, game over
if (!tetro.canMove(0, 0, tetro.shape, board)) {
isGameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
// Helper: update next preview
function updateNextPreview() {
nextTetrominoPreview.removeChildren();
var type = nextTetrominoType;
if (!type) {
return;
}
var shape = TETROMINO_SHAPES[type][0];
// Find min/max for centering
var minX = 99,
maxX = -99,
minY = 99,
maxY = -99;
for (var i = 0; i < shape.length; i++) {
if (shape[i][0] < minX) {
minX = shape[i][0];
}
if (shape[i][0] > maxX) {
maxX = shape[i][0];
}
if (shape[i][1] < minY) {
minY = shape[i][1];
}
if (shape[i][1] > maxY) {
maxY = shape[i][1];
}
}
var previewWidth = (maxX - minX + 1) * CELL_SIZE;
var previewHeight = (maxY - minY + 1) * CELL_SIZE;
if (type === 'I') {
// Show as a single image asset
var block = LK.getAsset('I', {
anchorX: 0.5,
anchorY: 0.5,
width: CELL_SIZE * 4,
height: CELL_SIZE
});
// Center the image in the preview area
block.x = (maxX - minX + 1) * CELL_SIZE / 2;
block.y = (maxY - minY + 1) * CELL_SIZE / 2;
nextTetrominoPreview.addChild(block);
} else {
for (var i = 0; i < shape.length; i++) {
var block = LK.getAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
width: CELL_SIZE,
height: CELL_SIZE
});
block.x = (shape[i][0] - minX) * CELL_SIZE + CELL_SIZE / 2;
block.y = (shape[i][1] - minY) * CELL_SIZE + CELL_SIZE / 2;
nextTetrominoPreview.addChild(block);
}
}
// Place preview to the right of the board, fully visible and inside the screen
nextTetrominoPreview.x = BOARD_OFFSET_X + BOARD_COLS * CELL_SIZE + 120;
nextTetrominoPreview.y = BOARD_OFFSET_Y + 200;
}
// Helper: clear full lines
function clearLines() {
var lines = [];
for (var r = 0; r < BOARD_ROWS; r++) {
var full = true;
for (var c = 0; c < BOARD_COLS; c++) {
if (!board[r][c]) {
full = false;
break;
}
}
if (full) {
lines.push(r);
}
}
if (lines.length === 0) {
return 0;
}
// Animate and remove lines
for (var i = 0; i < lines.length; i++) {
var row = lines[i];
for (var c = 0; c < BOARD_COLS; c++) {
if (blockRefs[row][c]) {
tween(blockRefs[row][c], {
alpha: 0
}, {
duration: 200,
onFinish: function (obj) {
if (obj.parent) {
obj.parent.removeChild(obj);
}
}.bind(null, blockRefs[row][c])
});
}
}
}
// Remove from board
for (var i = 0; i < lines.length; i++) {
var row = lines[i];
for (var c = 0; c < BOARD_COLS; c++) {
board[row][c] = 0;
blockRefs[row][c] = null;
}
}
// Drop above lines
for (var i = lines.length - 1; i >= 0; i--) {
var row = lines[i];
for (var r = row - 1; r >= 0; r--) {
for (var c = 0; c < BOARD_COLS; c++) {
board[r + 1][c] = board[r][c];
blockRefs[r + 1][c] = blockRefs[r][c];
if (blockRefs[r + 1][c]) {
tween(blockRefs[r + 1][c], {
y: blockRefs[r + 1][c].y + CELL_SIZE
}, {
duration: 100
});
}
}
}
// Clear top row
for (var c = 0; c < BOARD_COLS; c++) {
board[0][c] = 0;
blockRefs[0][c] = null;
}
}
return lines.length;
}
// Helper: activate powerup
function activatePowerup(row) {
// For MVP: clear the row where powerup landed
for (var c = 0; c < BOARD_COLS; c++) {
if (blockRefs[row][c]) {
tween(blockRefs[row][c], {
alpha: 0
}, {
duration: 200,
onFinish: function (obj) {
if (obj.parent) {
obj.parent.removeChild(obj);
}
}.bind(null, blockRefs[row][c])
});
board[row][c] = 0;
blockRefs[row][c] = null;
}
}
// Drop above lines
for (var r = row - 1; r >= 0; r--) {
for (var c = 0; c < BOARD_COLS; c++) {
board[r + 1][c] = board[r][c];
blockRefs[r + 1][c] = blockRefs[r][c];
if (blockRefs[r + 1][c]) {
tween(blockRefs[r + 1][c], {
y: blockRefs[r + 1][c].y + CELL_SIZE
}, {
duration: 100
});
}
}
}
// Clear top row
for (var c = 0; c < BOARD_COLS; c++) {
board[0][c] = 0;
blockRefs[0][c] = null;
}
}
// Helper: update score/level
function updateScore(lines) {
var points = [0, 100, 300, 500, 800];
score += points[lines] || 0;
linesCleared += lines;
scoreTxt.setText(score);
var newLevel = 1 + Math.floor(linesCleared / 10);
if (newLevel !== level) {
level = newLevel;
levelTxt.setText('Lv.' + level);
fallInterval = Math.max(150, 1000 - (level - 1) * 100);
}
}
// Helper: draw board grid (for visual reference)
var gridLines = new Container();
game.addChild(gridLines);
// Draw faint cell backgrounds for subtle grid
for (var r = 0; r < BOARD_ROWS; r++) {
for (var c = 0; c < BOARD_COLS; c++) {
var cell = LK.getAsset('O', {
anchorX: 0.5,
anchorY: 0.5,
width: CELL_SIZE - 4,
height: CELL_SIZE - 4,
color: 0x222222
});
cell.x = c * CELL_SIZE + CELL_SIZE / 2;
cell.y = r * CELL_SIZE + CELL_SIZE / 2;
cell.alpha = 0.15;
gridLines.addChild(cell);
}
}
// Draw vertical grid lines
for (var c = 0; c <= BOARD_COLS; c++) {
var vline = LK.getAsset('O', {
anchorX: 0.5,
anchorY: 0,
width: 4,
height: CELL_SIZE * BOARD_ROWS,
color: 0x222222 // darker gray for better contrast
});
vline.x = c * CELL_SIZE;
vline.y = 0;
vline.alpha = 0.35;
gridLines.addChild(vline);
}
// Draw horizontal grid lines
for (var r = 0; r <= BOARD_ROWS; r++) {
var hline = LK.getAsset('O', {
anchorX: 0,
anchorY: 0.5,
width: CELL_SIZE * BOARD_COLS,
height: 4,
color: 0x222222 // darker gray for better contrast
});
hline.x = 0;
hline.y = r * CELL_SIZE;
hline.alpha = 0.35;
gridLines.addChild(hline);
}
gridLines.x = BOARD_OFFSET_X;
gridLines.y = BOARD_OFFSET_Y;
// Move all blocks/containers to board offset
function updateBoardDisplayOffsets() {
gridLines.x = BOARD_OFFSET_X;
gridLines.y = BOARD_OFFSET_Y;
for (var r = 0; r < BOARD_ROWS; r++) {
for (var c = 0; c < BOARD_COLS; c++) {
if (blockRefs[r][c]) {
blockRefs[r][c].x = c * CELL_SIZE + CELL_SIZE / 2 + BOARD_OFFSET_X;
blockRefs[r][c].y = r * CELL_SIZE + CELL_SIZE / 2 + BOARD_OFFSET_Y;
}
}
}
if (currentTetromino) {
for (var i = 0; i < currentTetromino.blocks.length; i++) {
currentTetromino.blocks[i].x += BOARD_OFFSET_X;
currentTetromino.blocks[i].y += BOARD_OFFSET_Y;
}
}
}
// Remove board offset from tetromino before logic
function removeTetrominoOffset() {
if (currentTetromino) {
for (var i = 0; i < currentTetromino.blocks.length; i++) {
currentTetromino.blocks[i].x -= BOARD_OFFSET_X;
currentTetromino.blocks[i].y -= BOARD_OFFSET_Y;
}
}
}
// Touch controls
var dragStartX = null;
var dragStartY = null;
var dragTetrominoX = null;
var dragTetrominoY = null;
var lastTouchMove = 0;
var touchDown = false;
var hardDrop = false;
// Convert screen x,y to board col,row
function screenToBoard(x, y) {
var bx = Math.floor((x - BOARD_OFFSET_X) / CELL_SIZE);
var by = Math.floor((y - BOARD_OFFSET_Y) / CELL_SIZE);
return {
col: bx,
row: by
};
}
// Touch/mouse events
game.down = function (x, y, obj) {
if (isGameOver || !currentTetromino) {
return;
}
dragStartX = x;
dragStartY = y;
dragTetrominoX = currentTetromino.x;
dragTetrominoY = currentTetromino.y;
touchDown = true;
hardDrop = false;
lastTouchMove = Date.now();
};
game.move = function (x, y, obj) {
if (isGameOver || !currentTetromino || !touchDown) {
return;
}
var dx = x - dragStartX;
var dy = y - dragStartY;
var moved = false;
// Horizontal drag: move left/right
if (Math.abs(dx) > CELL_SIZE / 2) {
var dir = dx > 0 ? 1 : -1;
if (currentTetromino.tryMove(dir, 0, board)) {
dragStartX = x;
dragTetrominoX = currentTetromino.x;
moved = true;
}
}
// Vertical drag: hard drop
if (dy > CELL_SIZE * 2 && !hardDrop) {
// Hard drop
while (currentTetromino.tryMove(0, 1, board)) {}
hardDrop = true;
moved = true;
}
// Tap: rotate (handled in up)
if (moved) {
currentTetromino.updateBlockPositions();
updateBoardDisplayOffsets();
}
};
game.up = function (x, y, obj) {
if (isGameOver || !currentTetromino) {
return;
}
touchDown = false;
var dt = Date.now() - lastTouchMove;
var dx = x - dragStartX;
var dy = y - dragStartY;
// Tap: rotate
if (Math.abs(dx) < 30 && Math.abs(dy) < 30 && dt < 400) {
removeTetrominoOffset();
currentTetromino.tryRotate(board);
currentTetromino.updateBlockPositions();
updateBoardDisplayOffsets();
}
};
// Auto fall
function scheduleDrop() {
if (dropTimer) {
LK.clearTimeout(dropTimer);
}
if (isGameOver) {
return;
}
dropTimer = LK.setTimeout(function () {
if (isGameOver) {
return;
}
removeTetrominoOffset();
var moved = currentTetromino.tryMove(0, 1, board);
currentTetromino.updateBlockPositions();
updateBoardDisplayOffsets();
if (!moved) {
// Lock to board
currentTetromino.lockToBoard(board, blockRefs);
// Flash effect on lock
for (var i = 0; i < currentTetromino.blocks.length; i++) {
LK.effects.flashObject(currentTetromino.blocks[i], 0xffffff, 180);
}
// Powerup check
var landedPowerup = false;
for (var i = 0; i < currentTetromino.shape.length; i++) {
var nx = currentTetromino.x + currentTetromino.shape[i][0];
var ny = currentTetromino.y + currentTetromino.shape[i][1];
if (board[ny][nx] === 'powerup') {
activatePowerup(ny);
landedPowerup = true;
}
}
// Clear lines
var lines = clearLines();
updateScore(lines);
// Do not remove tetromino blocks here; they are now part of the board and will be removed when lines are cleared
currentTetromino = null;
// Spawn next
spawnTetromino();
updateBoardDisplayOffsets();
}
scheduleDrop();
}, fallInterval);
}
// Game update
game.update = function () {
// No per-frame logic needed for MVP
};
// Start game
function startGame() {
// Reset board
for (var r = 0; r < BOARD_ROWS; r++) {
for (var c = 0; c < BOARD_COLS; c++) {
board[r][c] = 0;
if (blockRefs[r][c]) {
if (blockRefs[r][c].parent) {
blockRefs[r][c].parent.removeChild(blockRefs[r][c]);
}
blockRefs[r][c] = null;
}
}
}
score = 0;
level = 1;
linesCleared = 0;
fallInterval = 1000;
scoreTxt.setText(score);
levelTxt.setText('Lv.1');
isGameOver = false;
nextTetrominoType = TETROMINO_TYPES[Math.floor(Math.random() * TETROMINO_TYPES.length)];
updateNextPreview();
if (currentTetromino) {
for (var i = 0; i < currentTetromino.blocks.length; i++) {
if (currentTetromino.blocks[i].parent) {
currentTetromino.blocks[i].parent.removeChild(currentTetromino.blocks[i]);
}
}
currentTetromino = null;
}
spawnTetromino();
updateBoardDisplayOffsets();
scheduleDrop();
}
// On game over, restart on new game
LK.on('gameStart', function () {
startGame();
});
// Initial start
LK.playMusic('tetris_bgm');
startGame(); ===================================================================
--- original.js
+++ change.js
@@ -293,11 +293,11 @@
// Power-up block
// Power-up effect
// Tetromino definitions (relative coordinates for each block in the tetromino)
var TETROMINO_SHAPES = {
- I: [[[0, 1], [1, 1], [2, 1], [3, 1]],
- // horizontal
- [[2, 0], [2, 1], [2, 2], [2, 3]] // vertical
+ I: [[[1, 0], [1, 1], [1, 2], [1, 3]],
+ // vertical (tall)
+ [[0, 1], [1, 1], [2, 1], [3, 1]] // horizontal
],
O: [[[1, 0], [2, 0], [1, 1], [2, 1]]],
T: [[[1, 0], [0, 1], [1, 1], [2, 1]]],
S: [[[1, 0], [2, 0], [0, 1], [1, 1]]],