<div id='js-event-counter' class='event-counter'>0</div>
<div id='js-score' class='score'>0</div>
<div id='js-level' class='level'>0</div>
<div id='js-tetris' class='grid' data-component='grid'></div>
<div id='js-next-piece' class='preview-cells'></div>
@import "compass/css3";
*,
*:after,
*:before
{
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
background-repeat: no-repeat;
position: relative;
}
$cell-size:20px;
$grid-width:($cell-size * 10) + 2px;
$grid-height:($cell-size * 20) + 2px;
$preview-size:($cell-size * 5) + 2px;
/* needs to correspond to piece.js */
$colours:
('white',#f0f0f0),
('blue',#3498db),
('yellow',#f1c40f),
('green',#2ecc71),
('red',#e74c3c),
('grey',#95a5a6),
('black',#34495e),
('purple',#9b59b6),
('white',#ecf0f1),
('orange',#e67e22),
('turquoise',#1abc9c);
@each $colour, $hex in $colours
{
.#{$colour}
{
background-color:$hex;
border:1px solid darken($hex,20);
box-shadow:inset 0 0 1px 1px lighten($hex,20);
}
}
body { background-color:#222; }
.event-counter
{
width:$grid-width;
height:20px;
margin:20px auto;
font-size:10px;
text-align:center;
color:#f0f0f0;
opacity:0;
}
.score,
.level
{
position:fixed;
left:463px;
z-index:1;
width:$grid-width;
height:40px;
margin:10px auto;
font-size:20px;
text-align:center;
font-family: Consolas, monaco, monospace;
color:#f0f0f0;
}
.score
{
top:150px;
font-weight:bold;
&:before
{
content:'score: ';
}
}
.level
{
top:175px;
&:before
{
content:'level: ';
}
}
.grid
{
width:$grid-width;
height:$grid-height;
position:fixed;
top:50px;
left:300px;
border:1px solid darken(#f0f0f0,20);
box-shadow:0 0 200px 0 #000;
}
.preview-cells
{
width:$preview-size;
height:$preview-size;
position:fixed;
top:50px;
left:520px;
border:1px solid darken(#f0f0f0,20);
}
.cell
{
width:$cell-size;
height:$cell-size;
display:inline-block;
float:left;
}
View Compiled
Config = {
size:{
'width':10,
'height':20
},
levels:{
0:{
'interval':750,
'threshold':25
},
1:{
'interval':725,
'threshold':50
},
2:{
'interval':700,
'threshold':75
},
3:{
'interval':675,
'threshold':100
},
4:{
'interval':650,
'threshold':125
},
5:{
'interval':625,
'threshold':150
},
6:{
'interval':600,
'threshold':175
},
7:{
'interval':580,
'threshold':200
},
8:{
'interval':560,
'threshold':225
},
9:{
'interval':540,
'threshold':250
},
10:{
'interval':520,
'threshold':275
},
11:{
'interval':500,
'threshold':300
},
12:{
'interval':480,
'threshold':325
},
13:{
'interval':460,
'threshold':350
},
14:{
'interval':440,
'threshold':375
},
15:{
'interval':420,
'threshold':400
},
16:{
'interval':400,
'threshold':425
},
17:{
'interval':380,
'threshold':450
},
18:{
'interval':360,
'threshold':475
},
19:{
'interval':340,
'threshold':500
},
20:{
'interval':320,
'threshold':525
},
21:{
'interval':300,
'threshold':550
},
22:{
'interval':285,
'threshold':575
},
23:{
'interval':270,
'threshold':600
},
24:{
'interval':255,
'threshold':625
},
25:{
'interval':240,
'threshold':650
},
26:{
'interval':225,
'threshold':675
},
27:{
'interval':210,
'threshold':700
},
28:{
'interval':195,
'threshold':725
},
29:{
'interval':180,
'threshold':750
},
30:{
'interval':165,
'threshold':775
},
31:{
'interval':155,
'threshold':825
},
32:{
'interval':145,
'threshold':880
},
33:{
'interval':140,
'threshold':950
},
34:{
'interval':135,
'threshold':1050
},
35:{
'interval':130,
'threshold':1150
},
36:{
'interval':125,
'threshold':1250
},
37:{
'interval':120,
'threshold':1350
},
38:{
'interval':115,
'threshold':1500
},
39:{
'interval':110,
'threshold':2000
},
40:{
'interval':100,
'threshold':5000
}
}
}
;(function() {
'use strict';
function Grid(gridDiv) {
this.gridDiv=document.getElementById(gridDiv);
this.inititialiseCells();
this.previewDiv=document.getElementById('js-next-piece');
this.initialisePreviewCells();
this.timer=new window.Timer(this);
this.keyListener=new window.KeyListener(this);
this.startGame();
}
Grid.prototype = {
// initial grid size
size:Config.size,
// the div this grid appears in
gridDiv:{},
// an array of cells, based on size
cells:[],
// current level
level:0,
// level definitions, such as interval, score thresh-hold etc
levels:Config.levels,
// the currently generated pieces
pieces:[],
// preview panel
previewCells:[],
previewDiv:{},
// the running score total
score:0,
/**
* inititialiseCells() - builds an array of cell objects
*/
inititialiseCells:function()
{
for (var y=0;y<this.size.height;y++)
{
this.cells[y]=[];
for (var x=0;x<this.size.width;x++)
{
this.cells[y][x]=new window.Cell(x,y);
this.cells[y][x].buildCellHtml()
this.cells[y][x].appendCell(this.gridDiv);
}
}
},
/**
* initialisePreviewCells() - sets up the piece preview cells
*/
initialisePreviewCells: function()
{
for (var y=0; y<5; y++)
{
this.previewCells[y]=[];
for (var x=0; x<5; x++)
{
this.previewCells[y][x]=new window.Cell(x,y);
this.previewCells[y][x].buildCellHtml()
this.previewCells[y][x].appendCell(this.previewDiv);
}
}
},
/**
* startGame() - triggers a game, including piece generation and timing
*/
startGame:function()
{
this.addPieceToGame();
this.addPieceToGame();
this.pieces[0].displayPreviewPiece(this.previewCells);
this.pieces[1].displayPiece(this.cells);
this.timer.startTimer();
},
/**
* addPieceToGame() - generates a new piece object for play
*/
addPieceToGame:function()
{
this.pieces.unshift(new Piece());
},
/**
* outputScore() - put the score on the screen
*/
outputScore: function()
{
document.getElementById("js-score").innerHTML=this.score;
},
/**
* outputLevel() - put the level on the screen
*/
outputLevel: function()
{
document.getElementById("js-level").innerHTML=this.level;
},
/**
* findCompletedRows() - looks for completed rows now this piece is stopped
*/
findCompletedRows: function(piecePosition)
{
// get the rows this piece occupies
var rowsToCheck={};
for (var index in piecePosition)
{
rowsToCheck[piecePosition[index].y]=1;
}
// iterate over those rows checking for a full set of states
var removeRows={};
for (var row in rowsToCheck)
{
var cellCount=0;
for (var x=0; x<this.size.width; x++)
{
cellCount+=this.cells[row][x].state;
}
if (cellCount === this.size.width)
{
removeRows[row]=1;
}
}
// if completed then trigger completed row function
var score=Object.keys(removeRows).length * Object.keys(removeRows).length;
this.score+=score;
this.outputScore();
for (var removeRow in removeRows)
{
// set all cells in the row to white and state=0
for (var x=0; x<this.size.width; x++)
{
this.cells[removeRow][x].unmarkCell();
// look up this column setting colour and state
for (var y=removeRow; y>=0; y--)
{
if ((y-1)>=0)
{
if (1==this.cells[y-1][x].state)
{
this.cells[y][x].markCell(this.cells[y-1][x].colour);
}
else
{
this.cells[y][x].unmarkCell();
}
}
}
}
}
}
};
window.Grid = Grid;
}());
;(function() {
'use strict';
function Piece() {
this.currentPosition={};
this.selectShape();
this.selectColour();
this.allowedMoves={
'left':true,
'right':true,
'down':true,
'rotate':true
};
this.stopped=false;
this.devOutput();
}
Piece.prototype = {
// stores what moves can be made from the current piece position
allowedMoves:{
'left':true,
'right':true,
'down':true,
'rotate':true
},
// stores the colour of this piece
colour:'',
// the set of colours this piece may take, needs to correspond to _colours.scss
colours:{
0:'blue',
1:'green',
2:'yellow',
3:'red',
4:'grey',
5:'black',
6:'purple',
7:'orange',
8:'turquoise'
},
// the current set of co-ordinates for this piece, four x/ys
currentPosition:{},
// the current orientation of this piece
currentOrientation:0,
// as above two but for next
nextPosition:{},
nextOrientation:0,
// the shape of this piece
shape:{},
// shapes including their initial positions on a ten wide grid
// positions can be centred for other grid widths by incrementing
// or decrementing all x co-ordinates
shapes:{
// I 0123456789 0123456789
// 0 .....#.... ..........
// 1 .....#.... ...####...
// 2 .....#.... ..........
// 3 .....#.... ..........
0:
{
0:{0:{x:5,y:0},1:{x:5,y:1},2:{x:5,y:2},3:{x:5,y:3}},
1:{0:{x:3,y:1},1:{x:4,y:1},2:{x:5,y:1},3:{x:6,y:1}}
},
// J 0123456789 0123456789 0123456789 0123456789
// 0 .....#.... ....#..... .....##... ..........
// 1 .....#.... ....###... .....#.... ....###...
// 2 ....##.... .......... .....#.... ......#...
// 3 .......... .......... .......... ..........
1:
{
0:{0:{x:5,y:0},1:{x:5,y:1},2:{x:4,y:2},3:{x:5,y:2}},
1:{0:{x:4,y:0},1:{x:4,y:1},2:{x:5,y:1},3:{x:6,y:1}},
2:{0:{x:5,y:0},1:{x:6,y:0},2:{x:5,y:1},3:{x:5,y:2}},
3:{0:{x:4,y:1},1:{x:5,y:1},2:{x:6,y:1},3:{x:6,y:2}}
},
// L 0123456789 0123456789 0123456789 0123456789
// 0 .....#.... .......... ....##.... ......#...
// 1 .....#.... ....###... .....#.... ....###...
// 2 .....##... ....#..... .....#.... ..........
// 3 .......... .......... .......... ..........
2:
{
0:{0:{x:5,y:0},1:{x:5,y:1},2:{x:5,y:2},3:{x:6,y:2}},
1:{0:{x:4,y:1},1:{x:5,y:1},2:{x:6,y:1},3:{x:4,y:2}},
2:{0:{x:4,y:0},1:{x:5,y:0},2:{x:5,y:1},3:{x:5,y:2}},
3:{0:{x:6,y:0},1:{x:4,y:1},2:{x:5,y:1},3:{x:6,y:1}}
},
// O 0123456789
// 0 ....##....
// 1 ....##....
// 2 ..........
// 3 ..........
3:
{
0:{0:{x:4,y:0},1:{x:5,y:0},2:{x:4,y:1},3:{x:5,y:1}}
},
// S 0123456789 0123456789
// 0 .....##... ....#.....
// 1 ....##.... ....##....
// 2 .......... .....#....
// 3 .......... ..........
4:
{
0:{0:{x:5,y:0},1:{x:6,y:0},2:{x:4,y:1},3:{x:5,y:1}},
1:{0:{x:4,y:0},1:{x:4,y:1},2:{x:5,y:1},3:{x:5,y:2}}
},
// T 0123456789 0123456789 0123456789 0123456789
// 0 .......... .....#.... .....#.... .....#....
// 1 ....###... ....##.... ....###... .....##...
// 2 .....#.... .....#.... .......... .....#....
// 3 .......... .......... .......... ..........
5:
{
0:{0:{x:4,y:1},1:{x:5,y:1},2:{x:6,y:1},3:{x:5,y:2}},
1:{0:{x:5,y:0},1:{x:4,y:1},2:{x:5,y:1},3:{x:5,y:2}},
2:{0:{x:5,y:0},1:{x:4,y:1},2:{x:5,y:1},3:{x:6,y:1}},
3:{0:{x:5,y:0},1:{x:5,y:1},2:{x:6,y:1},3:{x:5,y:2}}
},
// Z 0123456789 0123456789
// 0 ....##.... .....#....
// 1 .....##... ....##....
// 2 .......... ....#.....
// 3 .......... ..........
6:
{
0:{0:{x:4,y:0},1:{x:5,y:0},2:{x:5,y:1},3:{x:6,y:1}},
1:{0:{x:5,y:0},1:{x:4,y:1},2:{x:5,y:1},3:{x:4,y:2}}
}
},
// is this piece stopped, ie rached as far down as it will go and so a new piece is required
stopped:false,
/**
* countElements() - count the elements in an object
*
* @param count - integer count of object properties
*/
countElements: function(obj)
{
return Object.keys(obj).length;
},
/**
* selectShape() - selects a shape and orientation
*/
selectShape:function()
{
// select one of seven pieces at random
this.shape=this.shapes[this.selectRandom(this.shapes)];
// select a current orientation from that shape
this.currentOrientation=this.selectRandom(this.shape);
// clone that orientation into the current position property so
// shapes array is not edited on piece move
this.cloneOrientation();
},
/**
* selectColour() - selects a colour for this piece
*/
selectColour:function()
{
this.colour=this.colours[this.selectRandom(this.colours)];
},
/**
* selectRandom() - randomly selects a ref num from a count of object properties
*
* @param count - integer count of object properties
*/
selectRandom: function (obj)
{
return Math.floor(Math.random() * this.countElements(obj));
},
/**
* cloneOrientation() - copy the orientation into the object from the shapes
*/
cloneOrientation: function()
{
this.currentPosition={
0:{
x:this.shape[this.currentOrientation][0].x,
y:this.shape[this.currentOrientation][0].y
},
1:{
x:this.shape[this.currentOrientation][1].x,
y:this.shape[this.currentOrientation][1].y
},
2:{
x:this.shape[this.currentOrientation][2].x,
y:this.shape[this.currentOrientation][2].y
},
3:{
x:this.shape[this.currentOrientation][3].x,
y:this.shape[this.currentOrientation][3].y
}
}
},
/**
* getNextOrientation() - looks at the next orientation for this piece
*/
getNextOrientation: function()
{
var count=this.countElements(this.shape);
if (this.currentOrientation === (count - 1))
{
var orientation=this.shape[0];
this.nextOrientation=0;
return orientation;
}
else
{
var orientation=this.shape[this.currentOrientation + 1];
this.nextOrientation=this.currentOrientation + 1;
return orientation;
}
},
/**
* displayPiece() - set the current piece to be visible on the screen in its current
* position
* @param cells - the array of cells
*/
displayPiece:function(cells)
{
for (var index in this.currentPosition)
{
var coordinates=this.currentPosition[index];
cells[coordinates.y][coordinates.x].markCell(this.colour);
}
},
/**
* displayPreviewPiece() - place a piece in the preview window
*/
displayPreviewPiece: function(previewCells)
{
for (var y=0; y<5; y++)
{
for (var x=0; x<5; x++)
{
previewCells[y][x].unmarkCell();
}
}
for (var index in this.currentPosition)
{
var coordinates=this.currentPosition[index];
previewCells[coordinates.y+1][coordinates.x-3].markCell(this.colour);
}
},
/**
* movePiece() - moves a piece one cell in the given direction
* @param cells - array of cells for redrawing
* @param direction - left, right or down
* @param interval - timing interval for pausing set stopped action
*/
movePiece:function(cells,direction,interval)
{
if (false === this.checkMove('down') &&
'down' === direction)
{
// delay set stopped so that piece can be moved either side
var pauseInterval=interval-1; // remove one millisecond so as not to interfere with next interval
var t=this;
setTimeout(function() { t.setStopped(); },pauseInterval);
}
else
{
if (true === this.checkMove(direction))
{
for (var index in this.currentPosition)
{
var coordinates=this.currentPosition[index];
cells[coordinates.y][coordinates.x].unmarkCell();
this.setNewCoordinates(coordinates,direction);
}
this.setAllowedMoves(cells);
this.displayPiece(cells);
}
}
},
/**
* setNewCoordinates() - sets the new coordinates based on direction
* @param currentCoordinates - the cell coordinates to work on
* @param direction - direction the piece should move
*/
setNewCoordinates:function (currentCoordinates,direction)
{
switch(direction)
{
case 'left':
currentCoordinates.x--;
break;
case 'right':
currentCoordinates.x++;
break;
case 'down':
currentCoordinates.y++;
break;
}
},
/**
* rotate() - rotate the current piece clockwise
*/
rotate:function(cells)
{
if (true === this.checkMove('rotate'))
{
// get the next orientation
this.nextPosition=this.getNextOrientation();
// compute cell differences, i.e. the relationship between current and next
// use the original orientation
var compareOrientation=this.shape[this.currentOrientation];
// get x and y offset from the original orientation position
var xoffset=this.currentPosition[0].x - compareOrientation[0].x;
var yoffset=this.currentPosition[0].y - compareOrientation[0].y;
for (var index in this.currentPosition)
{
var coordinates=this.currentPosition[index];
cells[coordinates.y][coordinates.x].unmarkCell();
this.currentPosition[index].x=(this.nextPosition[index].x + xoffset);
this.currentPosition[index].y=(this.nextPosition[index].y + yoffset);
}
this.setAllowedMoves(cells);
this.displayPiece(cells);
this.currentOrientation=this.nextOrientation;
}
},
/**
* setStopped() - set this piece as stopped, this is checked by the interval timer
* and used to generate the new pieces
*/
setStopped: function ()
{
this.stopped=true;
},
/**
* resetAllowedMoves() - sets all allowed moves to true - required so that a piece
* move made before into an unmovable position doesn't block a legal move now
*/
resetAllowedMoves: function()
{
this.allowedMoves['left']=true;
this.allowedMoves['right']=true;
this.allowedMoves['down']=true;
this.allowedMoves['rotate']=true;
},
/**
* setAllowedMoves() - takes the current position and checks for the allowed moves
* @param cells - the array of cells
*/
setAllowedMoves: function(cells)
{
this.resetAllowedMoves();
for (var index in this.currentPosition)
{
var coordinates=this.currentPosition[index];
if (0 === coordinates.x ||
1 === cells[coordinates.y][(coordinates.x - 1)].state)
{
this.allowedMoves['left']=false;
}
if ((Config.size.width - 1) === coordinates.x ||
1 === cells[coordinates.y][(coordinates.x + 1)].state)
{
this.allowedMoves['right']=false;
}
if ((Config.size.height - 1) === coordinates.y ||
1 === cells[(coordinates.y + 1)][coordinates.x].state)
{
this.allowedMoves['down']=false;
}
}
// rotate
// get the next orientation
var nextPositionTest=this.getNextOrientation();
// compute cell differences, i.e. the relationship between current and next
// use the original orientation
var compareOrientation=this.shape[this.currentOrientation];
// get x and y offset from the original orientation position
var xoffset=this.currentPosition[0].x - compareOrientation[0].x;
var yoffset=this.currentPosition[0].y - compareOrientation[0].y;
for (var index in this.currentPosition)
{
var coordinates=this.currentPosition[index];
var nextPosX=nextPositionTest[index].x + xoffset;
var nextPosY=nextPositionTest[index].y + yoffset;
if (nextPosX<0 ||
nextPosX>=Config.size.width)
{
this.allowedMoves['rotate']=false;
break;
}
if (nextPosY<0 ||
nextPosY>=Config.size.height)
{
this.allowedMoves['rotate']=false;
break;
}
if (1 === cells[nextPosY][nextPosX].state)
{
this.allowedMoves['rotate']=false;
break;
}
}
},
/**
* checkMove() - looks at allowed moves to see if the move event is viable
*/
checkMove:function(move)
{
return this.allowedMoves[move];
},
/**
* devOutput() - adds this pieces data to the piece array dev output
*/
devOutput: function()
{
var devPieceOut=document.createElement("div");
var coordinates="<span class='dev-coordinates'>";
var c=1;
for (var coords in this.currentPosition)
{
coordinates+=c+"y:"+this.currentPosition[coords].y+" x:"+this.currentPosition[coords].x+"; ";
c++;
}
coordinates+="</span><br/><br/>";
devPieceOut.innerHTML=coordinates;
var allowedMoves="<span class='dev-allowed'>";
for (var allowed in this.allowedMoves)
{
allowedMoves+=this.allowedMoves[allowed]+"; ";
c++;
}
allowedMoves+="</span><br/><br/>";
devPieceOut.innerHTML=JSON.stringify(this,null,4)+"<br/><br/>";
//devPieceOut.innerHTML=JSON.stringify(this.shapes,null,4)+"<br/><br/>";
//document.getElementById("js-piece-data").appendChild(devPieceOut);
}
};
window.Piece = Piece;
}());
;(function() {
'use strict';
function Cell(x,y) {
this.x=x;
this.y=y;
}
Cell.prototype = {
// the div for this cell, with it's classes for colour
cellHtml:'',
// dev output to show cell state
devState:false,
// cells colour
colour:'white',
// the piece to which this cell currently belongs
piece:{},
// is this cell filled or not, filled cells restrict moves
state:0,
// co-ordinates
x:0,
y:0,
/**
* appendCell() - adds a cell to the grid div
* @param gridDiv - the div which contains the playing grid
*/
appendCell: function(gridDiv)
{
gridDiv.appendChild(this.cellHtml);
},
/**
* buildCellHtml() - builds some html for this cell
*/
buildCellHtml: function()
{
this.cellHtml=document.createElement("div");
this.addDevOutput();
this.setHtmlClass();
},
/**
* markCell() - marks a cell as filled and coloured
*
* @param colour - colour to mark the cell with
*/
markCell: function(colour)
{
this.setColour(colour);
this.setState(1);
},
/**
* unmarkCell() - unmarks a cell, back to white and empty
*/
unmarkCell: function()
{
this.setColour('white');
this.setState(0);
},
/**
* setColour() - sets the colour for this cell, html and
*/
setColour: function(colour)
{
this.colour=colour;
this.setHtmlClass();
},
/**
* setState() - sets a cells state
*
* @param state - Boolean part of a piece or not
*/
setState: function(state)
{
this.state=state;
if (true === this.devState)
{
document.getElementById('js-state-dev-'+this.x+'-'+this.y).innerHTML=state;
}
},
/**
* setHtmlClass() - sets the class for this cell
*/
setHtmlClass: function()
{
this.cellHtml.setAttribute("class","cell "+this.colour);
},
/**
* addDevOutput() - adds x, y and state values to cells for dev work
*/
addDevOutput: function()
{
if (true === this.devState)
{
this.cellHtml.innerHTML="<span id='js-x-dev' class='cell-dev x-dev'>"+this.x+"</span><span id='js-y-dev y-dev' class='cell-dev'>"+this.y+"</span><span id='js-state-dev-"+this.x+"-"+this.y+"' class='cell-dev state-dev'>"+this.state+"</span>";
}
}
};
window.Cell = Cell;
}());
;(function() {
'use strict';
var t;
function KeyListener(grid,timer) {
t=this;
t.grid=grid;
t.timer=grid.timer;
t.inititialiseKeys();
}
KeyListener.prototype = {
// the grid the events happen to
grid:{},
// the timer triggering intervals
timer:{},
/**
* inititialiseKeys() - adds an event listener for keypresses
*/
inititialiseKeys:function()
{
window.addEventListener('keydown',t.keyListener);
},
/**
* keyListener() - responds to the key presses for game play
*/
keyListener:function(keyEvent)
{
var cells=t.grid.cells;
var inPlayPiece=t.grid.pieces[1];
switch (keyEvent.keyCode)
{
case 37:
keyEvent.preventDefault();
inPlayPiece.movePiece(cells,'left',t.timer);
break;
case 39:
keyEvent.preventDefault();
inPlayPiece.movePiece(cells,'right',t.timer);
break;
case 40:
keyEvent.preventDefault();
inPlayPiece.movePiece(cells,'down',t.timer);
break;
case 32:
keyEvent.preventDefault();
inPlayPiece.rotate(cells);
break;
case 49: // 1 key for pausing
keyEvent.preventDefault();
if (true === t.timer.running)
{
t.timer.pauseTimer();
}
else
{
t.timer.startTimer();
}
break;
}
}
};
window.KeyListener = KeyListener;
}());;(function() {
'use strict';
var t;
function Timer(grid) {
t=this;
t.grid=grid;
t.currentInterval=t.grid.levels[0]['interval'];
t.eventCounterSpan=document.getElementById('js-event-counter');
}
Timer.prototype = {
// the current number of milliseconds between timer event
currentInterval:0,
// a counter for the number of events since game started
eventCount:0,
// a dom element for outputting event count (dev)
eventCounterSpan:{},
// stores the interval id for pausing (useful for dev)
intervalId:null,
// state, if running === true then the timer is running, else it's paused
running:true,
/**
* startTimer() - sets the timer running in response to a game start
*/
startTimer:function()
{
t.intervalId = setInterval(t.intervalTrigger,t.currentInterval);
t.running=true;
},
/**
* pauseTimer() - pause the timer
*/
pauseTimer:function()
{
window.clearInterval(t.intervalId);
t.running=false;
},
/**
* intervalTrigger() - function called each time an interval elapsed
*/
intervalTrigger:function()
{
var pieces=t.grid.pieces;
t.eventCount++;
t.eventCounterSpan.innerHTML=t.eventCount;
pieces[1].movePiece(t.grid.cells,'down',t.currentInterval);
if (true === pieces[1].stopped)
{
pieces[1].displayPiece(t.grid.cells);
t.grid.findCompletedRows(pieces[1].currentPosition);
pieces.unshift(new Piece());
pieces[0].displayPreviewPiece(t.grid.previewCells);
// stop game if new piece won't fit
var gameOver=false;
for (var index in pieces[1].currentPosition)
{
var coordinates=pieces[1].currentPosition[index];
if (1 === t.grid.cells[coordinates.y][coordinates.x].state)
{
gameOver=true;
break;
}
}
if (true === gameOver)
{
t.pauseTimer();
}
}
// do levels
var levelData=t.grid.levels[t.grid.level];
if (t.eventCount>=levelData.threshold)
{
t.grid.level++;
t.grid.outputLevel();
t.pauseTimer();
t.currentInterval=levelData.interval;
t.startTimer()
}
}
};
window.Timer = Timer;
}());
window.tetris=new window.Grid('js-tetris');
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.