From ba524f28fa6d418440308e4ca7adb41ed6595cc2 Mon Sep 17 00:00:00 2001 From: Thibault Neveu Date: Fri, 8 Jun 2018 15:02:39 +0100 Subject: [PATCH] Add event API + level1 --- demo/dist/metacar.min.js | 22 +- demo/webapp/{index.html => full_city.html} | 0 demo/webapp/level1.html | 18 ++ demo/webapp/public/js/level1.js | 28 ++ dist/metacar.min.js | 22 +- src/basic_motion_engine.ts | 12 +- src/embedded.ts | 7 +- src/embedded/level/level_1.ts | 316 +++++++++++++++++++++ src/level.ts | 17 +- src/metacar.ts | 139 ++++++++- src/utils.ts | 16 +- 11 files changed, 557 insertions(+), 40 deletions(-) rename demo/webapp/{index.html => full_city.html} (100%) create mode 100644 demo/webapp/level1.html create mode 100644 demo/webapp/public/js/level1.js create mode 100644 src/embedded/level/level_1.ts diff --git a/demo/dist/metacar.min.js b/demo/dist/metacar.min.js index c8a11f2..d3df358 100644 --- a/demo/dist/metacar.min.js +++ b/demo/dist/metacar.min.js @@ -155,7 +155,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedUrl\", function() { return embeddedUrl; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedContent\", function() { return embeddedContent; });\n/* harmony import */ var _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded/level/full_city */ \"./src/embedded/level/full_city.ts\");\n\nvar embeddedUrl = {\n fullCity: \"embedded://level/fullCity\"\n};\nvar embeddedContent = {\n level: {\n fullCity: _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__[\"fullCity\"]\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedUrl\", function() { return embeddedUrl; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedContent\", function() { return embeddedContent; });\n/* harmony import */ var _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded/level/full_city */ \"./src/embedded/level/full_city.ts\");\n/* harmony import */ var _embedded_level_level_1__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./embedded/level/level_1 */ \"./src/embedded/level/level_1.ts\");\n\n\nvar embeddedUrl = {\n fullCity: \"embedded://level/fullCity\",\n level1: \"embedded://level/level1\"\n};\nvar embeddedContent = {\n level: {\n fullCity: _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__[\"fullCity\"],\n level1: _embedded_level_level_1__WEBPACK_IMPORTED_MODULE_1__[\"level1\"]\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded.ts?"); /***/ }), @@ -171,6 +171,18 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ }), +/***/ "./src/embedded/level/level_1.ts": +/*!***************************************!*\ + !*** ./src/embedded/level/level_1.ts ***! + \***************************************/ +/*! exports provided: level1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"level1\", function() { return level1; });\nvar level1 = {\n \"cars\": [\n {\n \"mx\": 5,\n \"my\": 3,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 5,\n \"my\": 3,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 5,\n \"my\": 1,\n \"line\": 0,\n \"auto\": true\n }\n ],\n \"tree\": [\n {\n \"x\": 120,\n \"y\": 50\n },\n {\n \"x\": 86.5,\n \"y\": 85\n },\n {\n \"x\": 94.5,\n \"y\": 135\n },\n {\n \"x\": 30.5,\n \"y\": 128\n },\n {\n \"x\": 72.5,\n \"y\": 190\n },\n {\n \"x\": 23.5,\n \"y\": 232\n },\n {\n \"x\": 110.5,\n \"y\": 242\n },\n {\n \"x\": 43.5,\n \"y\": 33\n },\n {\n \"x\": 18.5,\n \"y\": 178\n },\n {\n \"x\": 305.5,\n \"y\": 125\n },\n {\n \"x\": 360.5,\n \"y\": 122\n }\n ],\n \"asset\": [\n {\n \"x\": 252.5,\n \"y\": 142\n },\n {\n \"x\": 86.5,\n \"y\": 85\n },\n {\n \"x\": 94.5,\n \"y\": 135\n },\n {\n \"x\": 30.5,\n \"y\": 128\n },\n {\n \"x\": 252.5,\n \"y\": 26\n },\n {\n \"x\": 195.5,\n \"y\": 0\n },\n {\n \"x\": 307.5,\n \"y\": 1\n },\n {\n \"x\": 72.5,\n \"y\": 190\n },\n {\n \"x\": 23.5,\n \"y\": 232\n },\n {\n \"x\": 110.5,\n \"y\": 242\n },\n {\n \"x\": 43.5,\n \"y\": 33\n },\n {\n \"x\": 35.5,\n \"y\": 185\n },\n {\n \"x\": 18.5,\n \"y\": 178\n },\n {\n \"x\": 289.5,\n \"y\": 126\n },\n {\n \"x\": 337.5,\n \"y\": 126\n },\n {\n \"x\": 305.5,\n \"y\": 125\n },\n {\n \"x\": 360.5,\n \"y\": 122\n },\n {\n \"x\": 492.5,\n \"y\": 56\n },\n {\n \"x\": 503.5,\n \"y\": 136\n },\n {\n \"x\": 504.5,\n \"y\": 58\n }\n ],\n \"bench\": [\n {\n \"x\": 252.5,\n \"y\": 142\n },\n {\n \"x\": 252.5,\n \"y\": 26\n }\n ],\n \"road\": [\n {\n \"x\": 240,\n \"y\": 60\n },\n {\n \"x\": 240,\n \"y\": 60\n },\n {\n \"x\": 480,\n \"y\": 0\n },\n {\n \"x\": 480,\n \"y\": 60\n },\n {\n \"x\": 480,\n \"y\": 120\n },\n {\n \"x\": 480,\n \"y\": 180\n },\n {\n \"x\": 480,\n \"y\": 240\n },\n {\n \"x\": 300,\n \"y\": 180\n },\n {\n \"x\": 300,\n \"y\": 180\n },\n {\n \"x\": 360,\n \"y\": 180\n },\n {\n \"x\": 420,\n \"y\": 180\n },\n {\n \"x\": 420,\n \"y\": 120\n },\n {\n \"x\": 420,\n \"y\": 60\n },\n {\n \"x\": 360,\n \"y\": 60\n },\n {\n \"x\": 300,\n \"y\": 60\n },\n {\n \"x\": 420,\n \"y\": 120\n }\n ],\n \"house3\": [\n {\n \"x\": 503.5,\n \"y\": 136\n }\n ],\n \"house\": [\n {\n \"x\": 504.5,\n \"y\": 58\n }\n ],\n \"map\": [\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n \"↱\",\n \"↠\",\n \"↔\",\n \"↔\",\n \"↰\",\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n \"↟\",\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n \"↳\",\n \"↔\",\n \"↔\",\n \"↔\",\n \"↲\",\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ]\n ],\n \"agent\": {\n \"mx\": 4,\n \"my\": 3,\n \"line\": 0,\n \"motion\": {\n \"type\": \"BasicMotionEngine\",\n \"options\": {\n \"rotationStep\": 0.5,\n \"actions\": [\n \"UP\",\n \"LEFT\",\n \"RIGHT\"\n ]\n }\n }\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded/level/level_1.ts?"); + +/***/ }), + /***/ "./src/global.ts": /*!***********************!*\ !*** ./src/global.ts ***! @@ -203,7 +215,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _met /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Level\", function() { return Level; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _asset_manager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./asset_manager */ \"./src/asset_manager.ts\");\n\n\nvar Level = (function () {\n function Level(levelContent, canvasId) {\n this.app = null;\n this.info = null;\n this.envs = [];\n this.map = null;\n this.agent = null;\n this.roads = {};\n this.cars = [];\n this.info = levelContent;\n this.map = this.info.map;\n this.canvasId = canvasId;\n this.am = new _asset_manager__WEBPACK_IMPORTED_MODULE_1__[\"AssetManger\"](this);\n }\n Level.prototype.load = function (loop) {\n var _this = this;\n this.loop = loop;\n return new Promise(function (resolve, reject) {\n _this.createLevel(_this.info).then(function () { return resolve(); });\n });\n };\n Level.prototype.createLevel = function (info) {\n var _this = this;\n this.app = new PIXI.Application({\n width: this.map[0].length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n height: this.map.length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n backgroundColor: 0x80bf3e\n });\n document.getElementById(this.canvasId).appendChild(this.app.view);\n return new Promise(function (resolve, reject) {\n _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].add([\"public/textures/textures.json\", \"public/textures/textures.png\"]).load(function () {\n _this.setup(info);\n resolve();\n });\n });\n };\n Level.prototype.setup = function (info) {\n var _this = this;\n var textures = _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].resources[_global__WEBPACK_IMPORTED_MODULE_0__[\"JSON_TEXTURES\"]].textures;\n this.am.createMap(this.map, info, textures);\n this.am.createCars(this.map, info, textures);\n if (info.agent)\n this.agent = this.am.createAgent(this.map, info, textures);\n this.app.ticker.add(function (delta) { return _this.loop(delta); });\n };\n Level.prototype.render = function () {\n this.app.ticker.start();\n };\n Level.prototype.reset = function () {\n this.agent.reset();\n };\n Level.prototype.setReward = function (agent_col, on_road, action) {\n var reward = -0.1;\n if (action == 0 || this.agent.core.vx == 1)\n reward += 0.5;\n if (agent_col.length > 0) {\n reward = -10;\n }\n else if (!on_road) {\n reward = -10;\n }\n return reward;\n };\n Level.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n for (var c = 0; c < this.cars.length; c++) {\n if (this.cars[c].lidar && !this.cars[c].core.agent)\n this.cars[c].step(delta);\n }\n if (this.agent) {\n var _a = this.agent.step(delta, action), agent_col = _a.agent_col, on_road = _a.on_road;\n var reward = this.setReward(agent_col, on_road, action);\n return reward;\n }\n return 0;\n };\n Level.prototype.stopRender = function () {\n this.app.ticker.stop();\n };\n Level.prototype.addChild = function (child) {\n this.app.stage.addChild(child);\n };\n Level.prototype.addRoad = function (road) {\n this.roads[[road.my.toString(), road.mx.toString()].toString()] = road;\n this.envs.push(road);\n this.app.stage.addChild(road);\n };\n Level.prototype.addCar = function (car) {\n this.cars.push(car);\n this.app.stage.addChild(car.core);\n this.envs.push(car.core);\n };\n Level.prototype.getRoad = function (my, mx) {\n return this.roads[[my.toString(), mx.toString()].toString()];\n };\n Level.prototype.getRoads = function () {\n return this.roads;\n };\n Level.prototype.findCarById = function (id) {\n return this.cars.find(function (e) { return e.car_id == id; });\n };\n Level.prototype.getEnvs = function () {\n return this.envs;\n };\n Level.prototype.getMap = function () {\n return this.map;\n };\n return Level;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/level.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Level\", function() { return Level; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _asset_manager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./asset_manager */ \"./src/asset_manager.ts\");\n\n\nvar Level = (function () {\n function Level(levelContent, canvasId) {\n this.app = null;\n this.info = null;\n this.envs = [];\n this.map = null;\n this.agent = null;\n this.roads = {};\n this.cars = [];\n this.info = levelContent;\n this.map = this.info.map;\n this.canvasId = canvasId;\n this.am = new _asset_manager__WEBPACK_IMPORTED_MODULE_1__[\"AssetManger\"](this);\n }\n Level.prototype.load = function (loop) {\n var _this = this;\n this.loop = loop;\n return new Promise(function (resolve, reject) {\n _this.createLevel(_this.info).then(function () { return resolve(); });\n });\n };\n Level.prototype.render = function (val) {\n if (val) {\n this.app.ticker.start();\n }\n else {\n this.app.ticker.stop();\n }\n };\n Level.prototype.createLevel = function (info) {\n var _this = this;\n this.app = new PIXI.Application({\n width: this.map[0].length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n height: this.map.length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n backgroundColor: 0x80bf3e\n });\n document.getElementById(this.canvasId).appendChild(this.app.view);\n return new Promise(function (resolve, reject) {\n _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].add([\"public/textures/textures.json\", \"public/textures/textures.png\"]).load(function () {\n _this.setup(info);\n resolve();\n });\n });\n };\n Level.prototype.setup = function (info) {\n var _this = this;\n var textures = _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].resources[_global__WEBPACK_IMPORTED_MODULE_0__[\"JSON_TEXTURES\"]].textures;\n this.am.createMap(this.map, info, textures);\n this.am.createCars(this.map, info, textures);\n if (info.agent)\n this.agent = this.am.createAgent(this.map, info, textures);\n this.app.ticker.add(function (delta) { return _this.loop(delta); });\n };\n Level.prototype.reset = function () {\n this.agent.reset();\n };\n Level.prototype.setReward = function (agent_col, on_road, action) {\n var reward = -0.1;\n if (action == 0 || this.agent.core.vx == 1)\n reward += 0.5;\n if (agent_col.length > 0) {\n reward = -10;\n }\n else if (!on_road) {\n reward = -10;\n }\n return reward;\n };\n Level.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n for (var c = 0; c < this.cars.length; c++) {\n if (this.cars[c].lidar && !this.cars[c].core.agent)\n this.cars[c].step(delta);\n }\n if (this.agent) {\n var _a = this.agent.step(delta, action), agent_col = _a.agent_col, on_road = _a.on_road;\n var reward = this.setReward(agent_col, on_road, action);\n return reward;\n }\n return 0;\n };\n Level.prototype.stopRender = function () {\n this.app.ticker.stop();\n };\n Level.prototype.addChild = function (child) {\n this.app.stage.addChild(child);\n };\n Level.prototype.addRoad = function (road) {\n this.roads[[road.my.toString(), road.mx.toString()].toString()] = road;\n this.envs.push(road);\n this.app.stage.addChild(road);\n };\n Level.prototype.addCar = function (car) {\n this.cars.push(car);\n this.app.stage.addChild(car.core);\n this.envs.push(car.core);\n };\n Level.prototype.getRoad = function (my, mx) {\n return this.roads[[my.toString(), mx.toString()].toString()];\n };\n Level.prototype.getRoads = function () {\n return this.roads;\n };\n Level.prototype.findCarById = function (id) {\n return this.cars.find(function (e) { return e.car_id == id; });\n };\n Level.prototype.getEnvs = function () {\n return this.envs;\n };\n Level.prototype.getMap = function () {\n return this.map;\n };\n return Level;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/level.ts?"); /***/ }), @@ -215,7 +227,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelUrl) {\n if (!canvasId || this.levelUrl) {\n console.error(\"You must specify the canvasId and the levelUrl\");\n }\n this.isPlaying = false;\n this.canvasId = canvasId;\n this.levelUrl = levelUrl;\n }\n MetaCar.prototype.load = function (level, agent) {\n var _this = this;\n return new Promise(function (resolve, reject) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"loadCustomURL\"](_this.levelUrl, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n });\n });\n };\n MetaCar.prototype.render = function () {\n this.level.render();\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function () {\n return this.level.agent.getState();\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n this.level.agent.last_position = [];\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype.loop = function (delta) {\n if (this.isPlaying) {\n this.agent.play(this);\n }\n else {\n this.level.step(delta);\n }\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelUrl) {\n var _this = this;\n this.eventList = [\"train\", \"play\", \"stop\", \"reset_env\", \"reset_agent\", \"save\", \"load\"];\n if (!canvasId || this.levelUrl) {\n console.error(\"You must specify the canvasId and the levelUrl\");\n }\n this.isPlaying = false;\n this.canvasId = canvasId;\n this.levelUrl = levelUrl;\n this.eventCallback = [\n function (fc) { return _this.onTrain(fc); },\n function (fc) { return _this.onPlay(fc); },\n function (fc) { return _this.onStop(fc); },\n function (fc) { return _this.onResetEnv(fc); },\n function (fc) { return _this.onResetAgent(fc); },\n function (fc) { return _this.onSave(fc); },\n function (fc, opt) { return _this.onLoad(fc, opt); }\n ];\n var canvas = document.getElementById(canvasId);\n var buttons = document.createElement('div');\n buttons.classList.add(\"metacar_buttons_container\");\n buttons.id = \"metacar_\" + canvasId + \"_buttons_container\";\n canvas.parentNode.insertBefore(buttons, canvas.nextSibling);\n this.buttonsContainer = buttons;\n }\n MetaCar.prototype.load = function (level, agent) {\n var _this = this;\n return new Promise(function (resolve, reject) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"loadCustomURL\"](_this.levelUrl, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n });\n });\n };\n MetaCar.prototype._createButton = function (parent, name) {\n var button = document.createElement('button');\n button.classList.add(\"metacar_button_train\");\n button.id = \"metacar_\" + this.canvasId + \"_button_\" + name;\n name = name.replace(/_/g, \" \");\n button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);\n ;\n parent.appendChild(button);\n return button;\n };\n MetaCar.prototype.onTrain = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"train\");\n button.addEventListener(\"click\", function () {\n _this.render(false);\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onPlay = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"play\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onStop = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"stop\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onResetEnv = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"reset_env\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onResetAgent = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"reset_agent\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onSave = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"save\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onLoad = function (fc, options) {\n var button = this._createButton(this.buttonsContainer, \"load_trained_agent\");\n var input_file = document.createElement('input');\n input_file.type = \"file\";\n input_file.accept = \"*/*\";\n input_file.style.display = \"none\";\n input_file.classList.add(\"metacar_button_input_file\");\n input_file.id = \"metacar_\" + this.canvasId + \"_button_input_file\";\n this.buttonsContainer.appendChild(input_file);\n input_file.addEventListener(\"change\", function (dump) {\n console.log(\"New file to handle\");\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"readDump\"](dump, function (content) {\n if (fc)\n fc(content);\n });\n });\n button.addEventListener(\"click\", function () {\n input_file.click();\n });\n };\n MetaCar.prototype.addEvent = function (eventName, fc, options) {\n var index = this.eventList.indexOf(eventName);\n if (index == -1) {\n console.error(\"The environement does not support this event. Only the following are\\\n avaible:\" + this.eventList);\n }\n var event = this.eventList[index];\n if (event != \"load\") {\n this.eventCallback[index](fc);\n }\n else {\n this.eventCallback[index](fc, options);\n }\n };\n MetaCar.prototype.render = function (val) {\n this.level.render(val);\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function () {\n return this.level.agent.getState();\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n this.level.agent.last_position = [];\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype.loop = function (delta) {\n if (this.isPlaying) {\n this.agent.play(this);\n }\n else {\n this.level.step(delta);\n }\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); /***/ }), @@ -235,11 +247,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /*!**********************!*\ !*** ./src/utils.ts ***! \**********************/ -/*! exports provided: loadJSON, loadEmbeddedURL, loadLocalStorageURL, loadCustomURL, mod, argMax, mean, saveAs, shuffleArray, keyboard */ +/*! exports provided: loadJSON, loadEmbeddedURL, loadLocalStorageURL, loadCustomURL, mod, argMax, mean, saveAs, readDump, shuffleArray, keyboard */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadJSON\", function() { return loadJSON; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadEmbeddedURL\", function() { return loadEmbeddedURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadLocalStorageURL\", function() { return loadLocalStorageURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadCustomURL\", function() { return loadCustomURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mod\", function() { return mod; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"argMax\", function() { return argMax; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mean\", function() { return mean; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"saveAs\", function() { return saveAs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"shuffleArray\", function() { return shuffleArray; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"keyboard\", function() { return keyboard; });\n/* harmony import */ var _embedded__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded */ \"./src/embedded.ts\");\n\nfunction loadJSON(url, callback) {\n var xobj = new XMLHttpRequest();\n xobj.overrideMimeType(\"application/json\");\n xobj.open('GET', url, true);\n xobj.onreadystatechange = function () {\n if (xobj.readyState == 4 && xobj.status == 200) {\n callback(xobj.responseText);\n }\n };\n xobj.send(null);\n}\nfunction loadEmbeddedURL(url, callback) {\n var split = url.split(\"//\");\n split = split[1].split(\"/\");\n callback(_embedded__WEBPACK_IMPORTED_MODULE_0__[\"embeddedContent\"][split[0]][split[1]]);\n}\nfunction loadLocalStorageURL(url, callback) {\n}\nfunction loadCustomURL(url, callback) {\n var customCall = {\n \"embedded:\": loadEmbeddedURL,\n \"http://\": loadJSON,\n \"https://\": loadJSON,\n \"localstorage://\": loadLocalStorageURL\n };\n var split = url.split(\"//\");\n customCall[split[0]](url, callback);\n}\nfunction mod(n, m) {\n return ((n % m) + m) % m;\n}\nfunction argMax(array) {\n if (array.every(function (v) { return v == -Infinity; })) {\n return Math.floor(Math.random() * array.length);\n }\n return array.map(function (x, i) { return [x, i]; }).reduce(function (r, a) { return (a[0] > r[0] ? a : r); })[1];\n}\nfunction mean(array) {\n if (array.length == 0)\n return null;\n var sum = array.reduce(function (a, b) { return a + b; });\n var avg = sum / array.length;\n return avg;\n}\nfunction saveAs(content, name) {\n var a = document.createElement(\"a\");\n document.body.appendChild(a);\n var blob = new Blob([content], { type: 'application/octet-binary' }), tmpURL = window.URL.createObjectURL(blob);\n a.href = tmpURL;\n a.download = name;\n a.click();\n window.URL.revokeObjectURL(tmpURL);\n a.href = \"\";\n}\nfunction shuffleArray(array) {\n for (var i = array.length - 1; i > 0; i--) {\n var j = Math.floor(Math.random() * (i + 1));\n var temp = array[i];\n array[i] = array[j];\n array[j] = temp;\n }\n return array;\n}\nfunction keyboard(keyCode) {\n var key = {};\n key.code = keyCode;\n key.isDown = false;\n key.isUp = true;\n key.press = undefined;\n key.release = undefined;\n key.downHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isUp && key.press)\n key.press();\n key.isDown = true;\n key.isUp = false;\n }\n event.preventDefault();\n };\n key.upHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isDown && key.release)\n key.release();\n key.isDown = false;\n key.isUp = true;\n }\n event.preventDefault();\n };\n window.addEventListener(\"keydown\", key.downHandler.bind(key), false);\n window.addEventListener(\"keyup\", key.upHandler.bind(key), false);\n return key;\n}\n\n\n//# sourceURL=webpack://metacar/./src/utils.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadJSON\", function() { return loadJSON; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadEmbeddedURL\", function() { return loadEmbeddedURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadLocalStorageURL\", function() { return loadLocalStorageURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadCustomURL\", function() { return loadCustomURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mod\", function() { return mod; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"argMax\", function() { return argMax; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mean\", function() { return mean; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"saveAs\", function() { return saveAs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"readDump\", function() { return readDump; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"shuffleArray\", function() { return shuffleArray; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"keyboard\", function() { return keyboard; });\n/* harmony import */ var _embedded__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded */ \"./src/embedded.ts\");\n\nfunction loadJSON(url, callback) {\n var xobj = new XMLHttpRequest();\n xobj.overrideMimeType(\"application/json\");\n xobj.open('GET', url, true);\n xobj.onreadystatechange = function () {\n if (xobj.readyState == 4 && xobj.status == 200) {\n callback(xobj.responseText);\n }\n };\n xobj.send(null);\n}\nfunction loadEmbeddedURL(url, callback) {\n var split = url.split(\"//\");\n split = split[1].split(\"/\");\n callback(_embedded__WEBPACK_IMPORTED_MODULE_0__[\"embeddedContent\"][split[0]][split[1]]);\n}\nfunction loadLocalStorageURL(url, callback) {\n}\nfunction loadCustomURL(url, callback) {\n var customCall = {\n \"embedded:\": loadEmbeddedURL,\n \"http://\": loadJSON,\n \"https://\": loadJSON,\n \"localstorage://\": loadLocalStorageURL\n };\n var split = url.split(\"//\");\n customCall[split[0]](url, callback);\n}\nfunction mod(n, m) {\n return ((n % m) + m) % m;\n}\nfunction argMax(array) {\n if (array.every(function (v) { return v == -Infinity; })) {\n return Math.floor(Math.random() * array.length);\n }\n return array.map(function (x, i) { return [x, i]; }).reduce(function (r, a) { return (a[0] > r[0] ? a : r); })[1];\n}\nfunction mean(array) {\n if (array.length == 0)\n return null;\n var sum = array.reduce(function (a, b) { return a + b; });\n var avg = sum / array.length;\n return avg;\n}\nfunction saveAs(content, name) {\n var a = document.createElement(\"a\");\n document.body.appendChild(a);\n var blob = new Blob([content], { type: 'application/octet-binary' }), tmpURL = window.URL.createObjectURL(blob);\n a.href = tmpURL;\n a.download = name;\n a.click();\n window.URL.revokeObjectURL(tmpURL);\n a.href = \"\";\n}\nfunction readDump(dump, callback) {\n var input = dump.target;\n var file = input.files[0];\n var reader = new FileReader();\n reader.readAsText(file, \"UTF-8\");\n reader.onload = function (evt) {\n callback(evt.target.result);\n };\n}\nfunction shuffleArray(array) {\n for (var i = array.length - 1; i > 0; i--) {\n var j = Math.floor(Math.random() * (i + 1));\n var temp = array[i];\n array[i] = array[j];\n array[j] = temp;\n }\n return array;\n}\nfunction keyboard(keyCode) {\n var key = {};\n key.code = keyCode;\n key.isDown = false;\n key.isUp = true;\n key.press = undefined;\n key.release = undefined;\n key.downHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isUp && key.press)\n key.press();\n key.isDown = true;\n key.isUp = false;\n }\n };\n key.upHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isDown && key.release)\n key.release();\n key.isDown = false;\n key.isUp = true;\n }\n };\n window.addEventListener(\"keydown\", key.downHandler.bind(key), false);\n window.addEventListener(\"keyup\", key.upHandler.bind(key), false);\n return key;\n}\n\n\n//# sourceURL=webpack://metacar/./src/utils.ts?"); /***/ }), diff --git a/demo/webapp/index.html b/demo/webapp/full_city.html similarity index 100% rename from demo/webapp/index.html rename to demo/webapp/full_city.html diff --git a/demo/webapp/level1.html b/demo/webapp/level1.html new file mode 100644 index 0000000..8142c67 --- /dev/null +++ b/demo/webapp/level1.html @@ -0,0 +1,18 @@ + + + + + Hello World + + + +
+ + + + + + + + + diff --git a/demo/webapp/public/js/level1.js b/demo/webapp/public/js/level1.js new file mode 100644 index 0000000..83619b1 --- /dev/null +++ b/demo/webapp/public/js/level1.js @@ -0,0 +1,28 @@ +// Get the url of the desired level +let levelUrl = metacar.level.level1; +// Create the environement (canvasID, levelUrl) +var env = new metacar.env("canvas", levelUrl); +env.load().then(() => { + // The level is loaded. Add listernes + env.addEvent("train", () => { + console.log("On train!"); + }); + env.addEvent("play", () => { + console.log("On play!"); + }); + env.addEvent("stop", () => { + console.log("On sotp!"); + }); + env.addEvent("reset_env", () => { + console.log("On reset env!"); + }); + env.addEvent("reset_agent", () => { + console.log("On reset agent"); + }) + env.addEvent("save", () => { + console.log("On save"); + }); + env.addEvent("load", (content) => { + console.log("content", content); + }); +}); diff --git a/dist/metacar.min.js b/dist/metacar.min.js index c8a11f2..d3df358 100644 --- a/dist/metacar.min.js +++ b/dist/metacar.min.js @@ -155,7 +155,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedUrl\", function() { return embeddedUrl; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedContent\", function() { return embeddedContent; });\n/* harmony import */ var _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded/level/full_city */ \"./src/embedded/level/full_city.ts\");\n\nvar embeddedUrl = {\n fullCity: \"embedded://level/fullCity\"\n};\nvar embeddedContent = {\n level: {\n fullCity: _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__[\"fullCity\"]\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedUrl\", function() { return embeddedUrl; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"embeddedContent\", function() { return embeddedContent; });\n/* harmony import */ var _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded/level/full_city */ \"./src/embedded/level/full_city.ts\");\n/* harmony import */ var _embedded_level_level_1__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./embedded/level/level_1 */ \"./src/embedded/level/level_1.ts\");\n\n\nvar embeddedUrl = {\n fullCity: \"embedded://level/fullCity\",\n level1: \"embedded://level/level1\"\n};\nvar embeddedContent = {\n level: {\n fullCity: _embedded_level_full_city__WEBPACK_IMPORTED_MODULE_0__[\"fullCity\"],\n level1: _embedded_level_level_1__WEBPACK_IMPORTED_MODULE_1__[\"level1\"]\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded.ts?"); /***/ }), @@ -171,6 +171,18 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ }), +/***/ "./src/embedded/level/level_1.ts": +/*!***************************************!*\ + !*** ./src/embedded/level/level_1.ts ***! + \***************************************/ +/*! exports provided: level1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"level1\", function() { return level1; });\nvar level1 = {\n \"cars\": [\n {\n \"mx\": 5,\n \"my\": 3,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 5,\n \"my\": 3,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 5,\n \"my\": 1,\n \"line\": 0,\n \"auto\": true\n }\n ],\n \"tree\": [\n {\n \"x\": 120,\n \"y\": 50\n },\n {\n \"x\": 86.5,\n \"y\": 85\n },\n {\n \"x\": 94.5,\n \"y\": 135\n },\n {\n \"x\": 30.5,\n \"y\": 128\n },\n {\n \"x\": 72.5,\n \"y\": 190\n },\n {\n \"x\": 23.5,\n \"y\": 232\n },\n {\n \"x\": 110.5,\n \"y\": 242\n },\n {\n \"x\": 43.5,\n \"y\": 33\n },\n {\n \"x\": 18.5,\n \"y\": 178\n },\n {\n \"x\": 305.5,\n \"y\": 125\n },\n {\n \"x\": 360.5,\n \"y\": 122\n }\n ],\n \"asset\": [\n {\n \"x\": 252.5,\n \"y\": 142\n },\n {\n \"x\": 86.5,\n \"y\": 85\n },\n {\n \"x\": 94.5,\n \"y\": 135\n },\n {\n \"x\": 30.5,\n \"y\": 128\n },\n {\n \"x\": 252.5,\n \"y\": 26\n },\n {\n \"x\": 195.5,\n \"y\": 0\n },\n {\n \"x\": 307.5,\n \"y\": 1\n },\n {\n \"x\": 72.5,\n \"y\": 190\n },\n {\n \"x\": 23.5,\n \"y\": 232\n },\n {\n \"x\": 110.5,\n \"y\": 242\n },\n {\n \"x\": 43.5,\n \"y\": 33\n },\n {\n \"x\": 35.5,\n \"y\": 185\n },\n {\n \"x\": 18.5,\n \"y\": 178\n },\n {\n \"x\": 289.5,\n \"y\": 126\n },\n {\n \"x\": 337.5,\n \"y\": 126\n },\n {\n \"x\": 305.5,\n \"y\": 125\n },\n {\n \"x\": 360.5,\n \"y\": 122\n },\n {\n \"x\": 492.5,\n \"y\": 56\n },\n {\n \"x\": 503.5,\n \"y\": 136\n },\n {\n \"x\": 504.5,\n \"y\": 58\n }\n ],\n \"bench\": [\n {\n \"x\": 252.5,\n \"y\": 142\n },\n {\n \"x\": 252.5,\n \"y\": 26\n }\n ],\n \"road\": [\n {\n \"x\": 240,\n \"y\": 60\n },\n {\n \"x\": 240,\n \"y\": 60\n },\n {\n \"x\": 480,\n \"y\": 0\n },\n {\n \"x\": 480,\n \"y\": 60\n },\n {\n \"x\": 480,\n \"y\": 120\n },\n {\n \"x\": 480,\n \"y\": 180\n },\n {\n \"x\": 480,\n \"y\": 240\n },\n {\n \"x\": 300,\n \"y\": 180\n },\n {\n \"x\": 300,\n \"y\": 180\n },\n {\n \"x\": 360,\n \"y\": 180\n },\n {\n \"x\": 420,\n \"y\": 180\n },\n {\n \"x\": 420,\n \"y\": 120\n },\n {\n \"x\": 420,\n \"y\": 60\n },\n {\n \"x\": 360,\n \"y\": 60\n },\n {\n \"x\": 300,\n \"y\": 60\n },\n {\n \"x\": 420,\n \"y\": 120\n }\n ],\n \"house3\": [\n {\n \"x\": 503.5,\n \"y\": 136\n }\n ],\n \"house\": [\n {\n \"x\": 504.5,\n \"y\": 58\n }\n ],\n \"map\": [\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n \"↱\",\n \"↠\",\n \"↔\",\n \"↔\",\n \"↰\",\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n \"↟\",\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n \"↳\",\n \"↔\",\n \"↔\",\n \"↔\",\n \"↲\",\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ]\n ],\n \"agent\": {\n \"mx\": 4,\n \"my\": 3,\n \"line\": 0,\n \"motion\": {\n \"type\": \"BasicMotionEngine\",\n \"options\": {\n \"rotationStep\": 0.5,\n \"actions\": [\n \"UP\",\n \"LEFT\",\n \"RIGHT\"\n ]\n }\n }\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded/level/level_1.ts?"); + +/***/ }), + /***/ "./src/global.ts": /*!***********************!*\ !*** ./src/global.ts ***! @@ -203,7 +215,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _met /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Level\", function() { return Level; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _asset_manager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./asset_manager */ \"./src/asset_manager.ts\");\n\n\nvar Level = (function () {\n function Level(levelContent, canvasId) {\n this.app = null;\n this.info = null;\n this.envs = [];\n this.map = null;\n this.agent = null;\n this.roads = {};\n this.cars = [];\n this.info = levelContent;\n this.map = this.info.map;\n this.canvasId = canvasId;\n this.am = new _asset_manager__WEBPACK_IMPORTED_MODULE_1__[\"AssetManger\"](this);\n }\n Level.prototype.load = function (loop) {\n var _this = this;\n this.loop = loop;\n return new Promise(function (resolve, reject) {\n _this.createLevel(_this.info).then(function () { return resolve(); });\n });\n };\n Level.prototype.createLevel = function (info) {\n var _this = this;\n this.app = new PIXI.Application({\n width: this.map[0].length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n height: this.map.length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n backgroundColor: 0x80bf3e\n });\n document.getElementById(this.canvasId).appendChild(this.app.view);\n return new Promise(function (resolve, reject) {\n _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].add([\"public/textures/textures.json\", \"public/textures/textures.png\"]).load(function () {\n _this.setup(info);\n resolve();\n });\n });\n };\n Level.prototype.setup = function (info) {\n var _this = this;\n var textures = _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].resources[_global__WEBPACK_IMPORTED_MODULE_0__[\"JSON_TEXTURES\"]].textures;\n this.am.createMap(this.map, info, textures);\n this.am.createCars(this.map, info, textures);\n if (info.agent)\n this.agent = this.am.createAgent(this.map, info, textures);\n this.app.ticker.add(function (delta) { return _this.loop(delta); });\n };\n Level.prototype.render = function () {\n this.app.ticker.start();\n };\n Level.prototype.reset = function () {\n this.agent.reset();\n };\n Level.prototype.setReward = function (agent_col, on_road, action) {\n var reward = -0.1;\n if (action == 0 || this.agent.core.vx == 1)\n reward += 0.5;\n if (agent_col.length > 0) {\n reward = -10;\n }\n else if (!on_road) {\n reward = -10;\n }\n return reward;\n };\n Level.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n for (var c = 0; c < this.cars.length; c++) {\n if (this.cars[c].lidar && !this.cars[c].core.agent)\n this.cars[c].step(delta);\n }\n if (this.agent) {\n var _a = this.agent.step(delta, action), agent_col = _a.agent_col, on_road = _a.on_road;\n var reward = this.setReward(agent_col, on_road, action);\n return reward;\n }\n return 0;\n };\n Level.prototype.stopRender = function () {\n this.app.ticker.stop();\n };\n Level.prototype.addChild = function (child) {\n this.app.stage.addChild(child);\n };\n Level.prototype.addRoad = function (road) {\n this.roads[[road.my.toString(), road.mx.toString()].toString()] = road;\n this.envs.push(road);\n this.app.stage.addChild(road);\n };\n Level.prototype.addCar = function (car) {\n this.cars.push(car);\n this.app.stage.addChild(car.core);\n this.envs.push(car.core);\n };\n Level.prototype.getRoad = function (my, mx) {\n return this.roads[[my.toString(), mx.toString()].toString()];\n };\n Level.prototype.getRoads = function () {\n return this.roads;\n };\n Level.prototype.findCarById = function (id) {\n return this.cars.find(function (e) { return e.car_id == id; });\n };\n Level.prototype.getEnvs = function () {\n return this.envs;\n };\n Level.prototype.getMap = function () {\n return this.map;\n };\n return Level;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/level.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Level\", function() { return Level; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _asset_manager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./asset_manager */ \"./src/asset_manager.ts\");\n\n\nvar Level = (function () {\n function Level(levelContent, canvasId) {\n this.app = null;\n this.info = null;\n this.envs = [];\n this.map = null;\n this.agent = null;\n this.roads = {};\n this.cars = [];\n this.info = levelContent;\n this.map = this.info.map;\n this.canvasId = canvasId;\n this.am = new _asset_manager__WEBPACK_IMPORTED_MODULE_1__[\"AssetManger\"](this);\n }\n Level.prototype.load = function (loop) {\n var _this = this;\n this.loop = loop;\n return new Promise(function (resolve, reject) {\n _this.createLevel(_this.info).then(function () { return resolve(); });\n });\n };\n Level.prototype.render = function (val) {\n if (val) {\n this.app.ticker.start();\n }\n else {\n this.app.ticker.stop();\n }\n };\n Level.prototype.createLevel = function (info) {\n var _this = this;\n this.app = new PIXI.Application({\n width: this.map[0].length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n height: this.map.length * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"],\n backgroundColor: 0x80bf3e\n });\n document.getElementById(this.canvasId).appendChild(this.app.view);\n return new Promise(function (resolve, reject) {\n _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].add([\"public/textures/textures.json\", \"public/textures/textures.png\"]).load(function () {\n _this.setup(info);\n resolve();\n });\n });\n };\n Level.prototype.setup = function (info) {\n var _this = this;\n var textures = _global__WEBPACK_IMPORTED_MODULE_0__[\"Loader\"].resources[_global__WEBPACK_IMPORTED_MODULE_0__[\"JSON_TEXTURES\"]].textures;\n this.am.createMap(this.map, info, textures);\n this.am.createCars(this.map, info, textures);\n if (info.agent)\n this.agent = this.am.createAgent(this.map, info, textures);\n this.app.ticker.add(function (delta) { return _this.loop(delta); });\n };\n Level.prototype.reset = function () {\n this.agent.reset();\n };\n Level.prototype.setReward = function (agent_col, on_road, action) {\n var reward = -0.1;\n if (action == 0 || this.agent.core.vx == 1)\n reward += 0.5;\n if (agent_col.length > 0) {\n reward = -10;\n }\n else if (!on_road) {\n reward = -10;\n }\n return reward;\n };\n Level.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n for (var c = 0; c < this.cars.length; c++) {\n if (this.cars[c].lidar && !this.cars[c].core.agent)\n this.cars[c].step(delta);\n }\n if (this.agent) {\n var _a = this.agent.step(delta, action), agent_col = _a.agent_col, on_road = _a.on_road;\n var reward = this.setReward(agent_col, on_road, action);\n return reward;\n }\n return 0;\n };\n Level.prototype.stopRender = function () {\n this.app.ticker.stop();\n };\n Level.prototype.addChild = function (child) {\n this.app.stage.addChild(child);\n };\n Level.prototype.addRoad = function (road) {\n this.roads[[road.my.toString(), road.mx.toString()].toString()] = road;\n this.envs.push(road);\n this.app.stage.addChild(road);\n };\n Level.prototype.addCar = function (car) {\n this.cars.push(car);\n this.app.stage.addChild(car.core);\n this.envs.push(car.core);\n };\n Level.prototype.getRoad = function (my, mx) {\n return this.roads[[my.toString(), mx.toString()].toString()];\n };\n Level.prototype.getRoads = function () {\n return this.roads;\n };\n Level.prototype.findCarById = function (id) {\n return this.cars.find(function (e) { return e.car_id == id; });\n };\n Level.prototype.getEnvs = function () {\n return this.envs;\n };\n Level.prototype.getMap = function () {\n return this.map;\n };\n return Level;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/level.ts?"); /***/ }), @@ -215,7 +227,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelUrl) {\n if (!canvasId || this.levelUrl) {\n console.error(\"You must specify the canvasId and the levelUrl\");\n }\n this.isPlaying = false;\n this.canvasId = canvasId;\n this.levelUrl = levelUrl;\n }\n MetaCar.prototype.load = function (level, agent) {\n var _this = this;\n return new Promise(function (resolve, reject) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"loadCustomURL\"](_this.levelUrl, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n });\n });\n };\n MetaCar.prototype.render = function () {\n this.level.render();\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function () {\n return this.level.agent.getState();\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n this.level.agent.last_position = [];\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype.loop = function (delta) {\n if (this.isPlaying) {\n this.agent.play(this);\n }\n else {\n this.level.step(delta);\n }\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelUrl) {\n var _this = this;\n this.eventList = [\"train\", \"play\", \"stop\", \"reset_env\", \"reset_agent\", \"save\", \"load\"];\n if (!canvasId || this.levelUrl) {\n console.error(\"You must specify the canvasId and the levelUrl\");\n }\n this.isPlaying = false;\n this.canvasId = canvasId;\n this.levelUrl = levelUrl;\n this.eventCallback = [\n function (fc) { return _this.onTrain(fc); },\n function (fc) { return _this.onPlay(fc); },\n function (fc) { return _this.onStop(fc); },\n function (fc) { return _this.onResetEnv(fc); },\n function (fc) { return _this.onResetAgent(fc); },\n function (fc) { return _this.onSave(fc); },\n function (fc, opt) { return _this.onLoad(fc, opt); }\n ];\n var canvas = document.getElementById(canvasId);\n var buttons = document.createElement('div');\n buttons.classList.add(\"metacar_buttons_container\");\n buttons.id = \"metacar_\" + canvasId + \"_buttons_container\";\n canvas.parentNode.insertBefore(buttons, canvas.nextSibling);\n this.buttonsContainer = buttons;\n }\n MetaCar.prototype.load = function (level, agent) {\n var _this = this;\n return new Promise(function (resolve, reject) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"loadCustomURL\"](_this.levelUrl, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n });\n });\n };\n MetaCar.prototype._createButton = function (parent, name) {\n var button = document.createElement('button');\n button.classList.add(\"metacar_button_train\");\n button.id = \"metacar_\" + this.canvasId + \"_button_\" + name;\n name = name.replace(/_/g, \" \");\n button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);\n ;\n parent.appendChild(button);\n return button;\n };\n MetaCar.prototype.onTrain = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"train\");\n button.addEventListener(\"click\", function () {\n _this.render(false);\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onPlay = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"play\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onStop = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"stop\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onResetEnv = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"reset_env\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onResetAgent = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"reset_agent\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onSave = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"save\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n MetaCar.prototype.onLoad = function (fc, options) {\n var button = this._createButton(this.buttonsContainer, \"load_trained_agent\");\n var input_file = document.createElement('input');\n input_file.type = \"file\";\n input_file.accept = \"*/*\";\n input_file.style.display = \"none\";\n input_file.classList.add(\"metacar_button_input_file\");\n input_file.id = \"metacar_\" + this.canvasId + \"_button_input_file\";\n this.buttonsContainer.appendChild(input_file);\n input_file.addEventListener(\"change\", function (dump) {\n console.log(\"New file to handle\");\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"readDump\"](dump, function (content) {\n if (fc)\n fc(content);\n });\n });\n button.addEventListener(\"click\", function () {\n input_file.click();\n });\n };\n MetaCar.prototype.addEvent = function (eventName, fc, options) {\n var index = this.eventList.indexOf(eventName);\n if (index == -1) {\n console.error(\"The environement does not support this event. Only the following are\\\n avaible:\" + this.eventList);\n }\n var event = this.eventList[index];\n if (event != \"load\") {\n this.eventCallback[index](fc);\n }\n else {\n this.eventCallback[index](fc, options);\n }\n };\n MetaCar.prototype.render = function (val) {\n this.level.render(val);\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_1__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function () {\n return this.level.agent.getState();\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n this.level.agent.last_position = [];\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype.loop = function (delta) {\n if (this.isPlaying) {\n this.agent.play(this);\n }\n else {\n this.level.step(delta);\n }\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); /***/ }), @@ -235,11 +247,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /*!**********************!*\ !*** ./src/utils.ts ***! \**********************/ -/*! exports provided: loadJSON, loadEmbeddedURL, loadLocalStorageURL, loadCustomURL, mod, argMax, mean, saveAs, shuffleArray, keyboard */ +/*! exports provided: loadJSON, loadEmbeddedURL, loadLocalStorageURL, loadCustomURL, mod, argMax, mean, saveAs, readDump, shuffleArray, keyboard */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadJSON\", function() { return loadJSON; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadEmbeddedURL\", function() { return loadEmbeddedURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadLocalStorageURL\", function() { return loadLocalStorageURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadCustomURL\", function() { return loadCustomURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mod\", function() { return mod; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"argMax\", function() { return argMax; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mean\", function() { return mean; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"saveAs\", function() { return saveAs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"shuffleArray\", function() { return shuffleArray; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"keyboard\", function() { return keyboard; });\n/* harmony import */ var _embedded__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded */ \"./src/embedded.ts\");\n\nfunction loadJSON(url, callback) {\n var xobj = new XMLHttpRequest();\n xobj.overrideMimeType(\"application/json\");\n xobj.open('GET', url, true);\n xobj.onreadystatechange = function () {\n if (xobj.readyState == 4 && xobj.status == 200) {\n callback(xobj.responseText);\n }\n };\n xobj.send(null);\n}\nfunction loadEmbeddedURL(url, callback) {\n var split = url.split(\"//\");\n split = split[1].split(\"/\");\n callback(_embedded__WEBPACK_IMPORTED_MODULE_0__[\"embeddedContent\"][split[0]][split[1]]);\n}\nfunction loadLocalStorageURL(url, callback) {\n}\nfunction loadCustomURL(url, callback) {\n var customCall = {\n \"embedded:\": loadEmbeddedURL,\n \"http://\": loadJSON,\n \"https://\": loadJSON,\n \"localstorage://\": loadLocalStorageURL\n };\n var split = url.split(\"//\");\n customCall[split[0]](url, callback);\n}\nfunction mod(n, m) {\n return ((n % m) + m) % m;\n}\nfunction argMax(array) {\n if (array.every(function (v) { return v == -Infinity; })) {\n return Math.floor(Math.random() * array.length);\n }\n return array.map(function (x, i) { return [x, i]; }).reduce(function (r, a) { return (a[0] > r[0] ? a : r); })[1];\n}\nfunction mean(array) {\n if (array.length == 0)\n return null;\n var sum = array.reduce(function (a, b) { return a + b; });\n var avg = sum / array.length;\n return avg;\n}\nfunction saveAs(content, name) {\n var a = document.createElement(\"a\");\n document.body.appendChild(a);\n var blob = new Blob([content], { type: 'application/octet-binary' }), tmpURL = window.URL.createObjectURL(blob);\n a.href = tmpURL;\n a.download = name;\n a.click();\n window.URL.revokeObjectURL(tmpURL);\n a.href = \"\";\n}\nfunction shuffleArray(array) {\n for (var i = array.length - 1; i > 0; i--) {\n var j = Math.floor(Math.random() * (i + 1));\n var temp = array[i];\n array[i] = array[j];\n array[j] = temp;\n }\n return array;\n}\nfunction keyboard(keyCode) {\n var key = {};\n key.code = keyCode;\n key.isDown = false;\n key.isUp = true;\n key.press = undefined;\n key.release = undefined;\n key.downHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isUp && key.press)\n key.press();\n key.isDown = true;\n key.isUp = false;\n }\n event.preventDefault();\n };\n key.upHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isDown && key.release)\n key.release();\n key.isDown = false;\n key.isUp = true;\n }\n event.preventDefault();\n };\n window.addEventListener(\"keydown\", key.downHandler.bind(key), false);\n window.addEventListener(\"keyup\", key.upHandler.bind(key), false);\n return key;\n}\n\n\n//# sourceURL=webpack://metacar/./src/utils.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadJSON\", function() { return loadJSON; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadEmbeddedURL\", function() { return loadEmbeddedURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadLocalStorageURL\", function() { return loadLocalStorageURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"loadCustomURL\", function() { return loadCustomURL; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mod\", function() { return mod; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"argMax\", function() { return argMax; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"mean\", function() { return mean; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"saveAs\", function() { return saveAs; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"readDump\", function() { return readDump; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"shuffleArray\", function() { return shuffleArray; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"keyboard\", function() { return keyboard; });\n/* harmony import */ var _embedded__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./embedded */ \"./src/embedded.ts\");\n\nfunction loadJSON(url, callback) {\n var xobj = new XMLHttpRequest();\n xobj.overrideMimeType(\"application/json\");\n xobj.open('GET', url, true);\n xobj.onreadystatechange = function () {\n if (xobj.readyState == 4 && xobj.status == 200) {\n callback(xobj.responseText);\n }\n };\n xobj.send(null);\n}\nfunction loadEmbeddedURL(url, callback) {\n var split = url.split(\"//\");\n split = split[1].split(\"/\");\n callback(_embedded__WEBPACK_IMPORTED_MODULE_0__[\"embeddedContent\"][split[0]][split[1]]);\n}\nfunction loadLocalStorageURL(url, callback) {\n}\nfunction loadCustomURL(url, callback) {\n var customCall = {\n \"embedded:\": loadEmbeddedURL,\n \"http://\": loadJSON,\n \"https://\": loadJSON,\n \"localstorage://\": loadLocalStorageURL\n };\n var split = url.split(\"//\");\n customCall[split[0]](url, callback);\n}\nfunction mod(n, m) {\n return ((n % m) + m) % m;\n}\nfunction argMax(array) {\n if (array.every(function (v) { return v == -Infinity; })) {\n return Math.floor(Math.random() * array.length);\n }\n return array.map(function (x, i) { return [x, i]; }).reduce(function (r, a) { return (a[0] > r[0] ? a : r); })[1];\n}\nfunction mean(array) {\n if (array.length == 0)\n return null;\n var sum = array.reduce(function (a, b) { return a + b; });\n var avg = sum / array.length;\n return avg;\n}\nfunction saveAs(content, name) {\n var a = document.createElement(\"a\");\n document.body.appendChild(a);\n var blob = new Blob([content], { type: 'application/octet-binary' }), tmpURL = window.URL.createObjectURL(blob);\n a.href = tmpURL;\n a.download = name;\n a.click();\n window.URL.revokeObjectURL(tmpURL);\n a.href = \"\";\n}\nfunction readDump(dump, callback) {\n var input = dump.target;\n var file = input.files[0];\n var reader = new FileReader();\n reader.readAsText(file, \"UTF-8\");\n reader.onload = function (evt) {\n callback(evt.target.result);\n };\n}\nfunction shuffleArray(array) {\n for (var i = array.length - 1; i > 0; i--) {\n var j = Math.floor(Math.random() * (i + 1));\n var temp = array[i];\n array[i] = array[j];\n array[j] = temp;\n }\n return array;\n}\nfunction keyboard(keyCode) {\n var key = {};\n key.code = keyCode;\n key.isDown = false;\n key.isUp = true;\n key.press = undefined;\n key.release = undefined;\n key.downHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isUp && key.press)\n key.press();\n key.isDown = true;\n key.isUp = false;\n }\n };\n key.upHandler = function (event) {\n if (event.keyCode === key.code) {\n if (key.isDown && key.release)\n key.release();\n key.isDown = false;\n key.isUp = true;\n }\n };\n window.addEventListener(\"keydown\", key.downHandler.bind(key), false);\n window.addEventListener(\"keyup\", key.upHandler.bind(key), false);\n return key;\n}\n\n\n//# sourceURL=webpack://metacar/./src/utils.ts?"); /***/ }), diff --git a/src/basic_motion_engine.ts b/src/basic_motion_engine.ts index e3875e6..fa337d0 100644 --- a/src/basic_motion_engine.ts +++ b/src/basic_motion_engine.ts @@ -77,15 +77,15 @@ export class BasicMotionEngine extends MotionEngine { } } - turnLeft(){ + turnLeft():void { /* Turn left */ - this.car.rotation -= this.rotationStep*Math.PI; - this.lidar.rotation = this.car.rotation; + this.car.rotation -= this.rotationStep*Math.PI + this.lidar.rotation = this.car.rotation; } - turnRight(){ + turnRight():void { /* Turn right */ @@ -93,14 +93,14 @@ export class BasicMotionEngine extends MotionEngine { this.lidar.rotation = this.car.rotation; } - moveForward(){ + moveForward():void { /* Move forward */ this.car.v = 1; } - moveBackward(){ + moveBackward():void { /* Move backward */ diff --git a/src/embedded.ts b/src/embedded.ts index 2426558..04da286 100644 --- a/src/embedded.ts +++ b/src/embedded.ts @@ -1,11 +1,14 @@ import {fullCity} from "./embedded/level/full_city"; +import {level1} from "./embedded/level/level_1"; export const embeddedUrl: any = { - fullCity: "embedded://level/fullCity" + fullCity: "embedded://level/fullCity", + level1: "embedded://level/level1" } export const embeddedContent: any = { level: { - fullCity: fullCity + fullCity: fullCity, + level1: level1 } } \ No newline at end of file diff --git a/src/embedded/level/level_1.ts b/src/embedded/level/level_1.ts new file mode 100644 index 0000000..fa44b7a --- /dev/null +++ b/src/embedded/level/level_1.ts @@ -0,0 +1,316 @@ +export const level1: any = { + "cars": [ + { + "mx": 5, + "my": 3, + "line": 0, + "auto": true + }, + { + "mx": 5, + "my": 3, + "line": 1, + "auto": true + }, + { + "mx": 5, + "my": 1, + "line": 0, + "auto": true + } + ], + "tree": [ + { + "x": 120, + "y": 50 + }, + { + "x": 86.5, + "y": 85 + }, + { + "x": 94.5, + "y": 135 + }, + { + "x": 30.5, + "y": 128 + }, + { + "x": 72.5, + "y": 190 + }, + { + "x": 23.5, + "y": 232 + }, + { + "x": 110.5, + "y": 242 + }, + { + "x": 43.5, + "y": 33 + }, + { + "x": 18.5, + "y": 178 + }, + { + "x": 305.5, + "y": 125 + }, + { + "x": 360.5, + "y": 122 + } + ], + "asset": [ + { + "x": 252.5, + "y": 142 + }, + { + "x": 86.5, + "y": 85 + }, + { + "x": 94.5, + "y": 135 + }, + { + "x": 30.5, + "y": 128 + }, + { + "x": 252.5, + "y": 26 + }, + { + "x": 195.5, + "y": 0 + }, + { + "x": 307.5, + "y": 1 + }, + { + "x": 72.5, + "y": 190 + }, + { + "x": 23.5, + "y": 232 + }, + { + "x": 110.5, + "y": 242 + }, + { + "x": 43.5, + "y": 33 + }, + { + "x": 35.5, + "y": 185 + }, + { + "x": 18.5, + "y": 178 + }, + { + "x": 289.5, + "y": 126 + }, + { + "x": 337.5, + "y": 126 + }, + { + "x": 305.5, + "y": 125 + }, + { + "x": 360.5, + "y": 122 + }, + { + "x": 492.5, + "y": 56 + }, + { + "x": 503.5, + "y": 136 + }, + { + "x": 504.5, + "y": 58 + } + ], + "bench": [ + { + "x": 252.5, + "y": 142 + }, + { + "x": 252.5, + "y": 26 + } + ], + "road": [ + { + "x": 240, + "y": 60 + }, + { + "x": 240, + "y": 60 + }, + { + "x": 480, + "y": 0 + }, + { + "x": 480, + "y": 60 + }, + { + "x": 480, + "y": 120 + }, + { + "x": 480, + "y": 180 + }, + { + "x": 480, + "y": 240 + }, + { + "x": 300, + "y": 180 + }, + { + "x": 300, + "y": 180 + }, + { + "x": 360, + "y": 180 + }, + { + "x": 420, + "y": 180 + }, + { + "x": 420, + "y": 120 + }, + { + "x": 420, + "y": 60 + }, + { + "x": 360, + "y": 60 + }, + { + "x": 300, + "y": 60 + }, + { + "x": 420, + "y": 120 + } + ], + "house3": [ + { + "x": 503.5, + "y": 136 + } + ], + "house": [ + { + "x": 504.5, + "y": 58 + } + ], + "map": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + "↱", + "↠", + "↔", + "↔", + "↰", + 0, + 0 + ], + [ + 0, + 0, + 0, + "↕", + 0, + 0, + 0, + "↟", + 0, + 0 + ], + [ + 0, + 0, + 0, + "↳", + "↔", + "↔", + "↔", + "↲", + 0, + 0 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ], + "agent": { + "mx": 4, + "my": 3, + "line": 0, + "motion": { + "type": "BasicMotionEngine", + "options": { + "rotationStep": 0.5, + "actions": [ + "UP", + "LEFT", + "RIGHT" + ] + } + } + } +} diff --git a/src/level.ts b/src/level.ts index 8d48093..2f6654a 100644 --- a/src/level.ts +++ b/src/level.ts @@ -60,6 +60,15 @@ export class Level { }); } + render(val: boolean){ + if (val){ + this.app.ticker.start(); + } + else{ + this.app.ticker.stop(); + } + } + createLevel(info: LevelInfo){ /* Create the level @@ -98,14 +107,6 @@ export class Level { this.app.ticker.add((delta: number) => this.loop(delta)); } - render(){ - /* - If the rendering has been stopped, this Method - restart the rendering. - */ - this.app.ticker.start(); - } - reset(){ /* Reset the game. diff --git a/src/metacar.ts b/src/metacar.ts index 88fd91f..60e7cec 100644 --- a/src/metacar.ts +++ b/src/metacar.ts @@ -5,6 +5,10 @@ import {Level, LevelInfo} from "./level"; import * as U from "./utils"; +export interface eventLoadOptions { + computer: boolean; +} + export class MetaCar { private isPlaying: boolean; @@ -12,6 +16,9 @@ export class MetaCar { private level: Level; private canvasId: string; private levelUrl: string; + private eventList: string[] = ["train", "play", "stop", "reset_env", "reset_agent", "save", "load"] + private eventCallback: any[]; + private buttonsContainer: HTMLDivElement; constructor(canvasId: string, levelUrl: string) { /** @@ -27,6 +34,23 @@ export class MetaCar { this.isPlaying = false; this.canvasId = canvasId; this.levelUrl = levelUrl; + this.eventCallback = [ + (fc: any) => this.onTrain(fc), + (fc: any) => this.onPlay(fc), + (fc:any) => this.onStop(fc), + (fc: any) => this.onResetEnv(fc), + (fc: any) => this.onResetAgent(fc), + (fc: any) => this.onSave(fc), + (fc: any, opt: eventLoadOptions) => this.onLoad(fc, opt) + ]; + + // Insert the event div + var canvas = document.getElementById(canvasId); + var buttons = document.createElement('div'); // create new textarea + buttons.classList.add("metacar_buttons_container"); + buttons.id = "metacar_"+ canvasId + "_buttons_container"; + canvas.parentNode.insertBefore(buttons, canvas.nextSibling); + this.buttonsContainer = buttons; } load(level: string, agent: any): Promise{ @@ -56,8 +80,8 @@ export class MetaCar { }); document.getElementById("stop").addEventListener("click", () => { this.isPlaying = false; - this.agent.stop(); this.level.render(); + this.agent.stop(); }); document.getElementById("reset").addEventListener("click", () => { this.level.reset(); @@ -74,12 +98,117 @@ export class MetaCar { */ } - render(){ + private _createButton(parent: HTMLDivElement, name: string): HTMLButtonElement{ + var button = document.createElement('button'); // create new textarea + button.classList.add("metacar_button_train"); + button.id = "metacar_"+ this.canvasId + "_button_" + name; + // Uppercase first letter and replace _ + name = name.replace(/_/g , " "); + button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);; + parent.appendChild(button); + return button + } + + onTrain(fc: any){ + // Create the button + const button = this._createButton(this.buttonsContainer, "train"); + // Listen the event + button.addEventListener("click", () => { + this.render(false); + if (fc) fc(); + }); + } + + onPlay(fc: any){ + // Create the button + const button = this._createButton(this.buttonsContainer, "play"); + // Listen the event + button.addEventListener("click", () => { + if (fc) fc(); + }); + } + + onStop(fc: any){ + // Create the button + const button = this._createButton(this.buttonsContainer, "stop"); + // Listen the event + button.addEventListener("click", () => { + if (fc) fc(); + }); + } + + onResetEnv(fc: any){ + // Create the button + const button = this._createButton(this.buttonsContainer, "reset_env"); + button.addEventListener("click", () => { + if (fc) fc(); + }); + } + + onResetAgent(fc: any){ + // Create the button + const button = this._createButton(this.buttonsContainer, "reset_agent"); + button.addEventListener("click", () => { + if (fc) fc(); + }); + } + + onSave(fc: any){ + // Create the button + const button = this._createButton(this.buttonsContainer, "save"); + button.addEventListener("click", () => { + if (fc) fc(); + }); + } + + onLoad(fc: any, options: eventLoadOptions){ + // Create the button + const button = this._createButton(this.buttonsContainer, "load_trained_agent"); + // Create the fake input input file + var input_file = document.createElement('input'); // create new textarea + input_file.type = "file"; + input_file.accept = "*/*"; + input_file.style.display = "none"; + input_file.classList.add("metacar_button_input_file"); + input_file.id = "metacar_"+ this.canvasId + "_button_input_file"; + this.buttonsContainer.appendChild(input_file); + + input_file.addEventListener("change", (dump) => { + console.log("New file to handle"); + U.readDump(dump, (content: any) => { + if (fc) fc(content); + }); + }); + + button.addEventListener("click", () => { + input_file.click(); + }); + } + + addEvent(eventName: string, fc: any, options?: eventLoadOptions):void { + /** + * eventName: Name of the event to listen + * fc: Function to call each time this event is raise + */ + const index = this.eventList.indexOf(eventName); + if (index == -1){ + console.error("The environement does not support this event. Only the following are\ + avaible:" + this.eventList); + } + const event = this.eventList[index]; + if (event != "load"){ + this.eventCallback[index](fc); + } + else{ + this.eventCallback[index](fc, options); + } + } + + render(val: boolean){ /* - Render the environement - again + Choose whether to render the environement. */ - this.level.render(); + this.level.render(val); } save(content: any, file_name: string){ diff --git a/src/utils.ts b/src/utils.ts index 6a995ef..d7e0334 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -122,18 +122,16 @@ function readBuffer(buffer) { } */ -/* -function readDump(e, callback) { - var input = e.target; +export function readDump(dump: any, callback: any) { + var input = dump.target; var file = input.files[0]; - var reader = new FileReader(); reader.readAsText(file, "UTF-8"); - reader.onload = (evt) => { + reader.onload = (evt:any) => { callback(evt.target.result); } } -*/ + export function shuffleArray(array: number[]) { /** @@ -174,7 +172,7 @@ export function keyboard(keyCode: any ) { key.isDown = true; key.isUp = false; } - event.preventDefault(); + //event.preventDefault(); }; key.upHandler = (event: any) => { @@ -183,9 +181,9 @@ export function keyboard(keyCode: any ) { key.isDown = false; key.isUp = true; } - event.preventDefault(); + //event.preventDefault(); }; - + //Attach event listeners window.addEventListener( "keydown", key.downHandler.bind(key), false