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 0000000..d6e3a1b Binary files /dev/null and b/tanks.gif differ