diff --git a/.gitignore b/.gitignore index 1fe7a25..ae67e4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -node_modules/ -virtual/js/build/ +node_modules/ +virtual/js/build/ +npm-debug.log diff --git a/package.json b/package.json index d2238b9..99b4a1b 100755 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --progress --colors --optimize-minimize", + "build:watch": "webpack --progress --colors --optimize-minimize --watch", "start": "babel-node test", "lint": "eslint --fix --ignore-path ./.eslintignore js/ test/ gulpfile.js webpack.config.js" }, diff --git a/test.js b/test.js index 4aaec74..b7bedb5 100644 --- a/test.js +++ b/test.js @@ -2,6 +2,7 @@ import keypress from "keypress"; import VirtualSphero from "./main"; const virtualSphero = new VirtualSphero(8081, "*"); +let virtualSpheroSpeed = 100; // キーにテストする内容を割り当てる const testKeys = { @@ -18,7 +19,7 @@ const testKeys = { }, b: function() { console.log("add sphero"); - virtualSphero.addSphero(`Sphero${new Date().getTime()}`); + virtualSphero.addSphero(`Sphero${+new Date() + Math.floor(Math.random() * 1000)}`); }, d: function() { console.log("remove sphero"); @@ -38,8 +39,11 @@ keypress(process.stdin); process.stdin.on("keypress", function(ch, key) { if (key && typeof testKeys[key.name] !== "undefined") { - if (Array.isArray(testKeys[key.name])) { - const args = testKeys[key.name]; + if (key && key.shift && (key.name === "up" || key.name === "down")) { + addSpeed(key.name === "up" ? 1 : -1); + console.log(`${key.name} speed: ${virtualSpheroSpeed}`); + } else if (Array.isArray(testKeys[key.name])) { + const args = getArgs(testKeys[key.name], key.name); console.log(`orb.${args[0]}(${args.slice(1).map(arg => "\"" + arg + "\"").join(", ")});`); commandAll(args[0], args.slice(1)); } else if (typeof testKeys[key.name] === "function") { @@ -59,5 +63,16 @@ function commandAll(commandName, args) { }); } +function addSpeed(speed) { + virtualSpheroSpeed = Math.max(0, Math.min(255, virtualSpheroSpeed + speed)); +} + +function getArgs(array, keyName) { + if (keyName !== "space") { + array.splice(1, 1, virtualSpheroSpeed); + } + return array; +} + process.stdin.setRawMode(true); process.stdin.resume(); diff --git a/virtual/index.html b/virtual/index.html index 8bb9545..bf005dd 100644 --- a/virtual/index.html +++ b/virtual/index.html @@ -2,16 +2,11 @@ - + Virtual Sphero -

Virtual Sphero

- - - + diff --git a/virtual/js/canvasManager.js b/virtual/js/canvasManager.js new file mode 100644 index 0000000..03f74d6 --- /dev/null +++ b/virtual/js/canvasManager.js @@ -0,0 +1,23 @@ +import eventPublisher from "./publisher"; + +export default class CanvasManager { + constructor() { + this.canvas = document.getElementById("canvas"); + this.ctx = this.canvas.getContext("2d"); + this.canvas.width = window.innerWidth; + this.canvas.height = window.innerHeight; + + eventPublisher.subscribe("clearCanvas", () => { + this.clearCanvas(); + }); + } + + resizeCanvas() { + this.canvas.width = window.innerWidth; + this.canvas.height = window.innerHeight; + } + + clearCanvas() { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } +} diff --git a/virtual/js/main.js b/virtual/js/main.js index 084d512..83adf03 100644 --- a/virtual/js/main.js +++ b/virtual/js/main.js @@ -1,12 +1,15 @@ -import VirtualSpheroController from "./virtual-sphero-controller"; +import VirtualSpheroManager from "./virtual-sphero-manager"; +import CanvasManager from "./canvasManager"; +import SocketManager from "./socketManager"; import "../css/style.css"; document.addEventListener("DOMContentLoaded", function() { - const sphero = new VirtualSpheroController(); + const sphero = new VirtualSpheroManager(); + const socket = new SocketManager(); + const canvas = new CanvasManager(); window.addEventListener("resize", function() { - sphero.resizeCanvas(); - sphero.clearCanvas(); - sphero.fixSpherosPosition(); + canvas.resizeCanvas(); + canvas.clearCanvas(); }); }); diff --git a/virtual/js/publisher.js b/virtual/js/publisher.js new file mode 100644 index 0000000..44d884d --- /dev/null +++ b/virtual/js/publisher.js @@ -0,0 +1,38 @@ +// Publisherは、データを保存せず、外部へ変更を知らせる機能に絞る。 + +class Publisher { + constructor() { + this.modelObservers = {}; + this.observers = {}; + } + subscribe(type, observer) { + if (typeof this.observers[type] === "undefined") { + this.observers[type] = []; + } + this.observers[type].push(observer); + } + publish(type, ...nextDatas) { + if (type.indexOf(":") !== -1) { + throw new Error("publishのtypeに「:」を含むことはできません。"); + } + if (typeof this.observers[type] === "undefined") { + this.observers[type] = []; + } + if (typeof this.modelObservers[type] === "undefined") { + this.modelObservers[type] = []; + } + this.modelObservers[type].forEach(observer => { + observer.apply(null, nextDatas); + }); + this.observers[type].forEach(observer => { + observer.apply(null, nextDatas); + }); + if (typeof this.observers[type + ":after"] !== "undefined") { + this.observers[type + ":after"].forEach(observer => { + observer.apply(null, nextDatas); + }); + } + } +} + +export default new Publisher(); diff --git a/virtual/js/socketManager.js b/virtual/js/socketManager.js new file mode 100644 index 0000000..5b836ae --- /dev/null +++ b/virtual/js/socketManager.js @@ -0,0 +1,29 @@ +import eventPublisher from "./publisher"; + +export default class SocketManager { + constructor() { + this.socket = io(); + + this.socket.on("connect", () => { + eventPublisher.publish("needShowSpheros"); + }); + + this.socket.on("addVirtualSphero", spheroName => { + eventPublisher.publish("addVirtualSphero", spheroName); + }); + + this.socket.on("removeVirtualSphero", spheroName => { + eventPublisher.publish("removeVirtualSphero", spheroName); + }); + + this.socket.on("command", (spheroName, commandName, args) => { + eventPublisher.publish("command", spheroName, commandName, args); + }); + + eventPublisher.subscribe("sendShowSpheros", showSpheros => { + this.socket.emit("request", { + showSpheros: showSpheros + }); + }); + } +} diff --git a/virtual/js/speed-controller.js b/virtual/js/speed-controller.js deleted file mode 100755 index f0ccb63..0000000 --- a/virtual/js/speed-controller.js +++ /dev/null @@ -1,12 +0,0 @@ -export default class SpeedController { - constructor() { - this._element = document.getElementById("speed"); - this.speed = 0.2; - this._element.value = this.speed; - this._element.addEventListener("change", () => { - if (this._element.value !== "" && !isNaN(this._element.value)) { - this.speed = parseFloat(this._element.value); - } - }); - } -} diff --git a/virtual/js/virtual-sphero-controller.js b/virtual/js/virtual-sphero-manager.js old mode 100755 new mode 100644 similarity index 75% rename from virtual/js/virtual-sphero-controller.js rename to virtual/js/virtual-sphero-manager.js index 8b48e30..3b7e777 --- a/virtual/js/virtual-sphero-controller.js +++ b/virtual/js/virtual-sphero-manager.js @@ -1,28 +1,25 @@ -import VirtualSphero from "./virtual-sphero"; -import SpeedController from "./speed-controller"; +import virtualSphero from "./virtual-sphero"; +import eventPublisher from "./publisher"; import { Engine, Render, World, Body, Bodies } from "matter-js"; -export default class VirtualSpheroController { +export default class VirtualSpheroManager { constructor() { const showParam = getParams().show; this.showSpheros = typeof showParam === "undefined" ? null : showParam.split(","); - this.socket = io(); - this.socket.on("connect", () => { - this.socket.emit("request", { - showSpheros: this.showSpheros - }); + eventPublisher.subscribe("needShowSpheros", () => { + eventPublisher.publish("sendShowSpheros", this.showSpheros); }); - this.socket.on("addVirtualSphero", spheroName => { + eventPublisher.subscribe("addVirtualSphero", spheroName => { this.addVirtualSphero(spheroName); }); - this.socket.on("removeVirtualSphero", spheroName => { + eventPublisher.subscribe("removeVirtualSphero", spheroName => { this.removeVirtualSphero(spheroName); }); - this.socket.on("command", (spheroName, commandName, args) => { + eventPublisher.subscribe("command", (spheroName, commandName, args) => { const virtualSphero = this.virtualSpheros[spheroName]; if (typeof virtualSphero !== "undefined" && typeof virtualSphero[commandName] !== "undefined") { @@ -30,19 +27,14 @@ export default class VirtualSpheroController { } }); - this.speedController = new SpeedController(); - this.engine = Engine.create(); this.engine.world.gravity.y = 0; Engine.run(this.engine); this.canvas = document.getElementById("canvas"); - this.ctx = this.canvas.getContext("2d"); - this.canvas.width = window.innerWidth; - this.canvas.height = window.innerHeight; const tick = () => { - this.clearCanvas(); + eventPublisher.publish("clearCanvas"); Object.keys(this.virtualSpheros).forEach(spheroName => { this.virtualSpheros[spheroName].move(); this.virtualSpheros[spheroName].draw(); @@ -53,17 +45,8 @@ export default class VirtualSpheroController { this.virtualSpheros = {}; } - resizeCanvas() { - this.canvas.width = window.innerWidth; - this.canvas.height = window.innerHeight; - } - - clearCanvas() { - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - } - addVirtualSphero(spheroName) { - this.virtualSpheros[spheroName] = new VirtualSphero(this.canvas, this.speedController, spheroName); + this.virtualSpheros[spheroName] = new virtualSphero(this.canvas, spheroName); World.add(this.engine.world, this.virtualSpheros[spheroName].body); } @@ -74,7 +57,6 @@ export default class VirtualSpheroController { } const commands = [ - /* sphero.js */ "setHeading", "setStabilization", @@ -133,7 +115,6 @@ const commands = [ "answerInput", "commitToFlash", "commitToFlashAlias", - /* custom.js */ "streamData", "color", diff --git a/virtual/js/virtual-sphero.js b/virtual/js/virtual-sphero.js index 563e83d..99473fa 100755 --- a/virtual/js/virtual-sphero.js +++ b/virtual/js/virtual-sphero.js @@ -1,23 +1,18 @@ import { Body, Bodies } from "matter-js"; -export default class VirtualSphero { - constructor(canvas, speedController, spheroName) { - this.speedController = speedController; +export default class virtualSphero { + constructor(canvas, spheroName) { this.canvas = canvas; this.spheroName = spheroName; this.ex = 0; this.ey = 0; this.radius = 25; - this.direction = 0; + this.degree = 0; this.body = Bodies.circle(1, 1, this.radius, { friction: 0.1 }); - this.body.restitution = 0; - - this.width = this.canvas.width; - this.height = this.canvas.height; this.ctx = this.canvas.getContext("2d"); this.fillColor = "white"; @@ -30,15 +25,15 @@ export default class VirtualSphero { }; } - roll(far, degree) { + roll(speed, degree) { this.rotate(degree); - const direction = (degree + 270) % 360; - this.ex = Math.cos(direction * Math.PI / 180) * far * 0.1; - this.ey = Math.sin(direction * Math.PI / 180) * far * 0.1; + const rollDegree = (this.degree + 270) % 360; + this.ex = Math.cos(rollDegree * Math.PI / 180) * speed * 0.1; + this.ey = Math.sin(rollDegree * Math.PI / 180) * speed * 0.1; } rotate(degree) { - this.direction = degree; + this.degree = degree; } color(color) { @@ -50,10 +45,7 @@ export default class VirtualSphero { } move() { - Body.setPosition(this.body, { - x: this.body.position.x + this.ex, - y: this.body.position.y + this.ey - }); + this.setPosition(this.body.position.x + this.ex, this.body.position.y + this.ey); this.fixPosition(); } @@ -68,7 +60,7 @@ export default class VirtualSphero { this.ctx.fill(); this.ctx.stroke(); - const rad = this.direction * Math.PI / 180; + const rad = this.degree * Math.PI / 180; this.ctx.save(); this.ctx.setTransform(Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), this.body.position.x, this.body.position.y); this.ctx.translate(-this.radius + 10, -this.radius + 10); @@ -77,8 +69,8 @@ export default class VirtualSphero { } fixPosition() { - this.setPosition(this.getValueInRange(this.width - this.radius, this.radius, this.body.position.x), - this.getValueInRange(this.height - this.radius, this.radius, this.body.position.y)); + this.setPosition(this.getValueInRange(this.canvas.width - this.radius, this.radius, this.body.position.x), + this.getValueInRange(this.canvas.height - this.radius, this.radius, this.body.position.y)); } setPosition(x, y) {