ngtris
Version:
Angular Tetris game
303 lines (302 loc) • 16.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var core_1 = require("@angular/core");
var Observable_1 = require("rxjs/Observable");
require("rxjs/add/observable/timer");
var NGTRISSHAPES = {
I: {
color: '#F44336',
transform: [[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]]
},
O: {
color: '#9C27B0',
transform: [[[1, 1], [1, 1]],
[[1, 1], [1, 1]],
[[1, 1], [1, 1]],
[[1, 1], [1, 1]]]
},
T: {
color: '#3F51B5',
transform: [[[0, 1, 0], [1, 1, 1], [0, 0, 0]],
[[0, 1, 0], [0, 1, 1], [0, 1, 0]],
[[0, 0, 0], [1, 1, 1], [0, 1, 0]],
[[0, 1, 0], [1, 1, 0], [0, 1, 0]]]
},
J: {
color: '#03A9F4',
transform: [[[1, 0, 0], [1, 1, 1], [0, 0, 0]],
[[0, 1, 1], [0, 1, 0], [0, 1, 0]],
[[0, 0, 0], [1, 1, 1], [0, 0, 1]],
[[0, 1, 0], [0, 1, 0], [1, 1, 0]]]
},
L: {
color: '#4CAF50',
transform: [[[0, 0, 1], [1, 1, 1], [0, 0, 0]],
[[0, 1, 0], [0, 1, 0], [0, 1, 1]],
[[0, 0, 0], [1, 1, 1], [1, 0, 0]],
[[1, 1, 0], [0, 1, 0], [0, 1, 0]]]
},
S: {
color: '#CDDC39',
transform: [[[0, 1, 1], [1, 1, 0], [0, 0, 0]],
[[1, 0, 0], [1, 1, 0], [0, 1, 0]],
[[0, 1, 1], [1, 1, 0], [0, 0, 0]],
[[1, 0, 0], [1, 1, 0], [0, 1, 0]]]
},
Z: {
color: '#FF9800',
transform: [[[1, 1, 0], [0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 1], [0, 1, 0]],
[[1, 1, 0], [0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 1], [0, 1, 0]]]
}
};
var NGTrisComponent = (function () {
function NGTrisComponent() {
this.rows = 20;
this.cols = 10;
this.source = Observable_1.Observable.timer(500, 500);
}
NGTrisComponent.prototype.ngOnInit = function () {
var _this = this;
this.isPlay = false;
this.gameWidth = window.innerWidth;
this.gameHeight = window.innerHeight - 60;
if (this.gameHeight / 2 >= this.gameWidth) {
this.gameHeight = this.gameWidth;
}
else {
this.gameWidth = this.gameHeight / 2;
}
this.gameLeft = (window.innerWidth - this.gameWidth) / 2;
this.subscription = this.source.subscribe(function (x) { return _this.doTimer(); });
};
NGTrisComponent.prototype.ngOnDestroy = function () {
this.subscription.unsubscribe();
};
NGTrisComponent.prototype.onStart = function () {
this.isPlay = true;
this.scores = 0;
this.lines = 0;
this.matrix = [];
for (var row = 0; row < this.rows; row++) {
for (var col = 0; col < this.cols; col++) {
this.matrix[row * this.cols + col] = { 'width': '10%', 'height': '5%',
'top': row * 5 + '%', 'left': col * 10 + '%' };
}
}
this.activeTetrominoTransform = 0;
this.initActiveTetromino();
};
NGTrisComponent.prototype.onLeftButton = function () {
if (!this.isPlay) {
return;
}
if (this.isPositionAvailable(this.activeTetrominoPosX - 1, this.activeTetrominoPosY, this.activeTetrominoMatrix)) {
this.activeTetrominoPosX--;
}
};
NGTrisComponent.prototype.onRightButton = function () {
if (!this.isPlay) {
return;
}
if (this.isPositionAvailable(this.activeTetrominoPosX + 1, this.activeTetrominoPosY, this.activeTetrominoMatrix)) {
this.activeTetrominoPosX++;
}
};
NGTrisComponent.prototype.onRotateButton = function () {
if (!this.isPlay) {
return;
}
this.rotateActiveTetromino();
};
NGTrisComponent.prototype.onResize = function (event) {
if (!this.isPlay) {
return;
}
this.gameWidth = event.target.innerWidth;
this.gameHeight = event.target.innerHeight - 60;
if (this.gameHeight / 2 >= this.gameWidth) {
this.gameHeight = this.gameWidth;
}
else {
this.gameWidth = this.gameHeight / 2;
}
this.gameLeft = (window.innerWidth - this.gameWidth) / 2;
};
NGTrisComponent.prototype.handleKeyboardEvent = function (event) {
switch (event.which) {
case 39:
this.onRightButton();
break;
case 38:
this.onRotateButton();
break;
case 37:
this.onLeftButton();
break;
}
};
NGTrisComponent.prototype.checkGameOver = function () {
for (var col = 0; col < this.cols; col++) {
if (this.matrix[col].backgroundColor !== undefined) {
this.isPlay = false;
return true;
}
}
return false;
};
NGTrisComponent.prototype.generateActiveMatrix = function (key, activeMatirx, activeTransform) {
var transform = NGTRISSHAPES[key].transform[activeTransform];
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (transform[row] !== undefined && transform[row][col] === 1) {
activeMatirx[row * 4 + col] = { 'top': row * 25 + '%', 'left': col * 25 + '%', 'backgroundColor': NGTRISSHAPES[key].color };
}
else {
activeMatirx[row * 4 + col] = { 'top': row * 25 + '%', 'left': col * 25 + '%' };
}
}
}
};
NGTrisComponent.prototype.initActiveTetromino = function () {
this.activeTetrominoMatrix = [];
var keys = Object.keys(NGTRISSHAPES);
if (this.nextTetrominoKey === undefined || NGTRISSHAPES[this.nextTetrominoKey] === undefined) {
this.nextTetrominoKey = keys[Math.floor(Math.random() * keys.length)];
}
this.activeTetrominoKey = this.nextTetrominoKey;
this.nextTetrominoKey = keys[Math.floor(Math.random() * keys.length)];
this.generateActiveMatrix(this.activeTetrominoKey, this.activeTetrominoMatrix, this.activeTetrominoTransform);
this.activeTetrominoPosY = -2;
this.activeTetrominoPosX = 3;
this.nextTetrominoMatrix = [];
this.generateActiveMatrix(this.nextTetrominoKey, this.nextTetrominoMatrix, 0);
};
NGTrisComponent.prototype.rotateActiveTetromino = function () {
var activeMatrix = [];
var key = this.activeTetrominoKey;
this.activeTetrominoTransform = (this.activeTetrominoTransform + 1) % 4;
var transform = NGTRISSHAPES[key].transform[this.activeTetrominoTransform];
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (transform[row] !== undefined && transform[row][col] === 1) {
activeMatrix[row * 4 + col] = { 'top': row * 25 + '%', 'left': col * 25 + '%', 'backgroundColor': NGTRISSHAPES[key].color };
}
else {
activeMatrix[row * 4 + col] = { 'top': row * 25 + '%', 'left': col * 25 + '%' };
}
}
}
if (this.isPositionAvailable(this.activeTetrominoPosX, this.activeTetrominoPosY + 1, activeMatrix)) {
this.activeTetrominoMatrix = activeMatrix;
}
};
NGTrisComponent.prototype.doTimer = function () {
if (!this.isPlay) {
return;
}
if (this.activeTetrominoPosY < this.rows) {
if (!this.isPositionAvailable(this.activeTetrominoPosX, this.activeTetrominoPosY + 1, this.activeTetrominoMatrix)) {
this.transferTetrominoToGrid();
this.initActiveTetromino();
this.scores += 10;
}
else {
this.activeTetrominoPosY++;
}
}
};
NGTrisComponent.prototype.isPositionAvailable = function (x, y, activeMatrix) {
var tetrominoRows = 4;
var tetrominoCols = 4;
var relativeRow;
var relativeCol;
for (var row = 0; row < tetrominoRows; row++) {
for (var col = 0; col < tetrominoCols; col++) {
var cell = activeMatrix[row * tetrominoCols + col];
if (cell.backgroundColor) {
relativeRow = y + row;
relativeCol = x + col;
if (relativeCol < 0 || relativeCol >= this.cols) {
return false;
}
if (relativeRow >= this.rows) {
return false;
}
if (relativeRow >= 0) {
if (this.matrix[relativeRow * this.cols + relativeCol].backgroundColor) {
return false;
}
}
}
}
}
return true;
};
NGTrisComponent.prototype.clearLines = function () {
for (var row = this.rows - 1; row >= 0; row--) {
var completeLine = true;
for (var col = 0; col < this.cols; col++) {
if (this.matrix[row * this.cols + col].backgroundColor === undefined) {
completeLine = false;
break;
}
}
if (completeLine) {
for (var start = row; start > 0; start--) {
for (var col = 0; col < this.cols; col++) {
this.matrix[start * this.cols + col].backgroundColor = this.matrix[(start - 1) * this.cols + col].backgroundColor;
}
}
for (var col = 0; col < this.cols; col++) {
this.matrix[col].backgroundColor = undefined;
}
this.lines++;
this.scores += 100;
row++;
}
}
};
NGTrisComponent.prototype.transferTetrominoToGrid = function () {
var tetrominoRows = 4;
var tetrominoCols = 4;
var relativeRow;
var relativeCol;
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
var cell = this.activeTetrominoMatrix[row * tetrominoCols + col];
if (cell && cell.backgroundColor) {
relativeRow = this.activeTetrominoPosY + row;
relativeCol = this.activeTetrominoPosX + col;
if (this.matrix[relativeRow * this.cols + relativeCol]) {
this.matrix[relativeRow * this.cols + relativeCol].backgroundColor = cell.backgroundColor;
}
}
}
}
this.clearLines();
this.checkGameOver();
};
return NGTrisComponent;
}());
NGTrisComponent.decorators = [
{ type: core_1.Component, args: [{
moduleId: module.id,
selector: 'ng-tris',
template: "\n <div class=\"game-space\">\n <div class=\"game-panel-container\" [ngStyle]=\"{'left':gameLeft + 'px', 'width': gameWidth + 'px'}\">\n <table style=\"width: 100%; height: 100%; text-align:center;\">\n <tr>\n <td>Score: {{scores}}</td><td>Lines: {{lines}}</td><td>Next:</td>\n <td>\n <div class=\"next-tetromino next-tetromino-Z\" style=\"width: 20px; height: 20px;\">\n <ul class=\"tetromino\">\n <li class=\"grid-square-block\" *ngFor=\"let cell of nextTetrominoMatrix\" \n [ngStyle]=\"{'top': cell.top, 'left': cell.left}\">\n <div *ngIf=\"cell.backgroundColor\" class=\"square-block\" [ngStyle]=\"{'background-color': cell.backgroundColor}\"></div>\n </li>\n </ul>\n </div>\n </td>\n </tr>\n </table>\n </div>\n <div class=\"well-container\" [ngStyle]=\"{'top':'30px', 'left':gameLeft + 'px', 'width': gameWidth + 'px', 'height': gameHeight + 'px'}\">\n <div class=\"well\">\n <div class=\"active-tetromino\" [ngStyle]=\"{'top': activeTetrominoPosY * 5 + '%', 'left': activeTetrominoPosX * 10 + '%', 'width': '40%', 'height': '20%'}\">\n <ul class=\"tetromino\">\n <li class=\"grid-square-block\" *ngFor=\"let cell of activeTetrominoMatrix\" \n [ngStyle]=\"{'top': cell.top, 'left': cell.left}\">\n <div *ngIf=\"cell.backgroundColor\" class=\"square-block\" [ngStyle]=\"{'background-color': cell.backgroundColor}\"></div>\n </li>\n </ul>\n </div>\n <ul class=\"well-grid\">\n <li class=\"grid-square-block\" *ngFor=\"let cell of matrix\" \n [ngStyle]=\"{'top': cell.top, 'left': cell.left, 'width': cell.width, 'height': cell.height}\"\n >\n <div *ngIf=\"cell.backgroundColor\" class=\"square-block\" [ngStyle]=\"{'background-color': cell.backgroundColor}\"></div>\n </li>\n </ul>\n </div>\n </div>\n <div class=\"game-panel-container\" [ngStyle]=\"{'top': 30 + gameHeight + 'px','left':gameLeft + 'px', 'width': gameWidth + 'px', 'height':'30px'}\">\n <table style=\"width: 100%; height: 100%; text-align:center;\"><tr>\n <td><button class=\"game-control\" (click)=\"onRotateButton()\">\n <svg viewBox=\"0 0 24 24\" style=\"width: 25px; height: 25px;\">\n <path d=\"M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z\"></path>\n </svg>\n </button></td>\n <td><button class=\"game-control\" (click)=\"onLeftButton()\">\n <svg viewBox=\"0 0 24 24\" style=\"width: 25px; height: 25px;\">\n <path d=\"M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z\"></path>\n </svg>\n </button></td>\n <td><button class=\"game-control\" (click)=\"onRightButton()\">\n <svg viewBox=\"0 0 24 24\" style=\"width: 25px; height: 25px;\">\n <path d=\"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z\"></path>\n </svg>\n </button></td>\n </tr></table>\n </div>\n <div *ngIf=\"!isPlay\" class=\"game-panel-container\"\n [ngStyle]=\"{'top': 30 + gameHeight/4 + 'px','left':gameLeft + gameWidth/4 + 'px', 'width': gameWidth/2 + 'px', 'height':'50px'}\">\n <button style=\"width: 100%; height: 100%;\" (click)=\"onStart()\">Start</button>\n </div>\n</div>\n ",
styles: [
"\n .game-space {\n margin: 0;\n padding: 0;\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n .well-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: #ecf0f1;\n }\n\n .tetromino {\n margin: 0;\n padding: 0;\n list-style-type: none;\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .tetromino .grid-square-block {\n width: 25%;\n height: 25%;\n }\n\n .well {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n\n .game-panel-container {\n position: absolute;\n margin: 0;\n padding: 0;\n border: 0;\n height: 25px;\n }\n\n .well .well-grid {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .well .active-tetromino {\n position: absolute;\n }\n\n .well-grid {\n margin: 0;\n padding: 0;\n list-style-type: none;\n }\n\n .grid-square-block {\n position: absolute;\n transition: top 0.1s linear;\n }\n\n .square-block {\n width: 100%;\n height: 100%;\n }\n\n .game-control {\n margin: 0;\n padding: 0;\n border: 0;\n background: grey;\n color: #fff;\n }\n"
]
},] },
];
/** @nocollapse */
NGTrisComponent.ctorParameters = function () { return []; };
NGTrisComponent.propDecorators = {
'onResize': [{ type: core_1.HostListener, args: ['window:resize', ['$event'],] },],
'handleKeyboardEvent': [{ type: core_1.HostListener, args: ['document:keydown', ['$event'],] },],
};
exports.NGTrisComponent = NGTrisComponent;