|
回复 seabookf_91 1# 帖子
此文章由 YugaYuga 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 YugaYuga 所有!转贴必须注明作者、出处和本声明,并保持内容完整
showing in chrome:
jsFiddle
Run again
Edit this fiddle
JavaScript
HTML
CSS
Result
/*
Clone, create and extend functions are used for Inheritance purpose.
For more details, please seach Eloquent Javascript on Google and go to charpter 8.
*/
function clone(object) {
function OneShotConstructor(){}
OneShotConstructor.prototype = object;
return new OneShotConstructor();
}
Object.prototype.create = function() {
var object = clone(this);
if (typeof object.construct == "function")
object.construct.apply(object, arguments);
return object;
};
Object.prototype.extend = function(properties) {
var result = clone(this);
forEachIn(properties, function(name, value) {
result[name] = value;
});
return result;
};
/*
These are helper methods to do loop through 2 Dimensional Array or just one Dimensional Array.
*/
function forEach2D(arr, action) {
for (var i = 0; i < arr.length; i++) {
var length = arr.length;
for (var j = 0; j < length; j++) {
action(i, j, arr[j]);
}
}
}
function forEach(arr, action) {
for (var i = 0; i < arr.length; i++) {
action(i, arr);
}
}
function forEachIn(obj, func) {
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop) && Object.prototype.propertyIsEnumerable.call(obj, prop)) {
func(prop, obj[prop]);
}
}
}
/*
Define some global variables.
*/
var gridSize = 20;
var boardWidth = 10;
var boardHeight = 20;
var ctx = undefined;
var board = undefined;
var piece = undefined;
var interval = undefined;
$(function() {
init();
if (ctx && piece && board) {
bindKeys(piece, ctx);
interval = window.setInterval("reDraw()",300);
}
})
var init = function() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
ctx = canvas.getContext("2d");
board = new Board(boardWidth, boardHeight);
board.initBoard();
piece = generateRandomPiece(board);
}else {
alert("Your browser doesn't support HTML5!!!");
}
}
var Piece = {
construct: function(x, y, direction, board, color) {
this.x = x;
this.y = y;
this.direction = direction;
this.olds = [];
this.shape = {};
this.board = board;
this.color = color;
this.dead = false;
},
getNextDirection: function () {
var that = this;
var directions = ['up', 'right', 'down', 'left'];
var index = 0;
forEach(directions, function(i, value){
if (value === that.direction) {
var tmpIndex = directions.indexOf(value);
if (tmpIndex === directions.length - 1) {
index = 0;
} else {
index = tmpIndex + 1;
}
}
})
return directions[index];
},
drawSelf: function(ctx) {
var that = this;
var clearOlds = function() {
if (that.olds.length > 0) {
forEach(that.olds, function(i, value) {
var tmpX = value.x;
var tmpY = value.y;
ctx.clearRect(tmpX, tmpY, gridSize, gridSize);
})
that.olds = [];
}
}
var renderNews = function() {
var shape = that.shape[that.direction];
var length = shape.length - 1;
forEach2D(shape, function(i, j, value) {
if (value === 1) {
var tmpX = that.x * gridSize + j * gridSize;
var tmpY = that.y * gridSize + i * gridSize;
that.olds.push({x: tmpX, y: tmpY});
ctx.fillStyle = that.color;
ctx.fillRect (tmpX, tmpY, gridSize, gridSize);
}
})
}
clearOlds();
renderNews();
},
setRotateShapes: function() {
console.log("Need to overide!!!");
},
getPieceShape: function() {
return this.shape[this.direction];
},
getShapeWidthByDirection: function() {
return this.getPieceShape()[0].length;
},
getShapeHeightByDirection: function() {
return this.getPieceShape().length;
},
canEachPartMoveLeft: function(pieceShape) {
var need2Check = new Array(pieceShape.length);
for (var i = 0; i < pieceShape.length; i++) {
var length = pieceShape.length;
for (var j = 0; j < length; j++) {
if (pieceShape[j] === 1) {
need2Check = {x: this.x + j, y: this.y + i};
break;
}
}
}
return need2Check;
},
canMoveLeft: function() {
if (this.dead) {
return false;
}
if (this.x <= 0) {
return false;
}
var canMoveLeftAgain = true;
forEach(this.canEachPartMoveLeft(this.getPieceShape()), function(i, value){
if (!canMoveLeftAgain) return;
var tmpX = value.x;
var tmpY = value.y;
var cell = this.board.cells[tmpX + tmpY * this.board.width - 1];
if (cell && cell.value === 1) {
canMoveLeftAgain = false;
}
})
return canMoveLeftAgain;
},
canEachPartMoveRight: function(pieceShape) {
var that = this;
var need2Check = new Array(pieceShape.length);
forEach2D(pieceShape, function(i, j, value) {
if (value === 1) {
need2Check = {x: that.x + j, y: that.y + i};
}
})
return need2Check;
},
canMoveRight: function() {
if (this.dead) {
return false;
}
if ((this.x + this.getShapeWidthByDirection()) >= this.board.width) {
return false;
}
var canMoveRightAgain = true;
forEach(this.canEachPartMoveRight(this.getPieceShape()), function(i, value){
if (!canMoveRightAgain) return;
var tmpX = value.x;
var tmpY = value.y;
var cell = this.board.cells[tmpX + tmpY * this.board.width + 1];
if (cell && cell.value === 1) {
canMoveRightAgain = false;
}
})
return canMoveRightAgain;
},
canEachPartMoveDown: function(pieceShape) {
var that = this;
var need2Check = new Array(pieceShape[0].length);
forEach2D(pieceShape, function(i, j, value) {
if (value === 1) {
need2Check[j] = {x: that.x + j, y: that.y + i};
}
})
return need2Check;
},
canMoveDown: function() {
if (this.dead) {
return false;
}
if ((this.y + this.getShapeHeightByDirection(this.getPieceShape())) >= this.board.height) {
return false;
}
var canMoveDownAgain = true;
forEach(this.canEachPartMoveDown(this.getPieceShape()), function(i, value){
if (!canMoveDownAgain) return;
var tmpX = value.x;
var tmpY = value.y;
var cell = this.board.cells[tmpX + (tmpY + 1) * this.board.width];
if (cell && cell.value === 1) {
canMoveDownAgain = false;
}
})
return canMoveDownAgain;
},
canRotate: function() {
if (this.dead) {
return false;
}
var nextDirect = this.getNextDirection();
var shapeArr = this.shape[nextDirect];
var rights = this.canEachPartMoveRight(shapeArr);
for (var i = 0; i < rights.length; i++) {
var tmpX = rights.x;
var tmpY = rights.y;
if (tmpX >= this.board.width) {
return false;
}
}
var downs = this.canEachPartMoveDown(shapeArr);
for (var i = 0; i < downs.length; i++) {
var tmpX = downs.x;
var tmpY = downs.y;
if (tmpY >= this.board.height) {
return false;
}
var cell = this.board.cells[tmpX + (tmpY + 1) * this.board.width];
if (cell && cell.value === 1) {
return false;
}
}
return true;
},
setPieceOnBoard: function() {
var that = this;
forEach2D(that.getPieceShape(), function(i, j, value){
if (value === 1)
that.board.setCell(that.x + j, that.y + i, value, that.color);
})
}
}
var RL = Piece.extend ({
setRotateShapes: function() {
this.shape = {
up: [[1,0], [1,0], [1,1]],
right: [[1,1,1], [1,0,0]],
down: [[1,1], [0,1], [0,1]],
left: [[0,0,1], [1,1,1]]
}
}
});
var LL = Piece.extend ({
setRotateShapes: function() {
this.shape = {
up: [[0,1], [0,1], [1,1]],
right: [[1,0,0], [1,1,1]],
down: [[1,1], [1,0], [1,0]],
left: [[1,1,1], [0,0,1]]
}
}
});
var Block = Piece.extend ({
setRotateShapes: function() {
this.shape = {
up: [[1,1], [1,1]],
right: [[1,1], [1,1]],
down: [[1,1], [1,1]],
left: [[1,1], [1,1]]
}
}
});
var T = Piece.extend ({
setRotateShapes: function() {
this.shape = {
up: [[0,1,0], [1,1,1]],
right: [[1,0], [1,1], [1,0]],
down: [[1,1,1], [0,1,0]],
left: [[0,1], [1,1], [0,1]]
}
}
});
var Stick = Piece.extend ({
setRotateShapes: function() {
this.shape = {
up: [[1], [1], [1], [1]],
right: [[1,1,1,1]],
down: [[1], [1], [1], [1]],
left: [[1,1,1,1]]
}
}
})
/*
Tetris Board holding all the cells.
*/
function Board(width, height) {
this.width = width;
this.height = height;
this.reDraw = false;
this.cells = new Array(this.width * this.height);
this.initBoard = function() {
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
var cell = new Cell(x, y, 0, '#FFFAFA');
this.cells[cell.x + cell.y * this.width] = cell;
}
}
}
// Recursively search the board to find the lines full
this.resetBoardRecursive = function(lineNo) {
if (lineNo == this.height) return;
var isLineFull = true;
for (var i = 0; i < this.width; i++) {
if (this.getCell(i, lineNo).value != 1) {
isLineFull = false;
break;
}
}
if (isLineFull) {
var tmpLineNo = lineNo;
this.reSetBoard(tmpLineNo);
this.reDraw = true;
}
this.resetBoardRecursive(++lineNo);
}
// Reset the board recursively
this.reSetBoard = function(lineNo) {
if (lineNo === 0) return;
for (var i = 0; i < this.width; i++) {
var cell = this.getCell(i, lineNo -1);
this.setCell(i, lineNo, cell.value, cell.color);
}
this.reSetBoard(--lineNo);
}
this.drawSelf = function (ctx) {
ctx.clearRect(0, 0, this.width * gridSize, this.height * gridSize);
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
var cell = this.getCell(x, y);
if (cell.value === 1) {
ctx.fillStyle = "#A9A9A9";
ctx.fillRect (cell.x * gridSize, cell.y * gridSize, gridSize, gridSize);
}
}
}
}
this.setCell = function(x, y, value, color) {
if ( x >= 0 && y >= 0) {
this.cells[x + y * this.width].value = value;
this.cells[x + y * this.width].color = color;
}
}
this.getCell = function(x, y) {
return this.cells[x + y * this.width];
}
this.printBoard = function() {
var printValue ="";
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
printValue += this.getCell(x, y).value;
}
printValue += "\n";
}
return printValue;
}
this.gameOver = function() {
var gameOver = false;
for (var i = 0; i < this.width; i++) {
if (this.getCell(i, 0).value === 1) {
gameOver = true;
break;
}
}
return gameOver;
}
function Cell(x, y, value, color) {
this.x = x;
this.y = y;
this.value = value;
this.color = color;
}
}
function generateRandomPiece(board) {
var pieces = [LL, RL, T, Block, Stick];
var colorObj = {
orange: '#FFA500',
brown: '#AC5930',
green: 'rgba(60,179,113,1)',
blue: '#4169E1',
red: '#DC143C',
pink: '#FF99FF'
}
function randomColor() {
var colors = [];
forEachIn(colorObj, function(prop, value){
colors.push(prop);
})
var rIndex = colors[Math.floor(Math.random() * colors.length)];
return colorObj[rIndex];
}
var randomPiece = pieces[Math.floor(Math.random() * pieces.length)];
var piece = randomPiece.create(4, 0, 'up', board, randomColor());
piece.setRotateShapes();
return piece;
}
/*
Use Jquery to bind the keyboard arrows with piece actions
*/
function bindKeys() {
$("body").keydown(function(event) {
event.stopPropagation();
if (event.which === 37) {
if (piece.canMoveLeft())
piece.x --;
} else if (event.which === 38) {
if (piece.canRotate())
piece.direction = piece.getNextDirection();
} else if (event.which === 39) {
if (piece.canMoveRight())
piece.x ++;
} else if (event.which === 40) {
if (piece.canMoveDown())
piece.y ++;
else {
piece.dead = true;
}
}
piece.drawSelf(ctx);
});
}
function reDraw() {
piece.drawSelf(ctx);
if (piece.canMoveDown())
piece.y ++;
else {
piece.dead = true;
}
if (piece.dead) {
piece.setPieceOnBoard();
board.resetBoardRecursive(1);
if (board.reDraw) {
board.drawSelf(ctx);
board.reDraw = false;
}
piece = generateRandomPiece(board);
}
if (board.gameOver()) {
if (interval) {
window.clearInterval(interval);
}
alert("Oops...., Game Over!!!");
}
} |
|