From bccbd7acfe9f245856a47dcd47eb2a91c32c4e31 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Fri, 18 Dec 2015 16:25:26 +0330 Subject: [PATCH] feat(tanks): tanks game! --- README.md | 4 + build/classes/interface.js | 28 ++++++ build/classes/log | 5 ++ build/classes/tank.js | 176 +++++++++++++++++++++++++++++++++++++ build/classes/unit.js | 2 +- build/log | 174 ++++++++++++++++++++++++++++++++++++ build/snake.js | 4 - build/tanks.js | 156 ++++++++++++++++++++++++++++++++ package.json | 2 +- src/classes/interface.js | 27 ++++++ src/classes/tank.js | 127 ++++++++++++++++++++++++++ src/classes/unit.js | 2 +- src/snake.js | 1 - src/tanks.js | 144 ++++++++++++++++++++++++++++++ tanks.gif | Bin 0 -> 69937 bytes 15 files changed, 844 insertions(+), 8 deletions(-) create mode 100644 build/classes/log create mode 100644 build/classes/tank.js create mode 100644 build/tanks.js create mode 100644 src/classes/tank.js create mode 100644 src/tanks.js create mode 100644 tanks.gif diff --git a/README.md b/README.md index 570c415..34f75f0 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,7 @@ spacecraft snake ----- ![snake](https://raw.githubusercontent.com/mdibaiee/node-games/master/snake.gif) + +tanks +----- +![tanks](https://raw.githubusercontent.com/mdibaiee/node-games/master/tanks.gif) diff --git a/build/classes/interface.js b/build/classes/interface.js index 7baddb8..e7d44e9 100644 --- a/build/classes/interface.js +++ b/build/classes/interface.js @@ -91,6 +91,34 @@ var Interface = (function () { } 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() { diff --git a/build/classes/log b/build/classes/log new file mode 100644 index 0000000..ae06f0c --- /dev/null +++ b/build/classes/log @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..999e86d --- /dev/null +++ b/build/classes/tank.js @@ -0,0 +1,176 @@ +'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); + +var _fs = require('fs'); + +var _fs2 = _interopRequireDefault(_fs); + +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 log = function log() { + for (var _len = arguments.length, strings = Array(_len), _key = 0; _key < _len; _key++) { + strings[_key] = arguments[_key]; + } + + _fs2.default.appendFileSync(__dirname + '/../log', strings.join(' ') + '\n'); +}; + +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(); + + log(this.angle, '(' + this._angle + ') =', bullet.velocity.join(',')); + + 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 index 777f077..2728e25 100644 --- a/build/classes/unit.js +++ b/build/classes/unit.js @@ -87,7 +87,7 @@ var Unit = (function () { }, { key: 'health', set: function set(value) { - this._health = Math.min(0, value); + this._health = Math.max(0, value); if (this.health === 0) { this.dead = true; diff --git a/build/log b/build/log index e69de29..3a9143c 100644 --- a/build/log +++ b/build/log @@ -0,0 +1,174 @@ +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 index 60a7d74..4677856 100644 --- a/build/snake.js +++ b/build/snake.js @@ -10,10 +10,6 @@ var _interface = require('./classes/interface'); var _interface2 = _interopRequireDefault(_interface); -var _fs = require('fs'); - -var _fs2 = _interopRequireDefault(_fs); - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var FRAME = 100; diff --git a/build/tanks.js b/build/tanks.js new file mode 100644 index 0000000..6eb279e --- /dev/null +++ b/build/tanks.js @@ -0,0 +1,156 @@ +'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/package.json b/package.json index e2ffd06..562fc9e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-games", - "version": "2.1.0", + "version": "3.0.0", "description": "Simple node console games", "main": "index.js", "scripts": { diff --git a/src/classes/interface.js b/src/classes/interface.js index 4052876..b8f33fc 100644 --- a/src/classes/interface.js +++ b/src/classes/interface.js @@ -74,4 +74,31 @@ export default class Interface { y: this.output.rows / 2 } } + + line(from, to) { + let delta = { + x: to.x - from.x, + y: to.y - from.y + } + + let error = 0; + + let deltaerr = Math.abs(delta.y / delta.x); + + let { y } = from; + + for (let 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; + } + } + } } diff --git a/src/classes/tank.js b/src/classes/tank.js new file mode 100644 index 0000000..e642300 --- /dev/null +++ b/src/classes/tank.js @@ -0,0 +1,127 @@ +import Unit from './unit'; +import fs from 'fs'; + +let log = (...strings) => { + fs.appendFileSync(__dirname + '/../log', strings.join(' ') + '\n'); +} + +const BULLET_SPEED = 10; + +export default class Tank extends Unit { + constructor(ui) { + super(ui); + + this._angle = 0; + this.bullets = []; + this.health = 100; + + this.size = { x: 5, y: 3 }; + } + + set angle(deg) { + if (deg < 0) deg = 0; + if (deg > 180) deg = 180; + + this._angle = radian(deg); + } + + get angle() { + return degree(this._angle); + } + + shoot() { + let bullet = new Bullet(this.output); + bullet.go(this.x + 2, this.y - 2); + bullet.velocity = this.normalize(); + + log(this.angle, '(' + this._angle + ') =', bullet.velocity.join(',')); + + this.bullets.push(bullet); + } + + draw() { + if (this.dead) return; + + let { x, y } = this; + 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; + + let cannon; + 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(); + } + + normalize() { + return [Math.cos(this._angle), Math.sin(this._angle) * -1]; + } + + static radian(deg) { + return radian(deg); + } + + static degree(rad) { + return degree(rad); + } +} + +export class Bullet extends Unit { + constructor(ui) { + super(ui); + + this.velocity = [0, 0]; + + this.shape = '•'; + this.color = 'red'; + + this.dieOnExit = true; + + this.gravity = [0.8, 0.8]; + this.acceleration = [0, 0.015]; + } + + speed() { + this.velocity[0] += this.acceleration[0]; + this.velocity[1] += this.acceleration[1]; + + let x = this.velocity[0] * this.gravity[0]; + let y = this.velocity[1] * this.gravity[1]; + return [x, y]; + } + + collides(target) { + let targetX = Math.round(target.x); + let targetY = Math.round(target.y); + let x = Math.round(this.x); + let 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; + } +} + +function radian(deg) { + return deg * Math.PI / 180; +} + +function degree(rad) { + return rad * 180 / Math.PI; +} diff --git a/src/classes/unit.js b/src/classes/unit.js index bdbb8ab..ecafbe1 100644 --- a/src/classes/unit.js +++ b/src/classes/unit.js @@ -8,7 +8,7 @@ export default class Unit { } set health(value) { - this._health = Math.min(0, value); + this._health = Math.max(0, value); if (this.health === 0) { this.dead = true; diff --git a/src/snake.js b/src/snake.js index 1226e8d..94f48c8 100644 --- a/src/snake.js +++ b/src/snake.js @@ -1,6 +1,5 @@ import Unit from './classes/unit'; import Interface from './classes/interface'; -import fs from 'fs'; let FRAME = 100; let ui = new Interface(); diff --git a/src/tanks.js b/src/tanks.js new file mode 100644 index 0000000..bb9c693 --- /dev/null +++ b/src/tanks.js @@ -0,0 +1,144 @@ +import Unit from './classes/unit'; +import Tank from './classes/tank'; +import Interface from './classes/interface'; + +let FRAME = 50; +let ui = new Interface(); +let immoblize = false; + +let one = new Tank(ui); +one.go(10, ui.rows); + +let two = new Tank(ui); +two.go(ui.columns - 10, ui.rows); + +let stop = false; + +function loop() { + if (stop) return; + + ui.clear(); + + if (one.dead || two.dead) { + let num = one.dead ? '2' : '1'; + const 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((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((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', () => { + if (immoblize) return; + + turn().angle -= 1; +}) + +ui.onKey('up', () => { + if (immoblize) return; + + turn().angle += 1; +}) + +ui.onKey('left', () => { + if (immoblize) return; + + turn().x -= 1; +}); + +ui.onKey('right', () => { + if (immoblize) return; + + turn().x += 1; +}); + +ui.onKey('space', () => { + if (immoblize) return; + + turn().shoot(); + + immoblize = true; + TURN = !TURN; +}); + +ui.onKey(() => { + 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(); + } +}) + +let TURN = true; +function turn() { + if (TURN) return one; + return two; +} diff --git a/tanks.gif b/tanks.gif new file mode 100644 index 0000000000000000000000000000000000000000..d6e3a1b757df5b366023e0238484898852f9a566 GIT binary patch literal 69937 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 literal 0 HcmV?d00001