Skip to content

Instantly share code, notes, and snippets.

@bcoe
Created Jul 19, 2010
Embed
What would you like to do?
// All the Tetris blocks are instances of this Block class.
Block = Class.extend({
init: function(game, grid, color) {
this.color = color;
this.grid = grid;
this.game = game;
this.x = 64;
this.y = -128;
this.rotation = 0;
this.lock = false;
},
// Update is called to move the block down the screen.
update: function() {
if (this.lock) {
return;
}
var ex = this.x;
var ey = this.y + 32;
var erotate = this.rotation;
if (!this.collide(ex, ey, erotate, true)) {
this.y += 32;
}
},
// Move the block left.
left: function() {
if (this.lock) {
return;
}
var ex = this.x - 32;
var ey = this.y;
var erotate = this.rotation;
if (!this.collide(ex, ey, erotate, false)) {
this.x -= 32;
}
},
// Move the block right.
right: function() {
if (this.lock) {
return;
}
var ex = this.x + 32;
var ey = this.y;
var erotate = this.rotation;
if (!this.collide(ex, ey, erotate, false)) {
this.x += 32;
}
},
// 'rotate' the block.
rotate: function() {
if (this.lock) {
return;
}
var ex = this.x;
var ey = this.y;
var erotate = (this.rotation + 1) % 4;
if (!this.collide(ex, ey, erotate, true)) {
this.rotation = (this.rotation + 1) % 4;
}
},
// Test for collision.
collide: function(ex, ey, erotate, can_lock) {
var self = this;
var y = ey;
var return_me = false;
var finish = false;
$.each(self.grid[erotate], function(k, v) {
var x = ex;
$.each(v, function(k2, v2) {
if (v2) {
var cx = x / 32;
var cy = y / 32;
if (cx >= 0 && cy >= 0) {
if (cx < self.game.max_x && cy < self.game.max_y) {
if (self.game.grid[cy][cx]) {
if (cx > 0 && cx < 11) {
finish =true;
}
return_me = true;
}
}
}
}
x += 32;
});
y += 32;
});
if (finish && can_lock) {
this.lock = true;
this.copy();
}
return return_me;
},
// Copy the block object onto the game grid. Create square objects.
copy: function() {
var self = this;
var y = self.y;
$.each(self.grid[self.rotation], function(k, v) {
var x = self.x;
$.each(v, function(k2, v2) {
if (v2) {
var cx = x / 32;
var cy = y / 32;
if (cx >= 0 && cy >= 0) {
if (cx < self.game.max_x && cy < self.game.max_y) {
self.game.grid[cy][cx] = 1;
square = new Square(self.game, cx, cy, self.color);
self.game.squares.push(square);
}
}
}
x += 32;
});
y += 32;
});
this.game.drop();
},
// Render this block on the HTML 5 canvas.
render: function() {
var self = this;
var y = self.y;
$.each(self.grid[self.rotation], function(k, v) {
var x = self.x;
$.each(v, function(k2, v2) {
if (v2) {
self.game.context.fillStyle = self.color;
self.game.context.fillRect (x, y, 32, 32);
}
x += 32;
});
y += 32;
});
}
});
// When a tetris block has reached its final resting place on the play
// area, it is copied onto square objects.
Square = Class.extend({
init: function(game, x, y, color) {
this.game = game;
this.x = x;
this.y = y;
this.color = color;
this.display = true;
},
get_x: function() {
return this.x;
},
get_y: function() {
return this.y;
},
set_y: function(y) {
this.y = y;
},
no_show: function() {
this.display = false;
},
down: function() {
},
render: function() {
if (this.display) {
this.game.context.fillStyle = this.color;
this.game.context.fillRect (this.x * 32, this.y * 32, 32, 32);
}
}
})
// The game itself.
Game = Class.extend({
// The tetris game area.
init_grid: function() {
// 12 x 18
this.max_x = 12;
this.max_y = 18;
this.grid = [
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1, 1]
]
},
// All the tetris blocks, I realize I should have used a
// rotation matrix, but was on a plane and couldn't look
// up the math.
generate_blocks: function() {
var self = this;
var square_block = new Block(self,
[
[
[1, 1],
[1, 1]
],
[
[1, 1],
[1, 1]
],
[
[1, 1],
[1, 1]
],
[
[1, 1],
[1, 1]
]
],
"rgba(255, 125, 0, 0.8)"
);
var straight_block = new Block(self,
[
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 1]
],
[
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 1]
]
],
"rgba(255, 255, 0, 0.8)"
);
var l1_block = new Block(self,
[
[
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 1],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 1, 0]
],
[
[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 1, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
]
],
"rgba(50, 126, 32, 0.8)"
);
var l2_block = new Block(self,
[
[
[0, 0, 0, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 0, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
]
],
"rgba(0, 255, 0, 0.8)"
);
var crazy_block = new Block(self,
[
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 0, 0]
],
],
"rgba(255, 0, 0, 0.8)"
);
var crazy_block2 = new Block(self,
[
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 1, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 1, 0]
],
],
"rgba(0, 255, 255, 0.8)"
);
var crazy_block3 = new Block(self,
[
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 0, 1, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 1, 0],
[0, 1, 1, 0, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 0, 1, 0]
],
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 1, 0],
[0, 1, 1, 0, 0]
],
],
"rgba(255, 125, 16, 0.8)"
);
this.blocks = [
l1_block,
l2_block,
square_block,
straight_block,
crazy_block,
crazy_block2,
crazy_block3
];
},
init: function() {
// Get the context of the 2D canvas for rendering.
var screen = document.getElementById('screen');
this.context = screen.getContext('2d');
var self = this;
this.init_grid();
this.speed = 6;
this.squares = [];
this.score = 0;
this.generate_blocks();
this.current_block = this.blocks[Number(Math.random() * (this.blocks.length - 0.5)).toFixed(0)];
this.line_count = 0;
this.increment = 0;
setInterval(function() {
// 10 x 17 rows.
self.context.fillStyle = "rgba(0, 0, 0, 1.0)";
self.context.fillRect (0, 0, 384, 576);
self.context.fillStyle = "rgba(100, 100, 100, 0.75)";
self.context.fillRect (0, 0, 32, 576);
self.context.fillRect (384 - 32, 0, 32, 576);
self.context.fillRect (32, 576 - 32, 384 - 64, 32);
// Allow the speed to change.
if (self.increment % self.speed == 0) {
self.current_block.update();
}
$.each(self.squares, function(k, v) {
v.render();
});
self.current_block.render();
self.increment++;
}, 50);
$(document).keydown( function(e) {
if (e.keyCode == 37) {
self.current_block.left();
}
if (e.keyCode == 39) {
self.current_block.right();
}
if (e.keyCode == 38) {
self.current_block.rotate();
}
if (e.keyCode == 40) {
self.current_block.update();
}
});
},
// Check to see whether any lines have been created.
check_lines: function() {
var self = this;
var lines = [];
var y = 0;
$.each(self.grid, function(k, v) {
var sum = 0;
if (y != 17) {
$.each(v, function(k2, v2) {
if (v2) {
sum += 1;
}
});
}
if (sum == 12) {
lines.push(y);
}
y++;
});
var add_score = 1;
$.each(lines, function(k, v) {
self.remove_line(v);
self.line_count++;
$('.lines').html("Lines: " + self.line_count);
if (self.line_count % 10 == 0) {
self.speed--;
if (self.speed < 1) {
self.spedd = 1;
}
}
add_score *= 10;
});
if (lines.length) {
self.score = self.score + add_score;
$('.score').html("Score: " + self.score);
this.check_lines();
}
},
// Remove a line from the screen updating all the square objects.
remove_line: function(line_num) {
var self = this;
var temp = [1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1];
this.grid[line_num] = temp;
$.each(self.squares, function(k, v) {
if (v.get_y() == line_num) {
v.no_show();
} else
if (v.get_y() < line_num) {
v.set_y(v.get_y() + 1)
}
});
var temp_grid = [
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 0, 0, 0, 0, 0 ,0 ,0, 0 ,0 , 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1, 1]
];
var y = 0;
$.each(self.grid, function(k, v) {
var x = 0;
$.each(v, function(k2, v2) {
if (y < line_num) {
if (self.grid[y][x]) {
temp_grid[y+1][x] = 1;
} else if (self.grid[y][x]) {
temp_grid[y][x] = self.grid[y][x];
}
} else {
if (self.grid[y][x]) {
temp_grid[y][x] = self.grid[y][x];
}
}
x++;
});
y++;
});
self.grid = temp_grid;
},
// Have you lost the game?
check_lose: function() {
var self = this;
var sum = 0;
$.each(self.grid[0], function(k, v) {
if (v) {
sum ++;
}
});
if (sum > 2) {
self.lose = true;
$('.lose').html("YOU LOSE
AND
THEREFORE
SUCK!")
}
},
// Drop a new block.
drop: function() {
if (!this.lose) {
this.check_lose();
this.generate_blocks();
this.current_block = this.blocks[Number(Math.random() * (this.blocks.length - 0.5)).toFixed(0)];
this.check_lines();
}
}
})
// Load the tetris game.
// Main application entry point.
$(document).ready(function() {
var game = new Game;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment