From 4830e50375442434b924f2b3fb4becdd924017bf Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Fri, 11 Dec 2015 17:47:45 +0330 Subject: [PATCH] chore: add spacecraft image --- README.md | 8 ++++ classes/interface.js | 55 +++++++++++++++++++++++ classes/unit.js | 91 ++++++++++++++++++++++++++++++++++++++ spacecraft.js | 103 +++++++++++++++++++++++++++++++++++++++++++ spacecraft.png | Bin 0 -> 36519 bytes 5 files changed, 257 insertions(+) create mode 100644 README.md create mode 100644 classes/interface.js create mode 100644 classes/unit.js create mode 100644 spacecraft.js create mode 100644 spacecraft.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..dac0c59 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +node-games +========== + +Some fun console games written using Node. + +spacecraft +---------- +![spacecraft](https://raw.githubusercontent.com/mdibaiee/node-games/master/spacecraft.png) diff --git a/classes/interface.js b/classes/interface.js new file mode 100644 index 0000000..92cb0c8 --- /dev/null +++ b/classes/interface.js @@ -0,0 +1,55 @@ +import ansi from 'ansi'; +const { stdout, stdin } = process; + +let listeners = []; + +const prefix = '\u001b'; +const keys = { + right: `${prefix}[C`, + up: `${prefix}[A`, + left: `${prefix}[D`, + down: `${prefix}[B`, + exit: '\u0003', + space: ' ' +} + +export default class Interface { + constructor(output = stdout, input = stdin) { + this.output = output; + this.input = input; + + this.input.setRawMode(true); + this.input.setEncoding('utf8'); + + this.cursor = ansi(this.output).hide(); + + this.columns = this.output.columns; + this.rows = this.output.rows; + + this.input.addListener('data', data => { + let key = Object.keys(keys).find((value, i) => { + return keys[value] === data; + }); + + if ( key === 'exit' ) process.exit(); + + let match = listeners.filter(listener => { + return listener.key === key || listener.key === data; + }); + + match.forEach(listener => listener.fn()); + }) + } + + clear() { + this.output.write('\u001b[2J\u001b[0;0H'); + } + + write(...args) { + this.cursor.write(...args); + } + + onKey(key, fn) { + listeners.push({ key, fn }); + } +} diff --git a/classes/unit.js b/classes/unit.js new file mode 100644 index 0000000..31fdb66 --- /dev/null +++ b/classes/unit.js @@ -0,0 +1,91 @@ +export default class Unit { + constructor(output) { + this._health = 0; + this.dead = false; + this.output = output; + + this.dieOnExit = false; + } + + set health(value) { + this._health = Math.min(0, value); + + if (this.health === 0) { + this.dead = true; + } + } + + get health() { + return this._health; + } + + set x(value) { + this._x = value; + + if (this.dieOnExit && this._x > this.output.columns) { + this.dead = true; + } + } + + get x() { + return this._x; + } + + set y(value) { + this._y = value; + + if (this.dieOnExit && this._y > this.output.rows) { + this.dead = true; + } + } + + get y() { + return this._y; + } + + move(x, y) { + if (!x && !y) return this.move(...this.speed()); + this.x += x; + this.y += y; + } + + draw() { + if (this.dead) return; + + let { x, y, shape } = 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(); + + + this.output.cursor.goto(Math.round(x), Math.round(y)); + this.output.write(shape); + this.output.cursor.reset(); + } + + go(x, y) { + this.x = x; + this.y = y; + } + + speed() { + let signs = [Math.random() > 0.5 ? -1 : 1, Math.random() > 0.5 ? -1 : 1]; + return [Math.random() * signs[0], Math.random() * signs[1]]; + } + + collides(target) { + if (Array.isArray(target)) { + return target.find(t => this.collides(t)); + } + + 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 && y == targetY; + } +} diff --git a/spacecraft.js b/spacecraft.js new file mode 100644 index 0000000..bc1ab2c --- /dev/null +++ b/spacecraft.js @@ -0,0 +1,103 @@ +import Unit from './classes/unit'; +import Interface from './classes/interface'; + +const FRAME = 20; +const ENEMY_SPAWN_RATE = 400; + +let ui = new Interface(); + +let player = new Unit(ui); +player.go(1, ui.output.rows / 2); +player.shape = '=>'; +player.color = '#77d6ff'; +player.bold = true; + +let explosion = new Unit(ui); +explosion.dead = true; + +let missles = []; +let enemies = []; +let score = 0; +setInterval(() => { + ui.clear(); + + player.draw(); + + missles.forEach((missle, i) => { + missle.move(1, 0); + missle.draw(); + + let enemy = missle.collides(enemies) + if (enemy) { + enemy.killed = 1; + enemy.color = 'red'; + enemy.shape = '*'; + missle.dead = true; + + score++; + } + + if (missle.dead) { + missles.splice(i, 1); + } + }); + + 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(`Score: ${score}`); + ui.cursor.reset(); +}, FRAME); + + +ui.onKey('right', () => { + player.move(1, 0); +}); +ui.onKey('down', () => { + player.move(0, 1); +}); +ui.onKey('up', () => { + player.move(0, -1); +}); +ui.onKey('left', () => { + player.move(-1, 0); +}); +ui.onKey('space', () => { + let missle = new Unit(ui); + missle.go(player.x, player.y); + missle.shape = '+'; + missle.dieOnExit = true; + + missles.push(missle); +}); + +setInterval(() => { + if (enemies.length > 5) return; + + let enemy = new Unit(ui); + enemy.go(Math.random() * ui.output.columns, 0); + enemy.shape = 'o'; + enemy.color = '#f7c71e'; + enemy.dieOnExit = true; + + enemy.speed = () => { + return [Math.random() > 0.9 ? 0.4 : 0, 0.06]; + } + + enemies.push(enemy); +}, 1000); + +process.on('exit', function() { + ui.cursor.horizontalAbsolute(0).eraseLine() + ui.cursor.show(); +}); diff --git a/spacecraft.png b/spacecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..a007b1e486dd748a738480df1de2d3e136db56d7 GIT binary patch literal 36519 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 F{ud&s4`ToT literal 0 HcmV?d00001