From c1198070bd7f48c7108dd29af9a59e235a30e605 Mon Sep 17 00:00:00 2001 From: Julian Calvento Date: Thu, 9 May 2019 17:04:06 -0300 Subject: [PATCH 1/4] Use Polyglot to add spanish translations --- Gruntfile.js | 9 ++ build/classes/interface.js | 150 ------------------------------ build/classes/log | 5 - build/classes/tank.js | 162 -------------------------------- build/classes/unit.js | 128 -------------------------- build/log | 174 ----------------------------------- build/snake.js | 184 ------------------------------------- build/spacecraft.js | 124 ------------------------- build/tanks.js | 156 ------------------------------- index.js | 5 +- package.json | 8 +- src/locales/en.json | 17 ++++ src/locales/es.json | 16 ++++ src/snake.js | 27 ++++-- src/spacecraft.js | 71 +++++++------- src/tanks.js | 29 +++--- 16 files changed, 126 insertions(+), 1139 deletions(-) delete mode 100644 build/classes/interface.js delete mode 100644 build/classes/log delete mode 100644 build/classes/tank.js delete mode 100644 build/classes/unit.js delete mode 100644 build/log delete mode 100644 build/snake.js delete mode 100644 build/spacecraft.js delete mode 100644 build/tanks.js create mode 100644 src/locales/en.json create mode 100644 src/locales/es.json diff --git a/Gruntfile.js b/Gruntfile.js index 0295c3f..a35ade6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,6 +10,14 @@ module.exports = function(grunt) { }] } }, + copy: { + main: { + expand: true, + cwd: 'src', + src: 'locales/*', + dest: 'build' + } + }, watch: { scripts: { files: ['src/**/*.js'], @@ -20,6 +28,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-babel'); grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-copy'); grunt.registerTask('default', ['babel']); }; diff --git a/build/classes/interface.js b/build/classes/interface.js deleted file mode 100644 index 375b62e..0000000 --- a/build/classes/interface.js +++ /dev/null @@ -1,150 +0,0 @@ -'use strict'; - -var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _ansi = require('ansi'); - -var _ansi2 = _interopRequireDefault(_ansi); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var _process = process; -var stdout = _process.stdout; -var stdin = _process.stdin; - -var listeners = []; - -var prefix = '\u001b'; -var keys = { - right: prefix + '[C', - up: prefix + '[A', - left: prefix + '[D', - down: prefix + '[B', - exit: '\u0003', - space: ' ' -}; - -var Interface = (function () { - function Interface() { - var _this = this; - - var output = arguments.length <= 0 || arguments[0] === undefined ? stdout : arguments[0]; - var input = arguments.length <= 1 || arguments[1] === undefined ? stdin : arguments[1]; - - _classCallCheck(this, Interface); - - this.output = output; - this.input = input; - - this.input.setRawMode(true); - this.input.setEncoding('utf8'); - - this.cursor = (0, _ansi2.default)(this.output).hide(); - - this.input.addListener('data', function (data) { - var always = listeners.filter(function (listener) { - return listener.key === ''; - }); - - always.forEach(function (listener) { - return listener.fn(); - }); - - var key = Object.keys(keys).find(function (value, i) { - return keys[value] === data; - }); - - if (key === 'exit') { - _this.output.write('\u001b[2J\u001b[0;0H'); - process.exit(); - } - - var match = listeners.filter(function (listener) { - return listener.key === key || listener.key === data; - }); - - match.forEach(function (listener) { - return listener.fn(); - }); - }); - } - - _createClass(Interface, [{ - key: 'clear', - value: function clear() { - this.output.write('\u001b[2J\u001b[0;0H'); - } - }, { - key: 'write', - value: function write() { - var _cursor; - - (_cursor = this.cursor).write.apply(_cursor, arguments); - } - }, { - key: 'onKey', - value: function onKey(key, fn) { - if (typeof key === 'function') { - fn = key; - key = ''; - } - listeners.push({ key: key, fn: fn }); - } - }, { - key: 'line', - value: function line(from, to) { - var delta = { - x: to.x - from.x, - y: to.y - from.y - }; - - var error = 0; - - var deltaerr = Math.abs(delta.y / delta.x); - - var y = from.y; - - for (var x = from.x; x < to.x; x++) { - this.cursor.goto(x, y); - this.write('.'); - error += deltaerr; - - while (error >= 0.5) { - this.cursor.goto(x, y); - this.write('.'); - y += Math.sign(delta.y); - - error -= 1; - } - } - } - }, { - key: 'columns', - get: function get() { - return this.output.columns; - } - }, { - key: 'rows', - get: function get() { - return this.output.rows; - } - }, { - key: 'center', - get: function get() { - return { - x: this.output.columns / 2, - y: this.output.rows / 2 - }; - } - }]); - - return Interface; -})(); - -exports.default = Interface; diff --git a/build/classes/log b/build/classes/log deleted file mode 100644 index ae06f0c..0000000 --- a/build/classes/log +++ /dev/null @@ -1,5 +0,0 @@ -0(0) = 0,1 -45(0.7853981633974483) = 0.7071067811865475,0.7071067811865476 -112.5(1.9634954084936207) = 0.9238795325112867,-0.3826834323650897 -157.5(2.748893571891069) = 0.3826834323650899,-0.9238795325112867 -180(3.141592653589793) = 1.2246467991473532e-16,-1 diff --git a/build/classes/tank.js b/build/classes/tank.js deleted file mode 100644 index 6ff327d..0000000 --- a/build/classes/tank.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.Bullet = undefined; - -var _unit = require('./unit'); - -var _unit2 = _interopRequireDefault(_unit); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var BULLET_SPEED = 10; - -var Tank = (function (_Unit) { - _inherits(Tank, _Unit); - - function Tank(ui) { - _classCallCheck(this, Tank); - - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Tank).call(this, ui)); - - _this._angle = 0; - _this.bullets = []; - _this.health = 100; - - _this.size = { x: 5, y: 3 }; - return _this; - } - - _createClass(Tank, [{ - key: 'shoot', - value: function shoot() { - var bullet = new Bullet(this.output); - bullet.go(this.x + 2, this.y - 2); - bullet.velocity = this.normalize(); - - this.bullets.push(bullet); - } - }, { - key: 'draw', - value: function draw() { - if (this.dead) return; - - var x = this.x; - var y = this.y; - - if (this.color && this.color[0] === '#') { - this.output.cursor.hex(this.color); - } else if (this.color) { - this.output.cursor[this.color](); - } - if (this.bold) this.output.cursor.bold(); - - x = Math.round(x) + 2; - y = Math.round(y) - 2; - - var cannon = undefined; - if (this.angle < 35) cannon = '_';else if (this.angle < 70) cannon = '/';else if (this.angle < 115) cannon = '|';else if (this.angle < 160) cannon = '\\';else cannon = '_'; - - this.output.cursor.goto(x + 2, y - 2); - this.output.write(cannon); - this.output.cursor.goto(x, y - 1); - this.output.write('.===.'); - this.output.cursor.goto(x, y); - this.output.write('o===o'); - this.output.cursor.reset(); - } - }, { - key: 'normalize', - value: function normalize() { - return [Math.cos(this._angle), Math.sin(this._angle) * -1]; - } - }, { - key: 'angle', - set: function set(deg) { - if (deg < 0) deg = 0; - if (deg > 180) deg = 180; - - this._angle = _radian(deg); - }, - get: function get() { - return _degree(this._angle); - } - }], [{ - key: 'radian', - value: function radian(deg) { - return _radian(deg); - } - }, { - key: 'degree', - value: function degree(rad) { - return _degree(rad); - } - }]); - - return Tank; -})(_unit2.default); - -exports.default = Tank; - -var Bullet = exports.Bullet = (function (_Unit2) { - _inherits(Bullet, _Unit2); - - function Bullet(ui) { - _classCallCheck(this, Bullet); - - var _this2 = _possibleConstructorReturn(this, Object.getPrototypeOf(Bullet).call(this, ui)); - - _this2.velocity = [0, 0]; - - _this2.shape = '•'; - _this2.color = 'red'; - - _this2.dieOnExit = true; - - _this2.gravity = [0.8, 0.8]; - _this2.acceleration = [0, 0.015]; - return _this2; - } - - _createClass(Bullet, [{ - key: 'speed', - value: function speed() { - this.velocity[0] += this.acceleration[0]; - this.velocity[1] += this.acceleration[1]; - - var x = this.velocity[0] * this.gravity[0]; - var y = this.velocity[1] * this.gravity[1]; - return [x, y]; - } - }, { - key: 'collides', - value: function collides(target) { - var targetX = Math.round(target.x); - var targetY = Math.round(target.y); - var x = Math.round(this.x); - var y = Math.round(this.y); - - return x > targetX - target.size.x && x < targetX + target.size.x && y > targetY - target.size.y && y < targetY + target.size.y; - } - }]); - - return Bullet; -})(_unit2.default); - -function _radian(deg) { - return deg * Math.PI / 180; -} - -function _degree(rad) { - return rad * 180 / Math.PI; -} diff --git a/build/classes/unit.js b/build/classes/unit.js deleted file mode 100644 index 2728e25..0000000 --- a/build/classes/unit.js +++ /dev/null @@ -1,128 +0,0 @@ -'use strict'; - -var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Unit = (function () { - function Unit(output) { - _classCallCheck(this, Unit); - - this._health = 0; - this.dead = false; - this.output = output; - - this.dieOnExit = false; - } - - _createClass(Unit, [{ - key: 'move', - value: function move(x, y) { - if (!x && !y) return this.move.apply(this, _toConsumableArray(this.speed())); - this.x += x; - this.y += y; - } - }, { - key: 'draw', - value: function draw() { - if (this.dead) return; - - var x = this.x; - var y = this.y; - var shape = this.shape; - - if (this.color && this.color[0] === '#') { - this.output.cursor.hex(this.color); - } else if (this.color) { - this.output.cursor[this.color](); - } - if (this.bold) this.output.cursor.bold(); - - this.output.cursor.goto(Math.round(x), Math.round(y)); - this.output.write(shape); - this.output.cursor.reset(); - } - }, { - key: 'go', - value: function go(x, y) { - this.x = x; - this.y = y; - } - }, { - key: 'random', - value: function random() { - this.x = Math.max(1, Math.floor(Math.random() * this.output.columns)); - this.y = Math.max(1, Math.floor(Math.random() * this.output.rows)); - } - }, { - key: 'speed', - value: function speed() { - var signs = [Math.random() > 0.5 ? -1 : 1, Math.random() > 0.5 ? -1 : 1]; - return [Math.random() * signs[0], Math.random() * signs[1]]; - } - }, { - key: 'collides', - value: function collides(target) { - var _this = this; - - if (Array.isArray(target)) { - return target.find(function (t) { - return _this.collides(t); - }); - } - - var targetX = Math.round(target.x); - var targetY = Math.round(target.y); - var x = Math.round(this.x); - var y = Math.round(this.y); - - return x === targetX && y == targetY; - } - }, { - key: 'health', - set: function set(value) { - this._health = Math.max(0, value); - - if (this.health === 0) { - this.dead = true; - } - }, - get: function get() { - return this._health; - } - }, { - key: 'x', - set: function set(value) { - this._x = value; - - if (this.dieOnExit && this._x > this.output.columns) { - this.dead = true; - } - }, - get: function get() { - return this._x; - } - }, { - key: 'y', - set: function set(value) { - this._y = value; - - if (this.dieOnExit && this._y > this.output.rows) { - this.dead = true; - } - }, - get: function get() { - return this._y; - } - }]); - - return Unit; -})(); - -exports.default = Unit; diff --git a/build/log b/build/log deleted file mode 100644 index 3a9143c..0000000 --- a/build/log +++ /dev/null @@ -1,174 +0,0 @@ -0 (0) = 0,1 -45 (0.7853981633974483) = 0.7071067811865475,0.7071067811865476 -45 (0.7853981633974483) = 0.7071067811865475,0.7071067811865476 -90 (1.5707963267948966) = 1,6.123233995736766e-17 -135 (2.356194490192345) = 0.7071067811865476,-0.7071067811865475 -180 (3.141592653589793) = 1.2246467991473532e-16,-1 -0 (0) = 1,0 -45 (0.7853981633974483) = 0.7071067811865476,0.7071067811865475 -90 (1.5707963267948966) = 6.123233995736766e-17,1 -135 (2.356194490192345) = -0.7071067811865475,0.7071067811865476 -180 (3.141592653589793) = -1,1.2246467991473532e-16 -0 (0) = -1,0 -45 (0.7853981633974483) = -0.7071067811865476,-0.7071067811865475 -90 (1.5707963267948966) = -6.123233995736766e-17,-1 -0 (0) = 1,0 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -90 (1.5707963267948966) = 6.123233995736766e-17,-1 -135 (2.356194490192345) = -0.7071067811865475,-0.7071067811865476 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -0 (0) = 1,0 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -90 (1.5707963267948966) = 6.123233995736766e-17,-1 -135 (2.356194490192345) = -0.7071067811865475,-0.7071067811865476 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -112.5 (1.9634954084936207) = -0.3826834323650897,-0.9238795325112867 -112.5 (1.9634954084936207) = -0.3826834323650897,-0.9238795325112867 -112.5 (1.9634954084936207) = -0.3826834323650897,-0.9238795325112867 -90 (1.5707963267948966) = 6.123233995736766e-17,-1 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -22.5 (0.39269908169872414) = 0.9238795325112867,-0.3826834323650898 -22.5 (0.39269908169872414) = 0.9238795325112867,-0.3826834323650898 -45 (0.7853981633974483) = 0.7071067811865476,-0.7071067811865475 -0 (0) = 1,0 -22.5 (0.39269908169872414) = 0.9238795325112867,-0.3826834323650898 -53.999999999999964 (0.9424777960769373) = 0.5877852522924737,-0.809016994374947 -0 (0) = 1,0 -54.999999999999964 (0.9599310885968807) = 0.5735764363510466,-0.8191520442889915 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -32.99999999999997 (0.5759586531581282) = 0.8386705679454243,-0.5446390350150266 -170.00000000000003 (2.967059728390361) = -0.9848077530122081,-0.17364817766692983 -42.99999999999997 (0.7504915783575612) = 0.7313537016191709,-0.6819983600624981 -170.00000000000003 (2.967059728390361) = -0.9848077530122081,-0.17364817766692983 -42.99999999999997 (0.7504915783575612) = 0.7313537016191709,-0.6819983600624981 -170.00000000000003 (2.967059728390361) = -0.9848077530122081,-0.17364817766692983 -45.99999999999997 (0.802851455917391) = 0.6946583704589977,-0.7193398003386507 -170.00000000000003 (2.967059728390361) = -0.9848077530122081,-0.17364817766692983 -35 (0.6108652381980153) = 0.8191520442889918,-0.573576436351046 -49.99999999999997 (0.8726646259971643) = 0.6427876096865397,-0.7660444431189777 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -48.99999999999997 (0.8552113334772209) = 0.6560590289905077,-0.7547095802227716 -167.00000000000009 (2.914699850830532) = -0.9743700647852356,-0.22495105434386348 -46.999999999999964 (0.8203047484373343) = 0.6819983600624989,-0.73135370161917 -48.99999999999997 (0.8552113334772209) = 0.6560590289905077,-0.7547095802227716 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -45.999999999999986 (0.8028514559173914) = 0.6946583704589975,-0.7193398003386511 -162.00000000000009 (2.827433388230815) = -0.951056516295154,-0.3090169943749463 -20.999999999999986 (0.366519142918809) = 0.9335804264972019,-0.35836794954530005 -46.999999999999986 (0.8203047484373346) = 0.6819983600624987,-0.7313537016191702 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -26.999999999999993 (0.47123889803846886) = 0.8910065241883679,-0.4539904997395467 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -147 (2.5656340004316647) = -0.8386705679454242,-0.5446390350150269 -10.99999999999999 (0.19198621771937607) = 0.981627183447664,-0.19080899537654464 -48.99999999999998 (0.8552113334772211) = 0.6560590289905076,-0.7547095802227717 -10 (0.17453292519943295) = 0.984807753012208,-0.17364817766693033 -0 (0) = 1,0 -10 (0.17453292519943295) = 0.984807753012208,-0.17364817766693033 -0 (0) = 1,0 -10 (0.17453292519943295) = 0.984807753012208,-0.17364817766693033 -0 (0) = 1,0 -10 (0.17453292519943295) = 0.984807753012208,-0.17364817766693033 -0 (0) = 1,0 -10 (0.17453292519943295) = 0.984807753012208,-0.17364817766693033 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -49.99999999999997 (0.8726646259971643) = 0.6427876096865397,-0.7660444431189777 -19.999999999999986 (0.3490658503988657) = 0.9396926207859084,-0.3420201433256685 -0 (0) = 1,0 -19.999999999999986 (0.3490658503988657) = 0.9396926207859084,-0.3420201433256685 -0 (0) = 1,0 -19.999999999999986 (0.3490658503988657) = 0.9396926207859084,-0.3420201433256685 -0 (0) = 1,0 -0 (0) = 1,0 -0 (0) = 1,0 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -180 (3.141592653589793) = -1,-1.2246467991473532e-16 -0 (0) = 1,0 -0 (0) = 1,0 -47.99999999999998 (0.8377580409572778) = 0.6691306063588585,-0.743144825477394 -134.99999999999991 (2.3561944901923435) = -0.7071067811865466,-0.7071067811865486 diff --git a/build/snake.js b/build/snake.js deleted file mode 100644 index 4677856..0000000 --- a/build/snake.js +++ /dev/null @@ -1,184 +0,0 @@ -'use strict'; - -var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; })(); - -var _unit = require('./classes/unit'); - -var _unit2 = _interopRequireDefault(_unit); - -var _interface = require('./classes/interface'); - -var _interface2 = _interopRequireDefault(_interface); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var FRAME = 100; -var ui = new _interface2.default(); - -var snake = []; -var UP = 0; -var DOWN = 1; -var LEFT = 2; -var RIGHT = 3; -var head = createPart(); -head.color = '#71da29'; -head.dieOnExit = true; -createPart(); -createPart(); - -var point = new _unit2.default(ui); -point.shape = '+'; -point.color = '#f3ff6a'; -point.random(); - -var score = 0; - -var stop = false; -function loop() { - if (stop) return; - ui.clear(); - - point.draw(); - - snake.forEach(function (part, i) { - part.draw(); - - if (i > 0) part.findWay(i); - - part.move(); - }); - - if (head.collides(point)) { - point.random(); - createPart(); - score++; - - FRAME -= 5; - } - - if (head.collides(snake.slice(2))) { - gameover(); - } - - ui.cursor.goto(0, 0).yellow().write('Score: ' + score); - ui.cursor.reset(); - - setTimeout(loop, FRAME); -} - -loop(); - -ui.onKey('right', function () { - changeDirection(RIGHT); -}); -ui.onKey('down', function () { - changeDirection(DOWN); -}); -ui.onKey('up', function () { - changeDirection(UP); -}); -ui.onKey('left', function () { - changeDirection(LEFT); -}); - -ui.onKey(function () { - if (!stop) return; - - stop = false; - snake = []; - head = createPart(); - head.color = '#71da29'; - createPart(); - createPart(); - - score = 0; - - point.random(); - - loop(); -}); - -function changeDirection(dir) { - if (head.direction === UP && dir === DOWN || head.direction === DOWN && dir === UP || head.direction === LEFT && dir === RIGHT || head.direction === RIGHT && dir === LEFT) return; - head.direction = dir; -} - -function createPart() { - var part = new _unit2.default(ui); - var last = snake[snake.length - 1]; - - var direction = undefined; - if (!last) { - direction = UP; - } else { - direction = last.direction; - } - - part.shape = '•'; - part.color = '#bdfe91'; - part.direction = direction; - part.changeTo = null; - - part.findWay = function (i) { - var ahead = snake[i - 1]; - - if (this.changeTo !== null) { - this.direction = this.changeTo; - this.changeTo = null; - } - if (this.direction !== ahead.direction) { - this.changeTo = ahead.direction; - } - }; - - part.speed = function () { - var multiplier = arguments.length <= 0 || arguments[0] === undefined ? 1 : arguments[0]; - var direction = part.direction; - - var x = direction == LEFT ? -1 : direction == RIGHT ? 1 : 0; - var y = direction == UP ? -1 : direction == DOWN ? 1 : 0; - - return [x * multiplier, y * multiplier]; - }; - - var _part$speed = part.speed(); - - var _part$speed2 = _slicedToArray(_part$speed, 2); - - var dX = _part$speed2[0]; - var dY = _part$speed2[1]; - - dX *= -1; - dY *= -1; - - var x = last ? last.x + dX : ui.center.x; - var y = last ? last.y + dY : ui.center.y; - - part.go(x, y); - - snake.push(part); - return part; -} - -function gameover() { - var MSG = 'Game Over!'; - ui.cursor.goto(ui.center.x - MSG.length / 2, ui.center.y); - ui.cursor.red(); - ui.cursor.bold(); - ui.write(MSG); - - ui.cursor.reset(); - ui.cursor.hex('#f65590'); - var RETRY = 'Press any key to play again'; - ui.cursor.goto(ui.center.x - RETRY.length / 2, ui.center.y + 2); - ui.write(RETRY); - - FRAME = 100; - - stop = true; -} - -process.on('exit', function () { - ui.cursor.horizontalAbsolute(0).eraseLine(); - ui.cursor.show(); -}); diff --git a/build/spacecraft.js b/build/spacecraft.js deleted file mode 100644 index 02315a2..0000000 --- a/build/spacecraft.js +++ /dev/null @@ -1,124 +0,0 @@ -'use strict'; - -var _unit = require('./classes/unit'); - -var _unit2 = _interopRequireDefault(_unit); - -var _interface = require('./classes/interface'); - -var _interface2 = _interopRequireDefault(_interface); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var FRAME = 20; -var ENEMY_SPAWN_RATE = 1000; -var RELOAD_TIME = 200; - -var ui = new _interface2.default(); - -var player = new _unit2.default(ui); -player.go(1, ui.center.y); -player.shape = '=>'; -player.color = '#77d6ff'; -player.bold = true; -player.canShoot = true; - -var explosion = new _unit2.default(ui); -explosion.dead = true; - -var missles = []; -var enemies = []; -var score = 0; -setInterval(function () { - ui.clear(); - - player.draw(); - - missles.forEach(function (missle, i) { - missle.move(1, 0); - missle.draw(); - - var enemy = missle.collides(enemies); - if (enemy) { - enemy.killed = 1; - enemy.color = 'red'; - enemy.shape = '*'; - missle.dead = true; - - ENEMY_SPAWN_RATE -= 5; - - score++; - } - - if (missle.dead) { - missles.splice(i, 1); - } - }); - - enemies.forEach(function (enemy, i) { - // move with speed - enemy.move(); - enemy.draw(); - - if (enemy.dead) { - enemies.splice(i, 1); - } - - if (enemy.killed == 3) enemy.dead = true; - if (enemy.killed < 3) enemy.killed++; - }); - - ui.cursor.goto(0, 0).yellow().write('Score: ' + score); - ui.cursor.reset(); -}, FRAME); - -ui.onKey('right', function () { - player.move(1, 0); -}); -ui.onKey('down', function () { - player.move(0, 1); -}); -ui.onKey('up', function () { - player.move(0, -1); -}); -ui.onKey('left', function () { - player.move(-1, 0); -}); - -ui.onKey('space', function () { - if (!player.canShoot) return; - - player.canShoot = false; - - var missle = new _unit2.default(ui); - missle.go(player.x, player.y); - missle.shape = '+'; - missle.dieOnExit = true; - - missles.push(missle); - - setTimeout(function () { - player.canShoot = true; - }, RELOAD_TIME); -}); - -(function loop() { - var enemy = new _unit2.default(ui); - enemy.go(Math.random() * ui.output.columns, 0); - enemy.shape = 'o'; - enemy.color = '#f7c71e'; - enemy.dieOnExit = true; - - enemy.speed = function () { - return [Math.random() > 0.9 ? 0.4 : 0, 0.06]; - }; - - enemies.push(enemy); - - setTimeout(loop, ENEMY_SPAWN_RATE); -})(); - -process.on('exit', function () { - ui.cursor.horizontalAbsolute(0).eraseLine(); - ui.cursor.show(); -}); diff --git a/build/tanks.js b/build/tanks.js deleted file mode 100644 index 6eb279e..0000000 --- a/build/tanks.js +++ /dev/null @@ -1,156 +0,0 @@ -'use strict'; - -var _unit = require('./classes/unit'); - -var _unit2 = _interopRequireDefault(_unit); - -var _tank = require('./classes/tank'); - -var _tank2 = _interopRequireDefault(_tank); - -var _interface = require('./classes/interface'); - -var _interface2 = _interopRequireDefault(_interface); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var FRAME = 50; -var ui = new _interface2.default(); -var immoblize = false; - -var one = new _tank2.default(ui); -one.go(10, ui.rows); - -var two = new _tank2.default(ui); -two.go(ui.columns - 10, ui.rows); - -var stop = false; - -function loop() { - if (stop) return; - - ui.clear(); - - if (one.dead || two.dead) { - var num = one.dead ? '2' : '1'; - var msg = 'Player ' + num + ' won!'; - ui.cursor.red(); - ui.cursor.bold(); - - ui.cursor.goto(ui.center.x - msg.length / 2, ui.center.y); - ui.write(msg); - - stop = true; - return; - } - - one.draw(); - one.bullets.forEach(function (bullet, i) { - if (bullet.dead) { - immoblize = false; - one.bullets.splice(i, 1); - return; - } - bullet.move(); - bullet.draw(); - - if (bullet.collides(two)) { - two.health -= 10; - bullet.dead = true; - } - }); - - ui.cursor.goto(0, 1); - if (turn() === one) ui.cursor.hex('#54ffff'); - ui.write('Player 1'); - ui.cursor.reset(); - ui.cursor.goto(0, 2); - ui.write('Health: ' + one.health); - ui.cursor.goto(0, 3); - ui.write('Angle: ' + parseInt(one.angle)); - - two.draw(); - two.bullets.forEach(function (bullet, i) { - if (bullet.dead) { - immoblize = false; - two.bullets.splice(i, 1); - return; - } - bullet.move(); - bullet.draw(); - - if (bullet.collides(one)) { - one.health -= 10; - bullet.dead = true; - } - }); - - ui.cursor.goto(ui.output.columns - 10, 1); - if (turn() === two) ui.cursor.hex('#54ffff'); - ui.write('Player 2'); - ui.cursor.reset(); - ui.cursor.goto(ui.output.columns - 10, 2); - ui.write('Health: ' + two.health); - ui.cursor.goto(ui.output.columns - 10, 3); - ui.write('Angle: ' + parseInt(two.angle)); - - setTimeout(loop, FRAME); -} - -loop(); - -ui.onKey('down', function () { - if (immoblize) return; - - turn().angle -= 1; -}); - -ui.onKey('up', function () { - if (immoblize) return; - - turn().angle += 1; -}); - -ui.onKey('left', function () { - if (immoblize) return; - - turn().x -= 1; -}); - -ui.onKey('right', function () { - if (immoblize) return; - - turn().x += 1; -}); - -ui.onKey('space', function () { - if (immoblize) return; - - turn().shoot(); - - immoblize = true; - TURN = !TURN; -}); - -ui.onKey(function () { - if (one.dead || two.dead) { - one.go(10, ui.rows); - two.go(ui.columns - 10, ui.rows); - - one.health = 100; - two.health = 100; - - one.dead = false; - two.dead = false; - - stop = false; - - loop(); - } -}); - -var TURN = true; -function turn() { - if (TURN) return one; - return two; -} diff --git a/index.js b/index.js index 5ef109d..a7596ea 100755 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ #!/usr/bin/env node var game = process.argv[2]; +var language = process.argv[3]; if (!game) { console.log('usage: node-games '); @@ -14,4 +15,6 @@ if (!game) { require('babel-polyfill'); -require(__dirname + '/build/' + game); +const gameToPlay = require(__dirname + '/build/' + game).default; +gameToPlay(language); + diff --git a/package.json b/package.json index 1310f24..45aa3c1 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Simple node console games", "main": "index.js", "scripts": { + "build": "grunt && grunt copy", "test": "echo \"Error: no test specified\" && exit 1" }, "bin": "index.js", @@ -23,13 +24,16 @@ "homepage": "https://github.com/mdibaiee/node-games#readme", "dependencies": { "ansi": "0.3.0", - "babel-core": "6.3.17", + "babel-core": "^6.26.3", "babel-polyfill": "6.3.14", - "babel-preset-es2015": "6.3.13" + "babel-preset-es2015": "6.3.13", + "node-polyglot": "^2.3.0" }, "devDependencies": { "grunt": "0.4.5", "grunt-babel": "6.0.0", + "grunt-cli": "^1.3.2", + "grunt-contrib-copy": "^1.0.0", "grunt-contrib-watch": "0.6.1" } } diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 0000000..f3be16f --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,17 @@ +{ + "snake": { + "score": "Score", + "gameOver": "Game Over!", + "anyKey": "Press any key to play again" + }, + "tanks": { + "playerWon": "Player %{num} won!", + "player": "Player %{number}", + "health": "Health %{value}", + "angle": "Angle %{value}" + }, + "spacecraft": { + "score": "Score" + } +} + diff --git a/src/locales/es.json b/src/locales/es.json new file mode 100644 index 0000000..04d9a79 --- /dev/null +++ b/src/locales/es.json @@ -0,0 +1,16 @@ +{ + "snake": { + "score": "Puntaje", + "gameOver": "¡Se acabó el juego!", + "anyKey": "Presioná cualquier tecla para jugar nuevamente" + }, + "tanks": { + "playerWon": "¡Ha ganado el jugador %{name}!", + "player": "Jugador %{number}", + "health": "Salud %{value}", + "angle": "Ángulo %{value}" + }, + "spacecraft": { + "score": "Puntaje" + } +} diff --git a/src/snake.js b/src/snake.js index 94f48c8..f58e1d8 100644 --- a/src/snake.js +++ b/src/snake.js @@ -1,5 +1,6 @@ import Unit from './classes/unit'; import Interface from './classes/interface'; +import Polyglot from "node-polyglot"; let FRAME = 100; let ui = new Interface(); @@ -23,7 +24,7 @@ point.random(); let score = 0; let stop = false; -function loop() { +function loop(polyglot) { if (stop) return; ui.clear(); @@ -46,17 +47,15 @@ function loop() { } if (head.collides(snake.slice(2))) { - gameover(); + gameover(i18n); } - ui.cursor.goto(0, 0).yellow().write(`Score: ${score}`); + ui.cursor.goto(0, 0).yellow().write(`${i18n.t('snake.score')}: ${score}`); ui.cursor.reset(); - setTimeout(loop, FRAME); + setTimeout(loop, FRAME, i18n); } -loop(); - ui.onKey('right', () => { changeDirection(RIGHT); }); @@ -146,8 +145,8 @@ function createPart() { return part; } -function gameover() { - const MSG = 'Game Over!'; +function gameover(i18n) { + const MSG = i18n.t('snake.gameOver'); ui.cursor.goto(ui.center.x - MSG.length / 2, ui.center.y); ui.cursor.red(); ui.cursor.bold(); @@ -155,7 +154,7 @@ function gameover() { ui.cursor.reset(); ui.cursor.hex('#f65590'); - const RETRY = 'Press any key to play again'; + const RETRY = i18n.t('snake.anyKey'); ui.cursor.goto(ui.center.x - RETRY.length / 2, ui.center.y + 2); ui.write(RETRY); @@ -165,6 +164,14 @@ function gameover() { } process.on('exit', function() { - ui.cursor.horizontalAbsolute(0).eraseLine() + ui.cursor.horizontalAbsolute(0).eraseLine(); ui.cursor.show(); }); + +export default function(language) { + const locale = require(`${__dirname}/locales/${language || 'en'}.json`); + + const i18n = new Polyglot({phrases: locale}); + + loop(i18n); +} diff --git a/src/spacecraft.js b/src/spacecraft.js index 17203fa..546271e 100644 --- a/src/spacecraft.js +++ b/src/spacecraft.js @@ -1,5 +1,6 @@ import Unit from './classes/unit'; import Interface from './classes/interface'; +import Polyglot from "node-polyglot"; const FRAME = 20; let ENEMY_SPAWN_RATE = 1000; @@ -20,49 +21,55 @@ explosion.dead = true; let missles = []; let enemies = []; let score = 0; -setInterval(() => { - ui.clear(); - player.draw(); +export default function(language) { + const locale = require(`${__dirname}/locales/${language || 'en'}.json`); - missles.forEach((missle, i) => { - missle.move(1, 0); - missle.draw(); + const i18n = new Polyglot({phrases: locale}); - let enemy = missle.collides(enemies) - if (enemy) { - enemy.killed = 1; - enemy.color = 'red'; - enemy.shape = '*'; - missle.dead = true; + setInterval((i18n) => { + ui.clear(); - ENEMY_SPAWN_RATE -= 5; + player.draw(); - score++; - } + missles.forEach((missle, i) => { + missle.move(1, 0); + missle.draw(); - if (missle.dead) { - missles.splice(i, 1); - } - }); + let enemy = missle.collides(enemies); + if (enemy) { + enemy.killed = 1; + enemy.color = 'red'; + enemy.shape = '*'; + missle.dead = true; - enemies.forEach((enemy, i) => { - // move with speed - enemy.move(); - enemy.draw(); + ENEMY_SPAWN_RATE -= 5; - if (enemy.dead) { - enemies.splice(i, 1); - } + score++; + } - if (enemy.killed == 3) enemy.dead = true; - if (enemy.killed < 3) enemy.killed++; - }) + if (missle.dead) { + missles.splice(i, 1); + } + }); - ui.cursor.goto(0, 0).yellow().write(`Score: ${score}`); - ui.cursor.reset(); -}, FRAME); + enemies.forEach((enemy, i) => { + // move with speed + enemy.move(); + enemy.draw(); + if (enemy.dead) { + enemies.splice(i, 1); + } + + if (enemy.killed == 3) enemy.dead = true; + if (enemy.killed < 3) enemy.killed++; + }) + + ui.cursor.goto(0, 0).yellow().write(`${i18n.t('spacecraft.score')}: ${score}`); + ui.cursor.reset(); + }, FRAME, i18n); +} ui.onKey('right', () => { player.move(1, 0); diff --git a/src/tanks.js b/src/tanks.js index bb9c693..274e05d 100644 --- a/src/tanks.js +++ b/src/tanks.js @@ -1,6 +1,7 @@ import Unit from './classes/unit'; import Tank from './classes/tank'; import Interface from './classes/interface'; +import Polyglot from "node-polyglot"; let FRAME = 50; let ui = new Interface(); @@ -14,14 +15,14 @@ two.go(ui.columns - 10, ui.rows); let stop = false; -function loop() { +function loop(i18n) { if (stop) return; ui.clear(); if (one.dead || two.dead) { let num = one.dead ? '2' : '1'; - const msg = `Player ${num} won!`; + const msg = i18n.t('tanks.playerWon', {num: num}); ui.cursor.red(); ui.cursor.bold(); @@ -50,12 +51,12 @@ function loop() { ui.cursor.goto(0, 1); if (turn() === one) ui.cursor.hex('#54ffff'); - ui.write('Player 1'); + ui.write(i18n.t('tanks.player', {number: "1"})); ui.cursor.reset(); ui.cursor.goto(0, 2); - ui.write('Health: ' + one.health); + ui.write(i18n.t('tanks.health', {value: one.health})); ui.cursor.goto(0, 3); - ui.write('Angle: ' + parseInt(one.angle)); + ui.write(i18n.t('tanks.angle', {value: parseInt(one.angle)})); two.draw(); two.bullets.forEach((bullet, i) => { @@ -75,18 +76,16 @@ function loop() { ui.cursor.goto(ui.output.columns - 10, 1); if (turn() === two) ui.cursor.hex('#54ffff'); - ui.write('Player 2'); + ui.write(i18n.t('tanks.player', {number: "2"})); ui.cursor.reset(); ui.cursor.goto(ui.output.columns - 10, 2); - ui.write('Health: ' + two.health); + ui.write(i18n.t('tanks.health', {value: two.health})); ui.cursor.goto(ui.output.columns - 10, 3); - ui.write('Angle: ' + parseInt(two.angle)); + ui.write(i18n.t('tanks.angle', {value: parseInt(two.angle)})); - setTimeout(loop, FRAME); + setTimeout(loop, FRAME, i18n); } -loop(); - ui.onKey('down', () => { if (immoblize) return; @@ -142,3 +141,11 @@ function turn() { if (TURN) return one; return two; } + +export default function(language) { + const locale = require(`${__dirname}/locales/${language || 'en'}.json`); + + const i18n = new Polyglot({phrases: locale}); + + loop(i18n); +} -- 2.34.1 From 7582b76ee137ae241c81a170e2edc7a136ed9e47 Mon Sep 17 00:00:00 2001 From: Julian Calvento Date: Thu, 16 May 2019 14:35:42 -0300 Subject: [PATCH 2/4] Refactor to remove duplicated code and add translations to the root directory --- index.js | 7 +++- {src/locales => locales}/en.json | 0 {src/locales => locales}/es.json | 0 src/snake.js | 55 +++++++++++++++----------------- src/spacecraft.js | 15 +++------ src/tanks.js | 14 +++----- 6 files changed, 40 insertions(+), 51 deletions(-) rename {src/locales => locales}/en.json (100%) rename {src/locales => locales}/es.json (100%) diff --git a/index.js b/index.js index a7596ea..8c57fd8 100755 --- a/index.js +++ b/index.js @@ -16,5 +16,10 @@ if (!game) { require('babel-polyfill'); const gameToPlay = require(__dirname + '/build/' + game).default; -gameToPlay(language); + +const locale = require(`${__dirname}/locales/${language || 'en'}.json`); +const Polyglot = require('node-polyglot'); +const i18n = new Polyglot({phrases: locale}); + +gameToPlay(i18n); diff --git a/src/locales/en.json b/locales/en.json similarity index 100% rename from src/locales/en.json rename to locales/en.json diff --git a/src/locales/es.json b/locales/es.json similarity index 100% rename from src/locales/es.json rename to locales/es.json diff --git a/src/snake.js b/src/snake.js index f58e1d8..2356e7e 100644 --- a/src/snake.js +++ b/src/snake.js @@ -1,6 +1,5 @@ import Unit from './classes/unit'; import Interface from './classes/interface'; -import Polyglot from "node-polyglot"; let FRAME = 100; let ui = new Interface(); @@ -24,7 +23,7 @@ point.random(); let score = 0; let stop = false; -function loop(polyglot) { +function loop(i18n) { if (stop) return; ui.clear(); @@ -69,23 +68,6 @@ ui.onKey('left', () => { changeDirection(LEFT); }); -ui.onKey(() => { - if (!stop) return; - - stop = false; - snake = []; - head = createPart(); - head.color = '#71da29'; - createPart(); - createPart(); - - score = 0; - - point.random(); - - loop(); -}) - function changeDirection(dir) { if (head.direction === UP && dir === DOWN || head.direction === DOWN && dir === UP || @@ -120,17 +102,17 @@ function createPart() { if (this.direction !== ahead.direction) { this.changeTo = ahead.direction; } - } + }; part.speed = function(multiplier = 1) { let { direction } = part; - let x = direction == LEFT ? -1 : - direction == RIGHT ? 1 : 0; - let y = direction == UP ? -1 : - direction == DOWN ? 1 : 0; + let x = direction === LEFT ? -1 : + direction === RIGHT ? 1 : 0; + let y = direction === UP ? -1 : + direction === DOWN ? 1 : 0; return [x * multiplier, y * multiplier]; - } + }; let [dX, dY] = part.speed(); dX *= -1; @@ -168,10 +150,23 @@ process.on('exit', function() { ui.cursor.show(); }); -export default function(language) { - const locale = require(`${__dirname}/locales/${language || 'en'}.json`); - - const i18n = new Polyglot({phrases: locale}); - +export default function(i18n) { loop(i18n); + + ui.onKey(() => { + if (!stop) return; + + stop = false; + snake = []; + head = createPart(); + head.color = '#71da29'; + createPart(); + createPart(); + + score = 0; + + point.random(); + + loop(i18n); + }); } diff --git a/src/spacecraft.js b/src/spacecraft.js index 546271e..7ee812f 100644 --- a/src/spacecraft.js +++ b/src/spacecraft.js @@ -1,6 +1,5 @@ import Unit from './classes/unit'; import Interface from './classes/interface'; -import Polyglot from "node-polyglot"; const FRAME = 20; let ENEMY_SPAWN_RATE = 1000; @@ -22,11 +21,7 @@ let missles = []; let enemies = []; let score = 0; -export default function(language) { - const locale = require(`${__dirname}/locales/${language || 'en'}.json`); - - const i18n = new Polyglot({phrases: locale}); - +export default function(i18n) { setInterval((i18n) => { ui.clear(); @@ -62,9 +57,9 @@ export default function(language) { enemies.splice(i, 1); } - if (enemy.killed == 3) enemy.dead = true; + if (enemy.killed === 3) enemy.dead = true; if (enemy.killed < 3) enemy.killed++; - }) + }); ui.cursor.goto(0, 0).yellow().write(`${i18n.t('spacecraft.score')}: ${score}`); ui.cursor.reset(); @@ -110,7 +105,7 @@ ui.onKey('space', () => { enemy.speed = () => { return [Math.random() > 0.9 ? 0.4 : 0, 0.06]; - } + }; enemies.push(enemy); @@ -118,6 +113,6 @@ ui.onKey('space', () => { }()); process.on('exit', function() { - ui.cursor.horizontalAbsolute(0).eraseLine() + ui.cursor.horizontalAbsolute(0).eraseLine(); ui.cursor.show(); }); diff --git a/src/tanks.js b/src/tanks.js index 274e05d..73089be 100644 --- a/src/tanks.js +++ b/src/tanks.js @@ -1,7 +1,5 @@ -import Unit from './classes/unit'; import Tank from './classes/tank'; import Interface from './classes/interface'; -import Polyglot from "node-polyglot"; let FRAME = 50; let ui = new Interface(); @@ -90,13 +88,13 @@ ui.onKey('down', () => { if (immoblize) return; turn().angle -= 1; -}) +}); ui.onKey('up', () => { if (immoblize) return; turn().angle += 1; -}) +}); ui.onKey('left', () => { if (immoblize) return; @@ -134,7 +132,7 @@ ui.onKey(() => { loop(); } -}) +}); let TURN = true; function turn() { @@ -142,10 +140,6 @@ function turn() { return two; } -export default function(language) { - const locale = require(`${__dirname}/locales/${language || 'en'}.json`); - - const i18n = new Polyglot({phrases: locale}); - +export default function(i18n) { loop(i18n); } -- 2.34.1 From 90bde04df80b2518e86669203ee610610eb5655a Mon Sep 17 00:00:00 2001 From: Julian Calvento Date: Thu, 16 May 2019 15:17:58 -0300 Subject: [PATCH 3/4] Add scrips to play easily and translate readme with GIFs --- README.es.md | 34 ++++++++++++++++++++++++++++++++++ README.md | 10 ++++++++++ package.json | 1 + snake-es.gif | Bin 0 -> 44943 bytes spacecraft-es.gif | Bin 0 -> 64505 bytes tanks-es.gif | Bin 0 -> 39118 bytes 6 files changed, 45 insertions(+) create mode 100644 README.es.md create mode 100644 snake-es.gif create mode 100644 spacecraft-es.gif create mode 100644 tanks-es.gif diff --git a/README.es.md b/README.es.md new file mode 100644 index 0000000..bc27d7a --- /dev/null +++ b/README.es.md @@ -0,0 +1,34 @@ +node-games +========== + +[English Version](README.md) + +Algunos juegos de consola escritos en Node. + +``` +npm i -g node-games + +node-games +``` + +Sin instalar el juego globalmente: +``` +npm start + +Ejemplo: +npm start snake es + +(Si no se especifica el lenguage, por defecto se usa inglés) +``` + +spacecraft +---------- +![spacecraft](spacecraft-es.gif) + +snake +----- +![snake](snake-es.gif) + +tanks +----- +![tanks](tanks-es.gif) diff --git a/README.md b/README.md index 34f75f0..f65d85c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ node-games ========== +[Version en español](README.es.md) + Some fun console games written using Node. ``` @@ -9,6 +11,14 @@ npm i -g node-games node-games ``` +Without installing node-games globally: +``` +npm start +npm start snake es + +(English will be default language if none is given) +``` + spacecraft ---------- ![spacecraft](https://raw.githubusercontent.com/mdibaiee/node-games/master/spacecraft.gif) diff --git a/package.json b/package.json index 45aa3c1..92086d3 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "build": "grunt && grunt copy", + "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "bin": "index.js", diff --git a/snake-es.gif b/snake-es.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d9c723d0b3ca2ee2034ea197ca8984d95e3fbfd GIT binary patch literal 44943 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 literal 0 HcmV?d00001 diff --git a/spacecraft-es.gif b/spacecraft-es.gif new file mode 100644 index 0000000000000000000000000000000000000000..3d1ce7e7802fdfcaf940b4b0ab4b17da20df5320 GIT binary patch literal 64505 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 CBSnW_K9AXsSF~HK9cLO{}&9sPtTA)=91MIYbIw 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 a{|yP~zJF5!`X4ip?dycE9|M;yI{yJTB(q-t literal 0 HcmV?d00001 diff --git a/tanks-es.gif b/tanks-es.gif new file mode 100644 index 0000000000000000000000000000000000000000..bfbfaaa6d424a98bfe28c30807e0b8f7554a52d7 GIT binary patch literal 39118 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 P$Mlwx Date: Thu, 16 May 2019 15:18:59 -0300 Subject: [PATCH 4/4] Add latest version of build --- build/classes/interface.js | 152 ++++++++++++++++++++++++++++++ build/classes/tank.js | 162 ++++++++++++++++++++++++++++++++ build/classes/unit.js | 128 +++++++++++++++++++++++++ build/locales/en.json | 17 ++++ build/locales/es.json | 16 ++++ build/snake.js | 188 +++++++++++++++++++++++++++++++++++++ build/spacecraft.js | 131 ++++++++++++++++++++++++++ build/tanks.js | 158 +++++++++++++++++++++++++++++++ 8 files changed, 952 insertions(+) create mode 100644 build/classes/interface.js create mode 100644 build/classes/tank.js create mode 100644 build/classes/unit.js create mode 100644 build/locales/en.json create mode 100644 build/locales/es.json create mode 100644 build/snake.js create mode 100644 build/spacecraft.js create mode 100644 build/tanks.js diff --git a/build/classes/interface.js b/build/classes/interface.js new file mode 100644 index 0000000..9dbdb7a --- /dev/null +++ b/build/classes/interface.js @@ -0,0 +1,152 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _ansi = require('ansi'); + +var _ansi2 = _interopRequireDefault(_ansi); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _process = process, + stdout = _process.stdout, + stdin = _process.stdin; + + +var listeners = []; + +var prefix = '\x1B'; +var keys = { + right: prefix + '[C', + up: prefix + '[A', + left: prefix + '[D', + down: prefix + '[B', + exit: '\x03', + space: ' ' +}; + +var Interface = function () { + function Interface() { + var _this = this; + + var output = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : stdout; + var input = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : stdin; + + _classCallCheck(this, Interface); + + this.output = output; + this.input = input; + + this.input.setRawMode(true); + this.input.setEncoding('utf8'); + + this.cursor = (0, _ansi2.default)(this.output).hide(); + + this.input.addListener('data', function (data) { + var always = listeners.filter(function (listener) { + return listener.key === ''; + }); + + always.forEach(function (listener) { + return listener.fn(); + }); + + var key = Object.keys(keys).find(function (value, i) { + return keys[value] === data; + }); + + if (key === 'exit') { + _this.output.write('\x1B[2J\x1B[0;0H'); + process.exit(); + } + + var match = listeners.filter(function (listener) { + return listener.key === key || listener.key === data; + }); + + match.forEach(function (listener) { + return listener.fn(); + }); + }); + } + + _createClass(Interface, [{ + key: 'clear', + value: function clear() { + this.output.write('\x1B[2J\x1B[0;0H'); + } + }, { + key: 'write', + value: function write() { + var _cursor; + + (_cursor = this.cursor).write.apply(_cursor, arguments); + } + }, { + key: 'onKey', + value: function onKey(key, fn) { + if (typeof key === 'function') { + fn = key; + key = ''; + } + listeners.push({ key: key, fn: fn }); + } + }, { + key: 'line', + value: function line(from, to) { + var delta = { + x: to.x - from.x, + y: to.y - from.y + }; + + var error = 0; + + var deltaerr = Math.abs(delta.y / delta.x); + + var y = from.y; + + + for (var x = from.x; x < to.x; x++) { + this.cursor.goto(x, y); + this.write('.'); + error += deltaerr; + + while (error >= 0.5) { + this.cursor.goto(x, y); + this.write('.'); + y += Math.sign(delta.y); + + error -= 1; + } + } + } + }, { + key: 'columns', + get: function get() { + return this.output.columns; + } + }, { + key: 'rows', + get: function get() { + return this.output.rows; + } + }, { + key: 'center', + get: function get() { + return { + x: this.output.columns / 2, + y: this.output.rows / 2 + }; + } + }]); + + return Interface; +}(); + +exports.default = Interface; diff --git a/build/classes/tank.js b/build/classes/tank.js new file mode 100644 index 0000000..9a7e3c9 --- /dev/null +++ b/build/classes/tank.js @@ -0,0 +1,162 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Bullet = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _unit = require('./unit'); + +var _unit2 = _interopRequireDefault(_unit); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var BULLET_SPEED = 10; + +var Tank = function (_Unit) { + _inherits(Tank, _Unit); + + function Tank(ui) { + _classCallCheck(this, Tank); + + var _this = _possibleConstructorReturn(this, (Tank.__proto__ || Object.getPrototypeOf(Tank)).call(this, ui)); + + _this._angle = 0; + _this.bullets = []; + _this.health = 100; + + _this.size = { x: 5, y: 3 }; + return _this; + } + + _createClass(Tank, [{ + key: 'shoot', + value: function shoot() { + var bullet = new Bullet(this.output); + bullet.go(this.x + 2, this.y - 2); + bullet.velocity = this.normalize(); + + this.bullets.push(bullet); + } + }, { + key: 'draw', + value: function draw() { + if (this.dead) return; + + var x = this.x, + y = this.y; + + if (this.color && this.color[0] === '#') { + this.output.cursor.hex(this.color); + } else if (this.color) { + this.output.cursor[this.color](); + } + if (this.bold) this.output.cursor.bold(); + + x = Math.round(x) + 2; + y = Math.round(y) - 2; + + var cannon = void 0; + if (this.angle < 35) cannon = '_';else if (this.angle < 70) cannon = '/';else if (this.angle < 115) cannon = '|';else if (this.angle < 160) cannon = '\\';else cannon = '_'; + + this.output.cursor.goto(x + 2, y - 2); + this.output.write(cannon); + this.output.cursor.goto(x, y - 1); + this.output.write('.===.'); + this.output.cursor.goto(x, y); + this.output.write('o===o'); + this.output.cursor.reset(); + } + }, { + key: 'normalize', + value: function normalize() { + return [Math.cos(this._angle), Math.sin(this._angle) * -1]; + } + }, { + key: 'angle', + set: function set(deg) { + if (deg < 0) deg = 0; + if (deg > 180) deg = 180; + + this._angle = _radian(deg); + }, + get: function get() { + return _degree(this._angle); + } + }], [{ + key: 'radian', + value: function radian(deg) { + return _radian(deg); + } + }, { + key: 'degree', + value: function degree(rad) { + return _degree(rad); + } + }]); + + return Tank; +}(_unit2.default); + +exports.default = Tank; + +var Bullet = exports.Bullet = function (_Unit2) { + _inherits(Bullet, _Unit2); + + function Bullet(ui) { + _classCallCheck(this, Bullet); + + var _this2 = _possibleConstructorReturn(this, (Bullet.__proto__ || Object.getPrototypeOf(Bullet)).call(this, ui)); + + _this2.velocity = [0, 0]; + + _this2.shape = '•'; + _this2.color = 'red'; + + _this2.dieOnExit = true; + + _this2.gravity = [0.8, 0.8]; + _this2.acceleration = [0, 0.015]; + return _this2; + } + + _createClass(Bullet, [{ + key: 'speed', + value: function speed() { + this.velocity[0] += this.acceleration[0]; + this.velocity[1] += this.acceleration[1]; + + var x = this.velocity[0] * this.gravity[0]; + var y = this.velocity[1] * this.gravity[1]; + return [x, y]; + } + }, { + key: 'collides', + value: function collides(target) { + var targetX = Math.round(target.x); + var targetY = Math.round(target.y); + var x = Math.round(this.x); + var y = Math.round(this.y); + + return x > targetX - target.size.x && x < targetX + target.size.x && y > targetY - target.size.y && y < targetY + target.size.y; + } + }]); + + return Bullet; +}(_unit2.default); + +function _radian(deg) { + return deg * Math.PI / 180; +} + +function _degree(rad) { + return rad * 180 / Math.PI; +} diff --git a/build/classes/unit.js b/build/classes/unit.js new file mode 100644 index 0000000..a72f4bc --- /dev/null +++ b/build/classes/unit.js @@ -0,0 +1,128 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Unit = function () { + function Unit(output) { + _classCallCheck(this, Unit); + + this._health = 0; + this.dead = false; + this.output = output; + + this.dieOnExit = false; + } + + _createClass(Unit, [{ + key: 'move', + value: function move(x, y) { + if (!x && !y) return this.move.apply(this, _toConsumableArray(this.speed())); + this.x += x; + this.y += y; + } + }, { + key: 'draw', + value: function draw() { + if (this.dead) return; + + var x = this.x, + y = this.y, + shape = this.shape; + + if (this.color && this.color[0] === '#') { + this.output.cursor.hex(this.color); + } else if (this.color) { + this.output.cursor[this.color](); + } + if (this.bold) this.output.cursor.bold(); + + this.output.cursor.goto(Math.round(x), Math.round(y)); + this.output.write(shape); + this.output.cursor.reset(); + } + }, { + key: 'go', + value: function go(x, y) { + this.x = x; + this.y = y; + } + }, { + key: 'random', + value: function random() { + this.x = Math.max(1, Math.floor(Math.random() * this.output.columns)); + this.y = Math.max(1, Math.floor(Math.random() * this.output.rows)); + } + }, { + key: 'speed', + value: function speed() { + var signs = [Math.random() > 0.5 ? -1 : 1, Math.random() > 0.5 ? -1 : 1]; + return [Math.random() * signs[0], Math.random() * signs[1]]; + } + }, { + key: 'collides', + value: function collides(target) { + var _this = this; + + if (Array.isArray(target)) { + return target.find(function (t) { + return _this.collides(t); + }); + } + + var targetX = Math.round(target.x); + var targetY = Math.round(target.y); + var x = Math.round(this.x); + var y = Math.round(this.y); + + return x === targetX && y == targetY; + } + }, { + key: 'health', + set: function set(value) { + this._health = Math.max(0, value); + + if (this.health === 0) { + this.dead = true; + } + }, + get: function get() { + return this._health; + } + }, { + key: 'x', + set: function set(value) { + this._x = value; + + if (this.dieOnExit && this._x > this.output.columns) { + this.dead = true; + } + }, + get: function get() { + return this._x; + } + }, { + key: 'y', + set: function set(value) { + this._y = value; + + if (this.dieOnExit && this._y > this.output.rows) { + this.dead = true; + } + }, + get: function get() { + return this._y; + } + }]); + + return Unit; +}(); + +exports.default = Unit; diff --git a/build/locales/en.json b/build/locales/en.json new file mode 100644 index 0000000..f3be16f --- /dev/null +++ b/build/locales/en.json @@ -0,0 +1,17 @@ +{ + "snake": { + "score": "Score", + "gameOver": "Game Over!", + "anyKey": "Press any key to play again" + }, + "tanks": { + "playerWon": "Player %{num} won!", + "player": "Player %{number}", + "health": "Health %{value}", + "angle": "Angle %{value}" + }, + "spacecraft": { + "score": "Score" + } +} + diff --git a/build/locales/es.json b/build/locales/es.json new file mode 100644 index 0000000..04d9a79 --- /dev/null +++ b/build/locales/es.json @@ -0,0 +1,16 @@ +{ + "snake": { + "score": "Puntaje", + "gameOver": "¡Se acabó el juego!", + "anyKey": "Presioná cualquier tecla para jugar nuevamente" + }, + "tanks": { + "playerWon": "¡Ha ganado el jugador %{name}!", + "player": "Jugador %{number}", + "health": "Salud %{value}", + "angle": "Ángulo %{value}" + }, + "spacecraft": { + "score": "Puntaje" + } +} diff --git a/build/snake.js b/build/snake.js new file mode 100644 index 0000000..f0f119c --- /dev/null +++ b/build/snake.js @@ -0,0 +1,188 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +exports.default = function (i18n) { + loop(i18n); + + ui.onKey(function () { + if (!stop) return; + + stop = false; + snake = []; + head = createPart(); + head.color = '#71da29'; + createPart(); + createPart(); + + score = 0; + + point.random(); + + loop(i18n); + }); +}; + +var _unit = require('./classes/unit'); + +var _unit2 = _interopRequireDefault(_unit); + +var _interface = require('./classes/interface'); + +var _interface2 = _interopRequireDefault(_interface); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var FRAME = 100; +var ui = new _interface2.default(); + +var snake = []; +var UP = 0; +var DOWN = 1; +var LEFT = 2; +var RIGHT = 3; +var head = createPart(); +head.color = '#71da29'; +head.dieOnExit = true; +createPart(); +createPart(); + +var point = new _unit2.default(ui); +point.shape = '+'; +point.color = '#f3ff6a'; +point.random(); + +var score = 0; + +var stop = false; +function loop(i18n) { + if (stop) return; + ui.clear(); + + point.draw(); + + snake.forEach(function (part, i) { + part.draw(); + + if (i > 0) part.findWay(i); + + part.move(); + }); + + if (head.collides(point)) { + point.random(); + createPart(); + score++; + + FRAME -= 5; + } + + if (head.collides(snake.slice(2))) { + gameover(i18n); + } + + ui.cursor.goto(0, 0).yellow().write(i18n.t('snake.score') + ': ' + score); + ui.cursor.reset(); + + setTimeout(loop, FRAME, i18n); +} + +ui.onKey('right', function () { + changeDirection(RIGHT); +}); +ui.onKey('down', function () { + changeDirection(DOWN); +}); +ui.onKey('up', function () { + changeDirection(UP); +}); +ui.onKey('left', function () { + changeDirection(LEFT); +}); + +function changeDirection(dir) { + if (head.direction === UP && dir === DOWN || head.direction === DOWN && dir === UP || head.direction === LEFT && dir === RIGHT || head.direction === RIGHT && dir === LEFT) return; + head.direction = dir; +} + +function createPart() { + var part = new _unit2.default(ui); + var last = snake[snake.length - 1]; + + var direction = void 0; + if (!last) { + direction = UP; + } else { + direction = last.direction; + } + + part.shape = '•'; + part.color = '#bdfe91'; + part.direction = direction; + part.changeTo = null; + + part.findWay = function (i) { + var ahead = snake[i - 1]; + + if (this.changeTo !== null) { + this.direction = this.changeTo; + this.changeTo = null; + } + if (this.direction !== ahead.direction) { + this.changeTo = ahead.direction; + } + }; + + part.speed = function () { + var multiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + var direction = part.direction; + + var x = direction === LEFT ? -1 : direction === RIGHT ? 1 : 0; + var y = direction === UP ? -1 : direction === DOWN ? 1 : 0; + + return [x * multiplier, y * multiplier]; + }; + + var _part$speed = part.speed(), + _part$speed2 = _slicedToArray(_part$speed, 2), + dX = _part$speed2[0], + dY = _part$speed2[1]; + + dX *= -1; + dY *= -1; + + var x = last ? last.x + dX : ui.center.x; + var y = last ? last.y + dY : ui.center.y; + + part.go(x, y); + + snake.push(part); + return part; +} + +function gameover(i18n) { + var MSG = i18n.t('snake.gameOver'); + ui.cursor.goto(ui.center.x - MSG.length / 2, ui.center.y); + ui.cursor.red(); + ui.cursor.bold(); + ui.write(MSG); + + ui.cursor.reset(); + ui.cursor.hex('#f65590'); + var RETRY = i18n.t('snake.anyKey'); + ui.cursor.goto(ui.center.x - RETRY.length / 2, ui.center.y + 2); + ui.write(RETRY); + + FRAME = 100; + + stop = true; +} + +process.on('exit', function () { + ui.cursor.horizontalAbsolute(0).eraseLine(); + ui.cursor.show(); +}); diff --git a/build/spacecraft.js b/build/spacecraft.js new file mode 100644 index 0000000..fdad993 --- /dev/null +++ b/build/spacecraft.js @@ -0,0 +1,131 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (i18n) { + setInterval(function (i18n) { + ui.clear(); + + player.draw(); + + missles.forEach(function (missle, i) { + missle.move(1, 0); + missle.draw(); + + var enemy = missle.collides(enemies); + if (enemy) { + enemy.killed = 1; + enemy.color = 'red'; + enemy.shape = '*'; + missle.dead = true; + + ENEMY_SPAWN_RATE -= 5; + + score++; + } + + if (missle.dead) { + missles.splice(i, 1); + } + }); + + enemies.forEach(function (enemy, i) { + // move with speed + enemy.move(); + enemy.draw(); + + if (enemy.dead) { + enemies.splice(i, 1); + } + + if (enemy.killed === 3) enemy.dead = true; + if (enemy.killed < 3) enemy.killed++; + }); + + ui.cursor.goto(0, 0).yellow().write(i18n.t('spacecraft.score') + ': ' + score); + ui.cursor.reset(); + }, FRAME, i18n); +}; + +var _unit = require('./classes/unit'); + +var _unit2 = _interopRequireDefault(_unit); + +var _interface = require('./classes/interface'); + +var _interface2 = _interopRequireDefault(_interface); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var FRAME = 20; +var ENEMY_SPAWN_RATE = 1000; +var RELOAD_TIME = 200; + +var ui = new _interface2.default(); + +var player = new _unit2.default(ui); +player.go(1, ui.center.y); +player.shape = '=>'; +player.color = '#77d6ff'; +player.bold = true; +player.canShoot = true; + +var explosion = new _unit2.default(ui); +explosion.dead = true; + +var missles = []; +var enemies = []; +var score = 0; + +ui.onKey('right', function () { + player.move(1, 0); +}); +ui.onKey('down', function () { + player.move(0, 1); +}); +ui.onKey('up', function () { + player.move(0, -1); +}); +ui.onKey('left', function () { + player.move(-1, 0); +}); + +ui.onKey('space', function () { + if (!player.canShoot) return; + + player.canShoot = false; + + var missle = new _unit2.default(ui); + missle.go(player.x, player.y); + missle.shape = '+'; + missle.dieOnExit = true; + + missles.push(missle); + + setTimeout(function () { + player.canShoot = true; + }, RELOAD_TIME); +}); + +(function loop() { + var enemy = new _unit2.default(ui); + enemy.go(Math.random() * ui.output.columns, 0); + enemy.shape = 'o'; + enemy.color = '#f7c71e'; + enemy.dieOnExit = true; + + enemy.speed = function () { + return [Math.random() > 0.9 ? 0.4 : 0, 0.06]; + }; + + enemies.push(enemy); + + setTimeout(loop, ENEMY_SPAWN_RATE); +})(); + +process.on('exit', function () { + ui.cursor.horizontalAbsolute(0).eraseLine(); + ui.cursor.show(); +}); diff --git a/build/tanks.js b/build/tanks.js new file mode 100644 index 0000000..e19a3a5 --- /dev/null +++ b/build/tanks.js @@ -0,0 +1,158 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function (i18n) { + loop(i18n); +}; + +var _tank = require('./classes/tank'); + +var _tank2 = _interopRequireDefault(_tank); + +var _interface = require('./classes/interface'); + +var _interface2 = _interopRequireDefault(_interface); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var FRAME = 50; +var ui = new _interface2.default(); +var immoblize = false; + +var one = new _tank2.default(ui); +one.go(10, ui.rows); + +var two = new _tank2.default(ui); +two.go(ui.columns - 10, ui.rows); + +var stop = false; + +function loop(i18n) { + if (stop) return; + + ui.clear(); + + if (one.dead || two.dead) { + var num = one.dead ? '2' : '1'; + var msg = i18n.t('tanks.playerWon', { num: num }); + ui.cursor.red(); + ui.cursor.bold(); + + ui.cursor.goto(ui.center.x - msg.length / 2, ui.center.y); + ui.write(msg); + + stop = true; + return; + } + + one.draw(); + one.bullets.forEach(function (bullet, i) { + if (bullet.dead) { + immoblize = false; + one.bullets.splice(i, 1); + return; + } + bullet.move(); + bullet.draw(); + + if (bullet.collides(two)) { + two.health -= 10; + bullet.dead = true; + } + }); + + ui.cursor.goto(0, 1); + if (turn() === one) ui.cursor.hex('#54ffff'); + ui.write(i18n.t('tanks.player', { number: "1" })); + ui.cursor.reset(); + ui.cursor.goto(0, 2); + ui.write(i18n.t('tanks.health', { value: one.health })); + ui.cursor.goto(0, 3); + ui.write(i18n.t('tanks.angle', { value: parseInt(one.angle) })); + + two.draw(); + two.bullets.forEach(function (bullet, i) { + if (bullet.dead) { + immoblize = false; + two.bullets.splice(i, 1); + return; + } + bullet.move(); + bullet.draw(); + + if (bullet.collides(one)) { + one.health -= 10; + bullet.dead = true; + } + }); + + ui.cursor.goto(ui.output.columns - 10, 1); + if (turn() === two) ui.cursor.hex('#54ffff'); + ui.write(i18n.t('tanks.player', { number: "2" })); + ui.cursor.reset(); + ui.cursor.goto(ui.output.columns - 10, 2); + ui.write(i18n.t('tanks.health', { value: two.health })); + ui.cursor.goto(ui.output.columns - 10, 3); + ui.write(i18n.t('tanks.angle', { value: parseInt(two.angle) })); + + setTimeout(loop, FRAME, i18n); +} + +ui.onKey('down', function () { + if (immoblize) return; + + turn().angle -= 1; +}); + +ui.onKey('up', function () { + if (immoblize) return; + + turn().angle += 1; +}); + +ui.onKey('left', function () { + if (immoblize) return; + + turn().x -= 1; +}); + +ui.onKey('right', function () { + if (immoblize) return; + + turn().x += 1; +}); + +ui.onKey('space', function () { + if (immoblize) return; + + turn().shoot(); + + immoblize = true; + TURN = !TURN; +}); + +ui.onKey(function () { + if (one.dead || two.dead) { + one.go(10, ui.rows); + two.go(ui.columns - 10, ui.rows); + + one.health = 100; + two.health = 100; + + one.dead = false; + two.dead = false; + + stop = false; + + loop(); + } +}); + +var TURN = true; +function turn() { + if (TURN) return one; + return two; +} -- 2.34.1