JS Tetris

Tetris powered by JS drawn on the HTML5 canvas element. Makes use of requestAnimationFrame in a throttled rendering loop.

by Taylor Lopez

HTML

<script src="https://cdn.rawgit.com/iAmMortos/JSConsole/master/console.min.js"></script>
<canvas id="board"></canvas>
<table id="stats">
	<tr>
		<td>Score</td>
		<td id="score"></td>
	</tr>
	<tr>
		<td>Lvl</td>
		<td id="level"></td>
	</tr>
	<tr>
		<td>Lines</td>
		<td id="lines"></td>
	</tr>
</table>
<div class="floatClear"></div>

CSS

html
{
  opacity: 1;
}

#board
{
    border: solid #ccc 1px;
	float: left;
}

#stats
{
	color: #000;
	font-size: 12px;
	font-family: Arial;
	float: left;
	border-collapse: collapse;
}
#stats td
{
	padding: 1px;
	margin: 0;
}

.floatClear
{
	clear: both;
	font-size: 0;
	display: hidden;
}

JavaScript

/////////// MAIN ///////////



function main() 
{
  // enableConsole();
  var game = new Tet();
  game.start();
}



/////////// CLASSES ///////////



/********** Vec2d Class **********/
function Vec2d(newX, newY)
{
  this.x = typeof newX !== 'undefined' ? newX : 0;
  this.y = typeof newY !== 'undefined' ? newY : 0;
}
/********** Vec2d Methods **********/
Vec2d.prototype.valueOf = function ()
{
  return {x: this.x, y: this.y};
};
Vec2d.prototype.getOffset = function(x, y)
{
  return new Vec2d(this.x + x, this.y + y);
};
/********** Vec2d Static Methods **********/
Vec2d.add = function(v1, v2)
{
  return new Vec2d(v1.x + v2.x, v1.y + v2.y);  
};



/********** Color Class **********/
// Accepts Color(100,200,0) or Color("#64C800")
function Color(r, g, b) {
  if (typeof r === 'string' && (r.indexOf('#') === 0 || r.indexOf('0x') === 0))
  {
    var colorStr = r;
    if (colorStr.indexOf("#") === 0)
      colorStr = colorStr.slice(1);
    else // starts with '0x'
      colorStr = colorStr.slice(2);
    
    if ([3, 6].indexOf(colorStr.length) !== -1)
    {
      // doubles every character to make it a uniform 6 characters
      if (colorStr.length === 3)
        for (var i = 0; i < 6; i += 2)
          colorStr = colorStr.slice(0,i) + colorStr[i] + colorStr.slice(i);
          
      this.r = parseInt(colorStr.slice(0,2), 16);
      this.g = parseInt(colorStr.slice(2,4), 16);
      this.b = parseInt(colorStr.slice(4), 16);

      if (isNaN(this.r + this.g + this.b))
        console.log("ERROR: Your color object string parameter was not in valid hexedecimal format: " + r);
    }
    else
      console.log("ERROR: Your Color object string parameter is the wrong size (not 3 or 6): " + r);
  }
  else
  {
    this.r = typeof r !== 'undefined' ? r : 0;
    this.g = typeof g !== 'undefined' ? g : 0;
    this.b = typeof b !== 'undefined' ? b : 0;
  }
}
/********** Color Methods **********/
Color.prototype.valueOf = function () {
  return {
    r: this.r,
    g: this.g,
   ...