diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2acffa --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.baseDir.ts* +node_modules/* +dist/dist-es6/* +demo/dist/dist-es6/* +demo/node_modules/ +*package-lock.json* \ No newline at end of file diff --git a/demo/app.js b/demo/app.js index f8cde0d..56a7bb0 100644 --- a/demo/app.js +++ b/demo/app.js @@ -1,49 +1,38 @@ 'use strict'; -var fs = require('fs'); -// [START app] +var fs = require('fs'); const express = require('express'); -var path = require("path"); - +var path = require("path"); function fromDir(startPath,filter){ - - //console.log('Starting from dir '+startPath+'/'); - - if (!fs.existsSync(startPath)){ - console.log("no dir ",startPath); - return []; - } - var files_list = []; var files=fs.readdirSync(startPath); for(var i=0;i=0) { + if (filename.indexOf(filter)>=0) { files_list.push(filename); }; }; return files_list; } +function get_path(file){ + return path.join(path.join(__dirname, "webapp/"), file); +} + const app = express(); app.use("/dist", express.static(path.join(__dirname, "dist/"))); app.use("/public", express.static(path.join(__dirname, "webapp/public/"))); - -function get_path(file){ - return path.join(path.join(__dirname, "webapp/"), file); -} - app.get('/', (req, res) => { res.sendFile(get_path("index.html")); }); +/** + * Create all HTML routes + * **/ const files = fromDir(path.join(__dirname, "webapp/"),'.html'); files.forEach(file => { let route = file.split("/"); @@ -61,4 +50,3 @@ app.listen(PORT, () => { console.log(`App listening on port ${PORT}`); console.log('Press Ctrl+C to quit.'); }); -// [END app] diff --git a/demo/dist/metacar.min.js b/demo/dist/metacar.min.js new file mode 100644 index 0000000..c8a11f2 --- /dev/null +++ b/demo/dist/metacar.min.js @@ -0,0 +1,257 @@ +window["metacar"] = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.ts"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./src/asset_manager.ts": +/*!******************************!*\ + !*** ./src/asset_manager.ts ***! + \******************************/ +/*! exports provided: AssetManger */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AssetManger\", function() { return AssetManger; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _car__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./car */ \"./src/car.ts\");\n/* harmony import */ var _basic_motion_engine__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./basic_motion_engine */ \"./src/basic_motion_engine.ts\");\n/* harmony import */ var _control_motion_engine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./control_motion_engine */ \"./src/control_motion_engine.ts\");\n/* harmony import */ var _bot_motion_engine__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./bot_motion_engine */ \"./src/bot_motion_engine.ts\");\n\n\n\n\n\n\n;\nvar AssetManger = (function () {\n function AssetManger(level) {\n this.assets = [];\n this.level = level;\n this.motion = {\n \"BasicMotionEngine\": _basic_motion_engine__WEBPACK_IMPORTED_MODULE_3__[\"BasicMotionEngine\"],\n \"ControlMotionEngine\": _control_motion_engine__WEBPACK_IMPORTED_MODULE_4__[\"ControlMotionEngine\"]\n };\n }\n AssetManger.prototype.createRoadSide = function (info, textures) {\n var x = (info.mx) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n var y = (info.my) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n var area = new _global__WEBPACK_IMPORTED_MODULE_1__[\"Graphics\"]();\n area.beginFill(0xe8e8e8);\n area.drawRoundedRect(0, 0, _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] + 30, _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] + 30, undefined);\n area.x = x - 15;\n area.y = y - 15;\n area.endFill();\n this.level.addChild(area);\n };\n AssetManger.prototype.createRoad = function (info, textures) {\n var _this = this;\n var road = new _global__WEBPACK_IMPORTED_MODULE_1__[\"Sprite\"](textures[_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[info.type].image]);\n road.x = (info.mx) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n road.y = (info.my) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n road.obstacle = false;\n road.mapId = _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].ROAD;\n road.orientation = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[info.type].orientation;\n road.setCarPosition = function (car, line) { return _this.setCarOnRoad(road, car, line); };\n road.cars = [];\n road.mx = info.mx;\n road.my = info.my;\n this.level.addRoad(road);\n };\n AssetManger.prototype.setCarOnRoad = function (road, car, line) {\n if (line == undefined)\n line = 0;\n var carById = this.level.findCarById(road.cars[0]);\n if (road.cars.length >= 1 && carById && carById.core.line == line) {\n line = line == 0 ? 1 : 0;\n }\n if (road.cars.length >= 2) {\n car.is_valid = false;\n return;\n }\n car.line = line;\n car.x = road.x;\n car.y = road.y;\n car.x += _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2;\n car.y += _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2;\n var x_margin = 0;\n var y_margin = (_global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] * 1 / 4);\n road.orientation = (Math.floor(road.orientation / car.rotationStep) * car.rotationStep);\n var th = -road.orientation * (Math.PI);\n var x_m = (Math.cos(th) * x_margin) - (y_margin * Math.sin(th));\n var y_m = (Math.cos(th) * y_margin) + (x_margin * Math.sin(th));\n var line_side_factor = line == 0 ? 1 : -1;\n var line_side_factor_t = line == 0 ? 0 : Math.PI;\n car.x += line_side_factor * Math.round(x_m);\n car.y += line_side_factor * Math.round(y_m);\n car.mx = Math.floor(car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n car.my = Math.floor(car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n car.rotation = (th + line_side_factor_t);\n car.checkAndsetNewRoad(road);\n };\n AssetManger.prototype.createAsset = function (img, info, textures, type) {\n var asset = new _global__WEBPACK_IMPORTED_MODULE_1__[\"Sprite\"](textures[img]);\n asset.obstacle = false;\n asset.type = type;\n asset.mapId = 0;\n asset.x = info.x;\n asset.y = info.y;\n this.level.addChild(asset);\n this.assets.push(asset);\n };\n AssetManger.prototype.createMap = function (map, info, textures, roadside) {\n if (roadside === void 0) { roadside = true; }\n if (roadside) {\n for (var my = 0; my < map.length; my++) {\n for (var mx = 0; mx < map[my].length; mx++) {\n if (_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[map[my][mx]]) {\n this.createRoadSide({ mx: mx, my: my, type: map[my][mx] }, textures);\n }\n }\n }\n }\n for (var my = 0; my < map.length; my++) {\n for (var mx = 0; mx < map[my].length; mx++) {\n if (_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[map[my][mx]]) {\n this.createRoad({ mx: mx, my: my, type: map[my][mx] }, textures);\n }\n }\n }\n for (var key in _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"]) {\n if (key != \"ROADS\" && info[key]) {\n for (var a = 0; a < info[key].length; a++) {\n this.createAsset(_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image, info[key][a], textures, key);\n }\n }\n }\n };\n AssetManger.prototype.createCars = function (map, info, textures) {\n for (var c in info.cars) {\n var options = { lidar: true, lidarInfo: { pts: 2, width: 0.5, height: 1, pos: 1 } };\n if (info.cars[c].auto) {\n options.lidar = true;\n options.motionEngine = new _bot_motion_engine__WEBPACK_IMPORTED_MODULE_5__[\"BotMotionEngine\"](this.level);\n }\n var n_car = new _car__WEBPACK_IMPORTED_MODULE_2__[\"Car\"](this.level, info.cars[c], textures, options);\n this.level.addCar(n_car);\n }\n };\n AssetManger.prototype.createAgent = function (map, info, textures) {\n var agent = new _car__WEBPACK_IMPORTED_MODULE_2__[\"Car\"](this.level, info.agent, textures, {\n image: _global__WEBPACK_IMPORTED_MODULE_1__[\"CAR_IMG\"].AGENT,\n lidar: true,\n motionEngine: new this.motion[info.agent.motion.type](this.level, info.agent.motion.options)\n });\n this.level.addChild(agent.lidar);\n this.level.addCar(agent);\n agent.core.agent = true;\n return agent;\n };\n AssetManger.prototype.addAsset = function (asset) {\n this.assets.push(asset);\n };\n AssetManger.prototype.exportMap = function (width, height, file_name) {\n var file = { \"cars\": [] };\n var map = [];\n var envs = this.level.getEnvs();\n for (var y = 0; y < height; y++) {\n var line = [];\n for (var x = 0; x < width; x++) {\n line.push(0);\n }\n map.push(line);\n }\n for (var e = 0; e < envs.length; e++) {\n var elem = envs[e];\n if (!elem.isremove) {\n if (elem.mapId == _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].CAR && !elem.agent && elem.is_valid) {\n file.cars.push({\n \"mx\": elem.mx,\n \"my\": elem.my,\n \"line\": elem.line\n });\n }\n else if (elem.mapId == _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].ROAD) {\n map[elem.my][elem.mx] = elem.arrow;\n }\n }\n }\n for (var e = 0; e < this.assets.length; e++) {\n var elem = this.assets[e];\n if (!elem.isremove) {\n if (elem.type != \"car\") {\n if (!file[elem.type])\n file[elem.type] = [];\n file[elem.type].push({\n \"x\": elem.x,\n \"y\": elem.y\n });\n }\n }\n }\n file.map = map;\n if (this.level.agent) {\n file.agent = {\n \"mx\": this.level.agent.core.mx,\n \"my\": this.level.agent.core.my,\n \"line\": this.level.agent.core.line,\n \"motion\": {\n \"type\": \"BasicMotionEngine\",\n \"options\": {\n \"rotationStep\": 0.5,\n \"actions\": [\"UP\", \"LEFT\", \"RIGHT\", \"DOWN\", \"WAIT\"]\n }\n }\n };\n }\n console.log(file);\n file = JSON.stringify(file, null, 4);\n _utils__WEBPACK_IMPORTED_MODULE_0__[\"saveAs\"](file, file_name);\n };\n return AssetManger;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/asset_manager.ts?"); + +/***/ }), + +/***/ "./src/basic_motion_engine.ts": +/*!************************************!*\ + !*** ./src/basic_motion_engine.ts ***! + \************************************/ +/*! exports provided: BasicMotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BasicMotionEngine\", function() { return BasicMotionEngine; });\n/* harmony import */ var _motion_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./motion_engine */ \"./src/motion_engine.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\nvar __extends = (undefined && undefined.__extends) || (function () {\n var extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\n\n\n\nvar BasicMotionEngine = (function (_super) {\n __extends(BasicMotionEngine, _super);\n function BasicMotionEngine(level, options) {\n var _this = _super.call(this, level) || this;\n _this.rotationStep = options.rotationStep;\n _this.actions = options.actions;\n return _this;\n }\n BasicMotionEngine.prototype.setUp = function (car, lidar) {\n this.car = car;\n this.lidar = lidar;\n this.state = [];\n for (var y = 0; y < lidar.pts; y++) {\n var line = [];\n for (var x = 0; x < lidar.pts; x++) {\n line.push(_global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].DEFAULT);\n }\n this.state.push(line);\n }\n this.setUpKeyboard();\n this.car.v = 0;\n this.detectInteractions();\n };\n BasicMotionEngine.prototype.setUpKeyboard = function () {\n var _this = this;\n var left = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](37);\n var up = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](38);\n var right = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](39);\n var down = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](40);\n if (this.actions.indexOf(\"LEFT\") != -1)\n left.press = function () { _this.turnLeft(); };\n if (this.actions.indexOf(\"RIGHT\") != -1)\n right.press = function () { _this.turnRight(); };\n if (this.actions.indexOf(\"UP\") != -1) {\n up.press = function () { _this.moveForward(); };\n up.release = function () {\n _this.car.v = 0;\n };\n }\n if (this.actions.indexOf(\"DOWN\") != -1) {\n down.press = function () { _this.moveBackward(); };\n down.release = function () {\n _this.car.v = 0;\n };\n }\n };\n BasicMotionEngine.prototype.turnLeft = function () {\n this.car.rotation -= this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BasicMotionEngine.prototype.turnRight = function () {\n this.car.rotation += this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BasicMotionEngine.prototype.moveForward = function () {\n this.car.v = 1;\n };\n BasicMotionEngine.prototype.moveBackward = function () {\n this.car.v = -1;\n };\n BasicMotionEngine.prototype.actionStep = function (delta, action) {\n if (this.actions[action] == \"LEFT\") {\n this.turnLeft();\n }\n if (this.actions[action] == \"RIGHT\") {\n this.turnRight();\n }\n if (this.actions[action] == \"UP\") {\n this.moveForward();\n }\n if (this.actions[action] == \"DOWN\") {\n this.moveBackward();\n }\n var _a = this.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n this.car.v = 0;\n return { agent_col: agent_col, on_road: on_road };\n };\n BasicMotionEngine.prototype.actionSpace = function () {\n return Array.apply(null, { length: this.actions.length }).map(Number.call, Number);\n };\n BasicMotionEngine.prototype.step = function (delta) {\n this.car.x += this.car.v * Math.cos(this.car.rotation) * delta;\n this.car.y += this.car.v * Math.sin(this.car.rotation) * delta;\n this.car.mx = Math.floor(this.car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.my = Math.floor(this.car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.checkAndsetNewRoad();\n this.lidar.x = this.car.x;\n this.lidar.y = this.car.y;\n this.lidar.rotation = this.car.rotation;\n var _a = this.detectInteractions(), agent_col = _a.agent_col, on_road = _a.on_road;\n if (agent_col.length > 0) {\n this.car.v = 0;\n this.car.vy = 0;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n return BasicMotionEngine;\n}(_motion_engine__WEBPACK_IMPORTED_MODULE_0__[\"MotionEngine\"]));\n\n\n\n//# sourceURL=webpack://metacar/./src/basic_motion_engine.ts?"); + +/***/ }), + +/***/ "./src/bot_motion_engine.ts": +/*!**********************************!*\ + !*** ./src/bot_motion_engine.ts ***! + \**********************************/ +/*! exports provided: BotMotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BotMotionEngine\", function() { return BotMotionEngine; });\n/* harmony import */ var _motion_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./motion_engine */ \"./src/motion_engine.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\nvar __extends = (undefined && undefined.__extends) || (function () {\n var extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\n\n\nvar BotMotionEngine = (function (_super) {\n __extends(BotMotionEngine, _super);\n function BotMotionEngine(level) {\n var _this = _super.call(this, level) || this;\n _this.map = _this.level.getMap();\n _this.mapSizeY = _this.map.length;\n _this.mapSizeX = _this.map[0].length;\n _this.rotationStep = 0.5;\n _this.rotationToNextCase = {};\n _this.rotationToNextCase[0] = { \"mx\": 1, \"my\": 0 };\n _this.rotationToNextCase[0.5] = { \"mx\": 0, \"my\": 1 };\n _this.rotationToNextCase[1.0] = { \"mx\": -1, \"my\": 0 };\n _this.rotationToNextCase[1.5] = { \"mx\": 0, \"my\": -1 };\n _this.rotationToNextCase[-0.5] = { \"mx\": 0, \"my\": -1 };\n _this.rotationToNextCase[-1.0] = { \"mx\": -1, \"my\": 0 };\n _this.rotationToNextCase[-1.5] = { \"mx\": 0, \"my\": 1 };\n return _this;\n }\n BotMotionEngine.prototype.setUp = function (car, lidar) {\n this.car = car;\n this.lidar = lidar;\n this.state = [];\n for (var y = 0; y < lidar.pts; y++) {\n var line = [];\n for (var x = 0; x < lidar.pts; x++) {\n line.push(_global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].DEFAULT);\n }\n this.state.push(line);\n }\n this.car.v = 0;\n this.detectInteractions();\n };\n BotMotionEngine.prototype.turnLeft = function () {\n this.car.rotation -= this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BotMotionEngine.prototype.turnRight = function () {\n this.car.rotation += this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BotMotionEngine.prototype.moveUp = function () {\n this.car.v = 1;\n };\n BotMotionEngine.prototype.moveDown = function () {\n this.car.v = -1;\n };\n BotMotionEngine.prototype.isRoad = function (nx, ny) {\n if (ny < 0 || ny >= this.mapSizeY || nx < 0 || nx >= this.mapSizeX || this.map[ny][nx] == 0) {\n return false;\n }\n return true;\n };\n BotMotionEngine.prototype.autoRotation = function () {\n var right_dist = _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] + (_global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 3);\n var left_dist = _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] - (_global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 3.5);\n var same_dist = _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n if (this.car.next_road) {\n var y_dist = Math.abs(((this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) - this.car.y) * this.car.next_road.outroad_np.my);\n var x_dist = Math.abs(((this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) - this.car.x) * this.car.next_road.outroad_np.mx);\n if (this.car.next_road.rotation_type == 0) {\n if (y_dist < right_dist && x_dist < right_dist) {\n this.car.haveTurned = true;\n this.car.rotation = this.car.rotation += Math.PI / 2;\n this.car.rotation = this.car.rotation % (2 * Math.PI);\n this.car.next_road = undefined;\n return;\n }\n }\n if (this.car.next_road.rotation_type == 1) {\n if (y_dist < left_dist && x_dist < left_dist) {\n this.car.haveTurned = true;\n this.car.rotation = this.car.rotation -= Math.PI / 2;\n this.car.rotation = this.car.rotation % (2 * Math.PI);\n this.car.next_road = undefined;\n return;\n }\n }\n if (this.car.next_road.rotation_type == 2) {\n if (y_dist < same_dist && x_dist < same_dist) {\n this.car.haveTurned = true;\n this.car.rotation = this.car.rotation -= Math.PI;\n this.car.rotation = this.car.rotation % (2 * Math.PI);\n if (y_dist != 0 && this.car.x < this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.x = this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.y = this.car.next_road.outroad.y;\n }\n else if (y_dist != 0 && this.car.x > this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.x = this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.y = this.car.next_road.outroad.y;\n }\n else if (x_dist != 0 && this.car.y < this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.y = this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.x = this.car.next_road.outroad.x;\n }\n else if (x_dist != 0 && this.car.y > this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.y = this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.x = this.car.next_road.outroad.x;\n }\n this.car.next_road = undefined;\n return;\n }\n }\n }\n else {\n var key = this.car.rotation / Math.PI;\n var key_r = ((this.car.rotation / Math.PI) + 0.5) % 2;\n var key_l = ((this.car.rotation / Math.PI) - 0.5) % 2;\n var is_next_pos = this.rotationToNextCase[key];\n var is_next_pos_r = this.rotationToNextCase[key_r];\n var is_next_pos_l = this.rotationToNextCase[key_l];\n var turn = false;\n var nx = this.car.mx + is_next_pos.mx;\n var ny = this.car.my + is_next_pos.my;\n if (!this.isRoad(nx, ny)) {\n turn = true;\n }\n else if (!this.car.haveTurned && !this.car.turnedRandom) {\n this.car.turnedRandom = Math.random();\n }\n else if (!this.car.haveTurned && this.car.turnedRandom < 0.33 && this.isRoad(this.car.mx + is_next_pos_r.mx, this.car.my + is_next_pos_r.my)) {\n turn = true;\n }\n else if (!this.car.haveTurned && this.car.turnedRandom > 0.66 && this.isRoad(this.car.mx + is_next_pos_l.mx, this.car.my + is_next_pos_l.my)) {\n turn = true;\n }\n if (turn) {\n var possibles_rotations = [(key + 0.5) % 2., (key - 0.5) % 2., null];\n for (var p = 0; p < possibles_rotations.length; p++) {\n var next_pos = void 0;\n if (possibles_rotations[p] != null) {\n next_pos = this.rotationToNextCase[possibles_rotations[p]];\n }\n else {\n next_pos = { \"mx\": 0, \"my\": 0 };\n }\n var px = this.car.mx + next_pos.mx;\n var py = this.car.my + next_pos.my;\n if (this.isRoad(px, py)) {\n this.car.next_road = {\n \"outroad\": { y: ny * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"], x: nx * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] },\n \"outroad_np\": is_next_pos,\n \"rotation_type\": p,\n };\n return;\n }\n }\n }\n }\n };\n BotMotionEngine.prototype.step = function (delta) {\n if (this.state.toString().indexOf(\",\" + _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].CAR.toString()) != -1) {\n this.car.v = 0;\n }\n else {\n this.car.v = 0.8;\n this.autoRotation();\n }\n this.car.x += this.car.v * Math.cos(this.car.rotation) * delta;\n this.car.y += this.car.v * Math.sin(this.car.rotation) * delta;\n this.car.mx = Math.floor(this.car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.my = Math.floor(this.car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.checkAndsetNewRoad();\n this.lidar.x = this.car.x;\n this.lidar.y = this.car.y;\n this.lidar.rotation = this.car.rotation;\n var _a = this.detectInteractions(), agent_col = _a.agent_col, on_road = _a.on_road;\n if (agent_col.length > 0) {\n this.car.v = 0;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n return BotMotionEngine;\n}(_motion_engine__WEBPACK_IMPORTED_MODULE_0__[\"MotionEngine\"]));\n\n\n\n//# sourceURL=webpack://metacar/./src/bot_motion_engine.ts?"); + +/***/ }), + +/***/ "./src/car.ts": +/*!********************!*\ + !*** ./src/car.ts ***! + \********************/ +/*! exports provided: Car */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Car\", function() { return Car; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar Global_carId = 0;\nvar Car = (function () {\n function Car(level, info, textures, options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n this.level = level;\n options.image = options.image || _global__WEBPACK_IMPORTED_MODULE_0__[\"CAR_IMG\"].DEFAULT;\n options.lidar = options.lidar || false;\n options.lidarInfo = options.lidarInfo || { pts: 5, width: 4, height: 5, pos: 0 };\n this.core = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"](textures[options.image]);\n this.info = info;\n this.core.scale.x = 0.8;\n this.core.scale.y = 0.8;\n this.core.anchor.x = 0.5;\n this.core.anchor.y = 0.5;\n this.core.road = undefined;\n this.core.carId = Global_carId;\n Global_carId += 1;\n this.core.agent = false;\n this.core.obstacle = true;\n this.core.mapId = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].CAR;\n if (options.lidar) {\n this.createLidar(options.lidarInfo);\n this.core.lidar = this.lidar;\n }\n if (options.motionEngine) {\n this.motion = options.motionEngine;\n this.motion.setUp(this.core, this.lidar);\n this.core.rotationStep = 0.5;\n }\n else {\n this.core.rotationStep = 0.5;\n }\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n this.core.x = (this.info.mx) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.y = (this.info.my) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.checkAndsetNewRoad = function (road) { return _this.checkAndsetNewRoad(road); };\n var road = this.level.getRoad(this.core.my, this.core.mx);\n this.core.line = 0;\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n }\n Car.prototype.checkAndsetNewRoad = function (n_road) {\n var current_road = this.core.road;\n if (!n_road) {\n n_road = this.level.getRoad(this.core.my, this.core.mx);\n ;\n }\n if (n_road != current_road) {\n if (current_road) {\n current_road.cars.splice(current_road.cars.indexOf(this.core.carId), 1);\n }\n this.core.road = n_road;\n this.core.haveTurned = false;\n this.turnedRandom = undefined;\n if (n_road)\n n_road.cars.push(this.core.carId);\n }\n };\n Car.prototype.reset = function () {\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n var road = this.level.getRoad(this.core.my, this.core.mx);\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n };\n Car.prototype.getState = function () {\n return this.motion.state.map(function (arr) { return arr.slice(); });\n };\n Car.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n if (action == null) {\n var _a = this.motion.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n }\n else {\n var _b = this.motion.actionStep(delta, action), agent_col = _b.agent_col, on_road = _b.on_road;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n Car.prototype.createLidar = function (lidarOptions) {\n this.lidar = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Container\"]();\n var area = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n area.pt = false;\n area.alpha = 0.5;\n area.beginFill(0x515151);\n area.drawRect(0, 0, this.core.width * lidarOptions.width, this.core.height * lidarOptions.height);\n area.endFill();\n var x_step = area.width / lidarOptions.pts;\n var y_step = area.height / lidarOptions.pts;\n for (var xs = lidarOptions.pts - 1; xs >= 0; xs--) {\n for (var ys = 0; ys < lidarOptions.pts; ys++) {\n var x = (x_step / 4) + xs * x_step;\n var y = (y_step / 4) + ys * y_step;\n var pt = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n pt.pt = true;\n pt.beginFill(0xffffff);\n pt.drawRect(x, y, 5, 5);\n pt.endFill();\n this.lidar.addChild(pt);\n }\n }\n this.lidar.pts = lidarOptions.pts;\n this.lidar.addChild(area);\n this.lidar.x = this.core.x;\n this.lidar.y = this.core.y;\n this.lidar.pivot.y = this.lidar.height / 2;\n this.lidar.pivot.x = this.core.width / 2 - (lidarOptions.pos * this.core.width);\n this.lidar.rotation = this.core.rotation;\n };\n return Car;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/car.ts?"); + +/***/ }), + +/***/ "./src/control_motion_engine.ts": +/*!**************************************!*\ + !*** ./src/control_motion_engine.ts ***! + \**************************************/ +/*! exports provided: ControlMotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ControlMotionEngine\", function() { return ControlMotionEngine; });\n/* harmony import */ var _motion_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./motion_engine */ \"./src/motion_engine.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\nvar __extends = (undefined && undefined.__extends) || (function () {\n var extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\n\n\n\nvar ControlMotionEngine = (function (_super) {\n __extends(ControlMotionEngine, _super);\n function ControlMotionEngine(level) {\n var _this = _super.call(this, level) || this;\n _this.level = level;\n _this.actions = [\"SteeringAngle\", \"Throttle\"];\n return _this;\n }\n ControlMotionEngine.prototype.setUp = function (car, lidar) {\n this.car = car;\n this.lidar = lidar;\n this.state = [];\n for (var y = 0; y < lidar.pts; y++) {\n var line = [];\n for (var x = 0; x < lidar.pts; x++) {\n line.push(_global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].DEFAULT);\n }\n this.state.push(line);\n }\n this.setUpKeyboard();\n this.car.v = 0;\n this.car.a = 0;\n this.car.yaw_rate = 0;\n this.detectInteractions();\n };\n ControlMotionEngine.prototype.setUpKeyboard = function () {\n var _this = this;\n var left = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](37);\n var up = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](38);\n var right = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](39);\n var down = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](40);\n left.press = function () {\n _this.turn(-0.5);\n };\n left.release = function () {\n _this.turn(0);\n };\n right.press = function () {\n _this.turn(0.5);\n };\n right.release = function () {\n _this.turn(0);\n };\n up.press = function () { _this.move(1); };\n up.release = function () {\n _this.car.a = 0;\n };\n down.press = function () { _this.move(-1); };\n down.release = function () {\n _this.car.a = 0;\n };\n };\n ControlMotionEngine.prototype.turn = function (value) {\n this.car.yaw_rate = value;\n };\n ControlMotionEngine.prototype.move = function (throttle) {\n this.car.a = throttle;\n };\n ControlMotionEngine.prototype.actionStep = function (delta, actions) {\n this.car.a = Math.min(Math.max(parseInt(actions[0].toString()), -1), 1);\n this.car.yaw_rate = Math.min(Math.max(parseInt(actions[1].toString()), -1), 1);\n var _a = this.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n this.car.a = 0;\n this.car.yaw_rate = 0;\n return { agent_col: agent_col, on_road: on_road };\n };\n ControlMotionEngine.prototype.actionSpace = function () {\n return Array.apply(null, { length: this.actions.length }).map(Number.call, Number);\n };\n ControlMotionEngine.prototype.step = function (delta) {\n if (this.car.v > 0)\n this.car.v = Math.max(0, this.car.v - 0.01);\n else if (this.car.v < 0)\n this.car.v = Math.min(0, this.car.v + 0.01);\n if (this.car.a > 0)\n this.car.v = Math.min(2., this.car.v + this.car.a * 0.02);\n else\n this.car.v = Math.max(-2., this.car.v + this.car.a * 0.02);\n if (this.car.yaw_rate == 0) {\n this.car.x += this.car.v * Math.cos(this.car.rotation) * delta;\n this.car.y += this.car.v * Math.sin(this.car.rotation) * delta;\n }\n else {\n var yr = this.car.yaw_rate * 0.01 * (this.car.v + 0.001) * Math.PI;\n this.car.x += (this.car.v / yr) * (Math.sin(this.car.rotation + (yr * delta)) - Math.sin(this.car.rotation));\n this.car.y += (this.car.v / yr) * (Math.cos(this.car.rotation) - Math.cos(this.car.rotation + (yr * delta)));\n this.car.rotation += yr * delta;\n }\n this.car.mx = Math.floor(this.car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.my = Math.floor(this.car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.checkAndsetNewRoad();\n this.lidar.x = this.car.x;\n this.lidar.y = this.car.y;\n this.lidar.rotation = this.car.rotation;\n var _a = this.detectInteractions(), agent_col = _a.agent_col, on_road = _a.on_road;\n if (agent_col.length > 0) {\n this.car.v = 0;\n this.car.vy = 0;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n return ControlMotionEngine;\n}(_motion_engine__WEBPACK_IMPORTED_MODULE_0__[\"MotionEngine\"]));\n\n\n\n//# sourceURL=webpack://metacar/./src/control_motion_engine.ts?"); + +/***/ }), + +/***/ "./src/embedded.ts": +/*!*************************!*\ + !*** ./src/embedded.ts ***! + \*************************/ +/*! exports provided: embeddedUrl, embeddedContent */ +/***/ (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?"); + +/***/ }), + +/***/ "./src/embedded/level/full_city.ts": +/*!*****************************************!*\ + !*** ./src/embedded/level/full_city.ts ***! + \*****************************************/ +/*! exports provided: fullCity */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"fullCity\", function() { return fullCity; });\nvar fullCity = {\n \"cars\": [\n {\n \"mx\": 2,\n \"my\": 5,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 3,\n \"my\": 4,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 3,\n \"my\": 4,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 6,\n \"my\": 3,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 6,\n \"my\": 3,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 8,\n \"my\": 2,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 8,\n \"my\": 2,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 2,\n \"my\": 7,\n \"line\": 0,\n \"auto\": true\n }\n ],\n \"house\": [\n {\n \"x\": 9,\n \"y\": 409\n },\n {\n \"x\": 146,\n \"y\": 162\n },\n {\n \"x\": 439,\n \"y\": 39\n }\n ],\n \"house2\": [\n {\n \"x\": 425,\n \"y\": 192\n },\n {\n \"x\": 431,\n \"y\": 354\n }\n ],\n \"house3\": [\n {\n \"x\": 426,\n \"y\": 281\n },\n {\n \"x\": 51,\n \"y\": 157\n },\n {\n \"x\": 553,\n \"y\": 34\n }\n ],\n \"bench\": [\n {\n \"x\": 259,\n \"y\": 206\n },\n {\n \"x\": 8,\n \"y\": 205\n }\n ],\n \"tree\": [\n {\n \"x\": 1,\n \"y\": 303\n },\n {\n \"x\": 54,\n \"y\": 357\n },\n {\n \"x\": 215,\n \"y\": 325\n },\n {\n \"x\": 230,\n \"y\": 400\n },\n {\n \"x\": 282,\n \"y\": 368\n },\n {\n \"x\": 182,\n \"y\": 433\n },\n {\n \"x\": 285,\n \"y\": 309\n },\n {\n \"x\": 576,\n \"y\": 233\n },\n {\n \"x\": 581,\n \"y\": 300\n },\n {\n \"x\": 519,\n \"y\": 388\n },\n {\n \"x\": 582,\n \"y\": 391\n },\n {\n \"x\": 256,\n \"y\": 69\n },\n {\n \"x\": 151,\n \"y\": 43\n },\n {\n \"x\": 77,\n \"y\": 77\n },\n {\n \"x\": 26,\n \"y\": 24\n },\n {\n \"x\": 189,\n \"y\": 98\n }\n ],\n \"map\": [\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↠\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↦\",\n \"↔\",\n \"↔\",\n \"↟\",\n \"↔\"\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n \"↔\",\n \"↔\",\n \"↧\",\n \"↔\",\n \"↠\",\n \"↔\",\n \"↤\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n \"↠\",\n 0,\n 0,\n 0,\n \"↠\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ]\n ]\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded/level/full_city.ts?"); + +/***/ }), + +/***/ "./src/global.ts": +/*!***********************!*\ + !*** ./src/global.ts ***! + \***********************/ +/*! exports provided: Application, Loader, Resources, Sprite, Graphics, Container, JSON_TEXTURES, LEVEL_FOLDER, ROADSIZE, CAR_IMG, MAP, ASSETS */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Application\", function() { return Application; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Loader\", function() { return Loader; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Resources\", function() { return Resources; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Sprite\", function() { return Sprite; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Graphics\", function() { return Graphics; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Container\", function() { return Container; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"JSON_TEXTURES\", function() { return JSON_TEXTURES; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LEVEL_FOLDER\", function() { return LEVEL_FOLDER; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ROADSIZE\", function() { return ROADSIZE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"CAR_IMG\", function() { return CAR_IMG; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MAP\", function() { return MAP; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ASSETS\", function() { return ASSETS; });\n/* harmony import */ var pixi_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! pixi.js */ \"pixi.js\");\n/* harmony import */ var pixi_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(pixi_js__WEBPACK_IMPORTED_MODULE_0__);\n\nvar Application = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Application\"];\nvar Loader = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"loader\"];\nvar Resources = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"loader\"].resources;\nvar Sprite = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"];\nvar Graphics = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"];\nvar Container = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Container\"];\nvar JSON_TEXTURES = \"public/textures/textures.json\";\nvar LEVEL_FOLDER = \"/level/\";\nvar ROADSIZE = 60;\nvar CAR_IMG = {\n DEFAULT: \"car.png\",\n AGENT: \"car_agent.png\"\n};\nvar MAP = {\n ROAD: -1,\n DEFAULT: 0,\n CAR: 1,\n AGENT: 1,\n};\nvar ASSETS = {\n ROADS: {\n \"↕\": {\n \"image\": \"road_u.png\",\n \"orientation\": 1.5\n },\n \"↔\": {\n \"image\": \"road_r.png\",\n \"orientation\": 0.\n },\n \"↱\": {\n \"image\": \"road_rotate_ld.png\",\n \"orientation\": 1.25\n },\n \"↰\": {\n \"image\": \"road_rotate_ul.png\",\n \"orientation\": 0.75\n },\n \"↲\": {\n \"image\": \"road_rotate_rl.png\",\n \"orientation\": 0.25\n },\n \"↳\": {\n \"image\": \"road_rotate_dl.png\",\n \"orientation\": 1.75\n },\n \"↟\": {\n \"image\": \"road_up.png\",\n \"orientation\": 1.5\n },\n \"↠\": {\n \"image\": \"road_rp.png\",\n \"orientation\": 0.\n },\n \"↤\": {\n \"image\": \"road_r2.png\",\n \"orientation\": 0.\n },\n \"↦\": {\n \"image\": \"road_l2.png\",\n \"orientation\": 1.\n },\n \"↥\": {\n \"image\": \"road_d2.png\",\n \"orientation\": 0.5\n },\n \"↧\": {\n \"image\": \"road_u2.png\",\n \"orientation\": 1.5\n },\n },\n \"house\": {\n \"image\": \"house.png\"\n },\n \"house2\": {\n \"image\": \"house2.png\"\n },\n \"house3\": {\n \"image\": \"house3.png\"\n },\n \"bench\": {\n \"image\": \"bench.png\"\n },\n \"tree\": {\n \"image\": \"tree.png\"\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/global.ts?"); + +/***/ }), + +/***/ "./src/index.ts": +/*!**********************!*\ + !*** ./src/index.ts ***! + \**********************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _metacar__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./metacar */ \"./src/metacar.ts\");\n/* harmony import */ var _embedded__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./embedded */ \"./src/embedded.ts\");\n\n\nvar metacar = {\n env: _metacar__WEBPACK_IMPORTED_MODULE_0__[\"MetaCar\"],\n level: _embedded__WEBPACK_IMPORTED_MODULE_1__[\"embeddedUrl\"]\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (metacar);\n\n\n//# sourceURL=webpack://metacar/./src/index.ts?"); + +/***/ }), + +/***/ "./src/level.ts": +/*!**********************!*\ + !*** ./src/level.ts ***! + \**********************/ +/*! exports provided: Level */ +/***/ (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?"); + +/***/ }), + +/***/ "./src/metacar.ts": +/*!************************!*\ + !*** ./src/metacar.ts ***! + \************************/ +/*! exports provided: MetaCar */ +/***/ (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?"); + +/***/ }), + +/***/ "./src/motion_engine.ts": +/*!******************************!*\ + !*** ./src/motion_engine.ts ***! + \******************************/ +/*! exports provided: MotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MotionEngine\", function() { return MotionEngine; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar MotionEngine = (function () {\n function MotionEngine(level) {\n this.level = level;\n }\n MotionEngine.prototype.boxesIntersect = function (a, b) {\n var ab = a.getBounds();\n var bb = b.getBounds();\n return ab.x + ab.width > bb.x && ab.x < bb.x + bb.width && ab.y + ab.height > bb.y && ab.y < bb.y + bb.height;\n };\n MotionEngine.prototype.detectInteractions = function () {\n var envs = this.level.getEnvs();\n var agent_col = [];\n var lidar_collisions = [];\n var on_road = false;\n for (var i = 0; i < envs.length; i++) {\n if (envs[i] != this.car && envs[i].obstacle && this.boxesIntersect(envs[i], this.car)) {\n agent_col.push(envs[i]);\n }\n else if (envs[i].mapId == _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].ROAD && this.boxesIntersect(envs[i], this.car)) {\n on_road = true;\n }\n if (this.boxesIntersect(envs[i], this.lidar)) {\n lidar_collisions.push(envs[i]);\n }\n }\n this.setState(lidar_collisions);\n return { agent_col: agent_col, on_road: on_road };\n };\n MotionEngine.prototype.setState = function (lidar_collisions) {\n var pt_id = 0;\n for (var i = 0; i < this.lidar.children.length; i++) {\n this.lidar.children[i].alpha = 0.1;\n if (this.lidar.children[i].pt) {\n var pt_y = Math.floor(pt_id / this.lidar.pts);\n var pt_x = Math.floor(pt_id % this.lidar.pts);\n this.state[pt_y][pt_x] = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].DEFAULT;\n for (var a = 0; a < lidar_collisions.length; a++) {\n if (lidar_collisions[a] != this.car) {\n var touch = this.boxesIntersect(lidar_collisions[a], this.lidar.children[i]);\n if (touch && lidar_collisions[a].obstacle) {\n this.lidar.children[i].alpha = 1.;\n }\n if (touch && (lidar_collisions[a].mapId > this.state[pt_y][pt_x] || (lidar_collisions[a].mapId == _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].ROAD && this.state[pt_y][pt_x] == _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].DEFAULT))) {\n this.state[pt_y][pt_x] = lidar_collisions[a].mapId;\n }\n }\n }\n pt_id += 1;\n }\n }\n };\n return MotionEngine;\n}());\n\n;\n\n\n//# sourceURL=webpack://metacar/./src/motion_engine.ts?"); + +/***/ }), + +/***/ "./src/utils.ts": +/*!**********************!*\ + !*** ./src/utils.ts ***! + \**********************/ +/*! exports provided: loadJSON, loadEmbeddedURL, loadLocalStorageURL, loadCustomURL, mod, argMax, mean, saveAs, 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?"); + +/***/ }), + +/***/ "pixi.js": +/*!***********************!*\ + !*** external "PIXI" ***! + \***********************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +eval("(function() { module.exports = window[\"PIXI\"]; }());\n\n//# sourceURL=webpack://metacar/external_%22PIXI%22?"); + +/***/ }) + +/******/ })["default"]; \ No newline at end of file diff --git a/demo/package.json b/demo/package.json index f8eec2a..94c086d 100644 --- a/demo/package.json +++ b/demo/package.json @@ -9,6 +9,7 @@ "author": "Thibault Neveu", "license": "ISC", "dependencies": { - "express": "^4.16.3" + "express": "^4.16.3", + "pixi.js": "^4.8.1" } } diff --git a/demo/webapp/index.html b/demo/webapp/index.html index ef6037b..df876a0 100644 --- a/demo/webapp/index.html +++ b/demo/webapp/index.html @@ -5,6 +5,26 @@ Hello World + +
+ +
+ + + + + + + +
+
+ +
+ + + + + diff --git a/demo/webapp/public/js/full_city.js b/demo/webapp/public/js/full_city.js new file mode 100644 index 0000000..3eae13e --- /dev/null +++ b/demo/webapp/public/js/full_city.js @@ -0,0 +1,8 @@ +// Get the url of the desired level +let levelUrl = metacar.level.fullCity; +// Create the environement (canvasID, levelUrl) +var env = new metacar.env("canvas", levelUrl); +env.load().then(() => { + // The level is loaded + +}); \ No newline at end of file diff --git a/demo/webapp/public/textures/textures.json b/demo/webapp/public/textures/textures.json new file mode 100644 index 0000000..965c7c8 --- /dev/null +++ b/demo/webapp/public/textures/textures.json @@ -0,0 +1,183 @@ +{"frames": { + +"bench.png": +{ + "frame": {"x":0,"y":0,"w":31,"h":16}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":31,"h":16}, + "sourceSize": {"w":31,"h":16}, + "pivot": {"x":0.5,"y":0.5} +}, +"car.png": +{ + "frame": {"x":31,"y":0,"w":42,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":24}, + "sourceSize": {"w":42,"h":24}, + "pivot": {"x":0.5,"y":0.5} +}, +"car_agent.png": +{ + "frame": {"x":73,"y":0,"w":42,"h":24}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":42,"h":24}, + "sourceSize": {"w":42,"h":24}, + "pivot": {"x":0.5,"y":0.5} +}, +"house.png": +{ + "frame": {"x":0,"y":469,"w":88,"h":62}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":88,"h":62}, + "sourceSize": {"w":88,"h":62}, + "pivot": {"x":0.5,"y":0.5} +}, +"house2.png": +{ + "frame": {"x":0,"y":264,"w":60,"h":85}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":85}, + "sourceSize": {"w":60,"h":85}, + "pivot": {"x":0.5,"y":0.5} +}, +"house3.png": +{ + "frame": {"x":0,"y":531,"w":89,"h":67}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":89,"h":67}, + "sourceSize": {"w":89,"h":67}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_d2.png": +{ + "frame": {"x":0,"y":349,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_l2.png": +{ + "frame": {"x":60,"y":264,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_r.png": +{ + "frame": {"x":0,"y":409,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_r2.png": +{ + "frame": {"x":60,"y":409,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_rotate_dl.png": +{ + "frame": {"x":60,"y":349,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_rotate_ld.png": +{ + "frame": {"x":60,"y":204,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_rotate_rl.png": +{ + "frame": {"x":0,"y":84,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_rotate_ul.png": +{ + "frame": {"x":48,"y":24,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_rp.png": +{ + "frame": {"x":60,"y":84,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_u.png": +{ + "frame": {"x":0,"y":204,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_u2.png": +{ + "frame": {"x":0,"y":144,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"road_up.png": +{ + "frame": {"x":60,"y":144,"w":60,"h":60}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":60,"h":60}, + "sourceSize": {"w":60,"h":60}, + "pivot": {"x":0.5,"y":0.5} +}, +"tree.png": +{ + "frame": {"x":0,"y":24,"w":48,"h":46}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":48,"h":46}, + "sourceSize": {"w":48,"h":46}, + "pivot": {"x":0.5,"y":0.5} +}}, +"meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "1.0", + "image": "textures.png", + "format": "RGBA8888", + "size": {"w":120,"h":598}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:8bfcaef7ab9440b3c4c801d035ca0e1a:71d4ef3f85e164cd8a50ee71cd767fd7:cf827d152df04949dfee256cd0c8efd8$" +} +} diff --git a/demo/webapp/public/textures/textures.png b/demo/webapp/public/textures/textures.png new file mode 100644 index 0000000..aa715b1 Binary files /dev/null and b/demo/webapp/public/textures/textures.png differ diff --git a/dist/metacar.min.js b/dist/metacar.min.js new file mode 100644 index 0000000..c8a11f2 --- /dev/null +++ b/dist/metacar.min.js @@ -0,0 +1,257 @@ +window["metacar"] = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.ts"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./src/asset_manager.ts": +/*!******************************!*\ + !*** ./src/asset_manager.ts ***! + \******************************/ +/*! exports provided: AssetManger */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"AssetManger\", function() { return AssetManger; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _car__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./car */ \"./src/car.ts\");\n/* harmony import */ var _basic_motion_engine__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./basic_motion_engine */ \"./src/basic_motion_engine.ts\");\n/* harmony import */ var _control_motion_engine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./control_motion_engine */ \"./src/control_motion_engine.ts\");\n/* harmony import */ var _bot_motion_engine__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./bot_motion_engine */ \"./src/bot_motion_engine.ts\");\n\n\n\n\n\n\n;\nvar AssetManger = (function () {\n function AssetManger(level) {\n this.assets = [];\n this.level = level;\n this.motion = {\n \"BasicMotionEngine\": _basic_motion_engine__WEBPACK_IMPORTED_MODULE_3__[\"BasicMotionEngine\"],\n \"ControlMotionEngine\": _control_motion_engine__WEBPACK_IMPORTED_MODULE_4__[\"ControlMotionEngine\"]\n };\n }\n AssetManger.prototype.createRoadSide = function (info, textures) {\n var x = (info.mx) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n var y = (info.my) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n var area = new _global__WEBPACK_IMPORTED_MODULE_1__[\"Graphics\"]();\n area.beginFill(0xe8e8e8);\n area.drawRoundedRect(0, 0, _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] + 30, _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] + 30, undefined);\n area.x = x - 15;\n area.y = y - 15;\n area.endFill();\n this.level.addChild(area);\n };\n AssetManger.prototype.createRoad = function (info, textures) {\n var _this = this;\n var road = new _global__WEBPACK_IMPORTED_MODULE_1__[\"Sprite\"](textures[_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[info.type].image]);\n road.x = (info.mx) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n road.y = (info.my) * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n road.obstacle = false;\n road.mapId = _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].ROAD;\n road.orientation = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[info.type].orientation;\n road.setCarPosition = function (car, line) { return _this.setCarOnRoad(road, car, line); };\n road.cars = [];\n road.mx = info.mx;\n road.my = info.my;\n this.level.addRoad(road);\n };\n AssetManger.prototype.setCarOnRoad = function (road, car, line) {\n if (line == undefined)\n line = 0;\n var carById = this.level.findCarById(road.cars[0]);\n if (road.cars.length >= 1 && carById && carById.core.line == line) {\n line = line == 0 ? 1 : 0;\n }\n if (road.cars.length >= 2) {\n car.is_valid = false;\n return;\n }\n car.line = line;\n car.x = road.x;\n car.y = road.y;\n car.x += _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2;\n car.y += _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2;\n var x_margin = 0;\n var y_margin = (_global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] * 1 / 4);\n road.orientation = (Math.floor(road.orientation / car.rotationStep) * car.rotationStep);\n var th = -road.orientation * (Math.PI);\n var x_m = (Math.cos(th) * x_margin) - (y_margin * Math.sin(th));\n var y_m = (Math.cos(th) * y_margin) + (x_margin * Math.sin(th));\n var line_side_factor = line == 0 ? 1 : -1;\n var line_side_factor_t = line == 0 ? 0 : Math.PI;\n car.x += line_side_factor * Math.round(x_m);\n car.y += line_side_factor * Math.round(y_m);\n car.mx = Math.floor(car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n car.my = Math.floor(car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n car.rotation = (th + line_side_factor_t);\n car.checkAndsetNewRoad(road);\n };\n AssetManger.prototype.createAsset = function (img, info, textures, type) {\n var asset = new _global__WEBPACK_IMPORTED_MODULE_1__[\"Sprite\"](textures[img]);\n asset.obstacle = false;\n asset.type = type;\n asset.mapId = 0;\n asset.x = info.x;\n asset.y = info.y;\n this.level.addChild(asset);\n this.assets.push(asset);\n };\n AssetManger.prototype.createMap = function (map, info, textures, roadside) {\n if (roadside === void 0) { roadside = true; }\n if (roadside) {\n for (var my = 0; my < map.length; my++) {\n for (var mx = 0; mx < map[my].length; mx++) {\n if (_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[map[my][mx]]) {\n this.createRoadSide({ mx: mx, my: my, type: map[my][mx] }, textures);\n }\n }\n }\n }\n for (var my = 0; my < map.length; my++) {\n for (var mx = 0; mx < map[my].length; mx++) {\n if (_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"].ROADS[map[my][mx]]) {\n this.createRoad({ mx: mx, my: my, type: map[my][mx] }, textures);\n }\n }\n }\n for (var key in _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"]) {\n if (key != \"ROADS\" && info[key]) {\n for (var a = 0; a < info[key].length; a++) {\n this.createAsset(_global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image, info[key][a], textures, key);\n }\n }\n }\n };\n AssetManger.prototype.createCars = function (map, info, textures) {\n for (var c in info.cars) {\n var options = { lidar: true, lidarInfo: { pts: 2, width: 0.5, height: 1, pos: 1 } };\n if (info.cars[c].auto) {\n options.lidar = true;\n options.motionEngine = new _bot_motion_engine__WEBPACK_IMPORTED_MODULE_5__[\"BotMotionEngine\"](this.level);\n }\n var n_car = new _car__WEBPACK_IMPORTED_MODULE_2__[\"Car\"](this.level, info.cars[c], textures, options);\n this.level.addCar(n_car);\n }\n };\n AssetManger.prototype.createAgent = function (map, info, textures) {\n var agent = new _car__WEBPACK_IMPORTED_MODULE_2__[\"Car\"](this.level, info.agent, textures, {\n image: _global__WEBPACK_IMPORTED_MODULE_1__[\"CAR_IMG\"].AGENT,\n lidar: true,\n motionEngine: new this.motion[info.agent.motion.type](this.level, info.agent.motion.options)\n });\n this.level.addChild(agent.lidar);\n this.level.addCar(agent);\n agent.core.agent = true;\n return agent;\n };\n AssetManger.prototype.addAsset = function (asset) {\n this.assets.push(asset);\n };\n AssetManger.prototype.exportMap = function (width, height, file_name) {\n var file = { \"cars\": [] };\n var map = [];\n var envs = this.level.getEnvs();\n for (var y = 0; y < height; y++) {\n var line = [];\n for (var x = 0; x < width; x++) {\n line.push(0);\n }\n map.push(line);\n }\n for (var e = 0; e < envs.length; e++) {\n var elem = envs[e];\n if (!elem.isremove) {\n if (elem.mapId == _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].CAR && !elem.agent && elem.is_valid) {\n file.cars.push({\n \"mx\": elem.mx,\n \"my\": elem.my,\n \"line\": elem.line\n });\n }\n else if (elem.mapId == _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].ROAD) {\n map[elem.my][elem.mx] = elem.arrow;\n }\n }\n }\n for (var e = 0; e < this.assets.length; e++) {\n var elem = this.assets[e];\n if (!elem.isremove) {\n if (elem.type != \"car\") {\n if (!file[elem.type])\n file[elem.type] = [];\n file[elem.type].push({\n \"x\": elem.x,\n \"y\": elem.y\n });\n }\n }\n }\n file.map = map;\n if (this.level.agent) {\n file.agent = {\n \"mx\": this.level.agent.core.mx,\n \"my\": this.level.agent.core.my,\n \"line\": this.level.agent.core.line,\n \"motion\": {\n \"type\": \"BasicMotionEngine\",\n \"options\": {\n \"rotationStep\": 0.5,\n \"actions\": [\"UP\", \"LEFT\", \"RIGHT\", \"DOWN\", \"WAIT\"]\n }\n }\n };\n }\n console.log(file);\n file = JSON.stringify(file, null, 4);\n _utils__WEBPACK_IMPORTED_MODULE_0__[\"saveAs\"](file, file_name);\n };\n return AssetManger;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/asset_manager.ts?"); + +/***/ }), + +/***/ "./src/basic_motion_engine.ts": +/*!************************************!*\ + !*** ./src/basic_motion_engine.ts ***! + \************************************/ +/*! exports provided: BasicMotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BasicMotionEngine\", function() { return BasicMotionEngine; });\n/* harmony import */ var _motion_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./motion_engine */ \"./src/motion_engine.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\nvar __extends = (undefined && undefined.__extends) || (function () {\n var extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\n\n\n\nvar BasicMotionEngine = (function (_super) {\n __extends(BasicMotionEngine, _super);\n function BasicMotionEngine(level, options) {\n var _this = _super.call(this, level) || this;\n _this.rotationStep = options.rotationStep;\n _this.actions = options.actions;\n return _this;\n }\n BasicMotionEngine.prototype.setUp = function (car, lidar) {\n this.car = car;\n this.lidar = lidar;\n this.state = [];\n for (var y = 0; y < lidar.pts; y++) {\n var line = [];\n for (var x = 0; x < lidar.pts; x++) {\n line.push(_global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].DEFAULT);\n }\n this.state.push(line);\n }\n this.setUpKeyboard();\n this.car.v = 0;\n this.detectInteractions();\n };\n BasicMotionEngine.prototype.setUpKeyboard = function () {\n var _this = this;\n var left = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](37);\n var up = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](38);\n var right = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](39);\n var down = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](40);\n if (this.actions.indexOf(\"LEFT\") != -1)\n left.press = function () { _this.turnLeft(); };\n if (this.actions.indexOf(\"RIGHT\") != -1)\n right.press = function () { _this.turnRight(); };\n if (this.actions.indexOf(\"UP\") != -1) {\n up.press = function () { _this.moveForward(); };\n up.release = function () {\n _this.car.v = 0;\n };\n }\n if (this.actions.indexOf(\"DOWN\") != -1) {\n down.press = function () { _this.moveBackward(); };\n down.release = function () {\n _this.car.v = 0;\n };\n }\n };\n BasicMotionEngine.prototype.turnLeft = function () {\n this.car.rotation -= this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BasicMotionEngine.prototype.turnRight = function () {\n this.car.rotation += this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BasicMotionEngine.prototype.moveForward = function () {\n this.car.v = 1;\n };\n BasicMotionEngine.prototype.moveBackward = function () {\n this.car.v = -1;\n };\n BasicMotionEngine.prototype.actionStep = function (delta, action) {\n if (this.actions[action] == \"LEFT\") {\n this.turnLeft();\n }\n if (this.actions[action] == \"RIGHT\") {\n this.turnRight();\n }\n if (this.actions[action] == \"UP\") {\n this.moveForward();\n }\n if (this.actions[action] == \"DOWN\") {\n this.moveBackward();\n }\n var _a = this.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n this.car.v = 0;\n return { agent_col: agent_col, on_road: on_road };\n };\n BasicMotionEngine.prototype.actionSpace = function () {\n return Array.apply(null, { length: this.actions.length }).map(Number.call, Number);\n };\n BasicMotionEngine.prototype.step = function (delta) {\n this.car.x += this.car.v * Math.cos(this.car.rotation) * delta;\n this.car.y += this.car.v * Math.sin(this.car.rotation) * delta;\n this.car.mx = Math.floor(this.car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.my = Math.floor(this.car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.checkAndsetNewRoad();\n this.lidar.x = this.car.x;\n this.lidar.y = this.car.y;\n this.lidar.rotation = this.car.rotation;\n var _a = this.detectInteractions(), agent_col = _a.agent_col, on_road = _a.on_road;\n if (agent_col.length > 0) {\n this.car.v = 0;\n this.car.vy = 0;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n return BasicMotionEngine;\n}(_motion_engine__WEBPACK_IMPORTED_MODULE_0__[\"MotionEngine\"]));\n\n\n\n//# sourceURL=webpack://metacar/./src/basic_motion_engine.ts?"); + +/***/ }), + +/***/ "./src/bot_motion_engine.ts": +/*!**********************************!*\ + !*** ./src/bot_motion_engine.ts ***! + \**********************************/ +/*! exports provided: BotMotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BotMotionEngine\", function() { return BotMotionEngine; });\n/* harmony import */ var _motion_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./motion_engine */ \"./src/motion_engine.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\nvar __extends = (undefined && undefined.__extends) || (function () {\n var extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\n\n\nvar BotMotionEngine = (function (_super) {\n __extends(BotMotionEngine, _super);\n function BotMotionEngine(level) {\n var _this = _super.call(this, level) || this;\n _this.map = _this.level.getMap();\n _this.mapSizeY = _this.map.length;\n _this.mapSizeX = _this.map[0].length;\n _this.rotationStep = 0.5;\n _this.rotationToNextCase = {};\n _this.rotationToNextCase[0] = { \"mx\": 1, \"my\": 0 };\n _this.rotationToNextCase[0.5] = { \"mx\": 0, \"my\": 1 };\n _this.rotationToNextCase[1.0] = { \"mx\": -1, \"my\": 0 };\n _this.rotationToNextCase[1.5] = { \"mx\": 0, \"my\": -1 };\n _this.rotationToNextCase[-0.5] = { \"mx\": 0, \"my\": -1 };\n _this.rotationToNextCase[-1.0] = { \"mx\": -1, \"my\": 0 };\n _this.rotationToNextCase[-1.5] = { \"mx\": 0, \"my\": 1 };\n return _this;\n }\n BotMotionEngine.prototype.setUp = function (car, lidar) {\n this.car = car;\n this.lidar = lidar;\n this.state = [];\n for (var y = 0; y < lidar.pts; y++) {\n var line = [];\n for (var x = 0; x < lidar.pts; x++) {\n line.push(_global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].DEFAULT);\n }\n this.state.push(line);\n }\n this.car.v = 0;\n this.detectInteractions();\n };\n BotMotionEngine.prototype.turnLeft = function () {\n this.car.rotation -= this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BotMotionEngine.prototype.turnRight = function () {\n this.car.rotation += this.rotationStep * Math.PI;\n this.lidar.rotation = this.car.rotation;\n };\n BotMotionEngine.prototype.moveUp = function () {\n this.car.v = 1;\n };\n BotMotionEngine.prototype.moveDown = function () {\n this.car.v = -1;\n };\n BotMotionEngine.prototype.isRoad = function (nx, ny) {\n if (ny < 0 || ny >= this.mapSizeY || nx < 0 || nx >= this.mapSizeX || this.map[ny][nx] == 0) {\n return false;\n }\n return true;\n };\n BotMotionEngine.prototype.autoRotation = function () {\n var right_dist = _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] + (_global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 3);\n var left_dist = _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] - (_global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 3.5);\n var same_dist = _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"];\n if (this.car.next_road) {\n var y_dist = Math.abs(((this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) - this.car.y) * this.car.next_road.outroad_np.my);\n var x_dist = Math.abs(((this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) - this.car.x) * this.car.next_road.outroad_np.mx);\n if (this.car.next_road.rotation_type == 0) {\n if (y_dist < right_dist && x_dist < right_dist) {\n this.car.haveTurned = true;\n this.car.rotation = this.car.rotation += Math.PI / 2;\n this.car.rotation = this.car.rotation % (2 * Math.PI);\n this.car.next_road = undefined;\n return;\n }\n }\n if (this.car.next_road.rotation_type == 1) {\n if (y_dist < left_dist && x_dist < left_dist) {\n this.car.haveTurned = true;\n this.car.rotation = this.car.rotation -= Math.PI / 2;\n this.car.rotation = this.car.rotation % (2 * Math.PI);\n this.car.next_road = undefined;\n return;\n }\n }\n if (this.car.next_road.rotation_type == 2) {\n if (y_dist < same_dist && x_dist < same_dist) {\n this.car.haveTurned = true;\n this.car.rotation = this.car.rotation -= Math.PI;\n this.car.rotation = this.car.rotation % (2 * Math.PI);\n if (y_dist != 0 && this.car.x < this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.x = this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.y = this.car.next_road.outroad.y;\n }\n else if (y_dist != 0 && this.car.x > this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.x = this.car.next_road.outroad.x + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.y = this.car.next_road.outroad.y;\n }\n else if (x_dist != 0 && this.car.y < this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.y = this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.x = this.car.next_road.outroad.x;\n }\n else if (x_dist != 0 && this.car.y > this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2) {\n this.car.y = this.car.next_road.outroad.y + _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 2 - _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] / 4;\n this.car.x = this.car.next_road.outroad.x;\n }\n this.car.next_road = undefined;\n return;\n }\n }\n }\n else {\n var key = this.car.rotation / Math.PI;\n var key_r = ((this.car.rotation / Math.PI) + 0.5) % 2;\n var key_l = ((this.car.rotation / Math.PI) - 0.5) % 2;\n var is_next_pos = this.rotationToNextCase[key];\n var is_next_pos_r = this.rotationToNextCase[key_r];\n var is_next_pos_l = this.rotationToNextCase[key_l];\n var turn = false;\n var nx = this.car.mx + is_next_pos.mx;\n var ny = this.car.my + is_next_pos.my;\n if (!this.isRoad(nx, ny)) {\n turn = true;\n }\n else if (!this.car.haveTurned && !this.car.turnedRandom) {\n this.car.turnedRandom = Math.random();\n }\n else if (!this.car.haveTurned && this.car.turnedRandom < 0.33 && this.isRoad(this.car.mx + is_next_pos_r.mx, this.car.my + is_next_pos_r.my)) {\n turn = true;\n }\n else if (!this.car.haveTurned && this.car.turnedRandom > 0.66 && this.isRoad(this.car.mx + is_next_pos_l.mx, this.car.my + is_next_pos_l.my)) {\n turn = true;\n }\n if (turn) {\n var possibles_rotations = [(key + 0.5) % 2., (key - 0.5) % 2., null];\n for (var p = 0; p < possibles_rotations.length; p++) {\n var next_pos = void 0;\n if (possibles_rotations[p] != null) {\n next_pos = this.rotationToNextCase[possibles_rotations[p]];\n }\n else {\n next_pos = { \"mx\": 0, \"my\": 0 };\n }\n var px = this.car.mx + next_pos.mx;\n var py = this.car.my + next_pos.my;\n if (this.isRoad(px, py)) {\n this.car.next_road = {\n \"outroad\": { y: ny * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"], x: nx * _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"] },\n \"outroad_np\": is_next_pos,\n \"rotation_type\": p,\n };\n return;\n }\n }\n }\n }\n };\n BotMotionEngine.prototype.step = function (delta) {\n if (this.state.toString().indexOf(\",\" + _global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].CAR.toString()) != -1) {\n this.car.v = 0;\n }\n else {\n this.car.v = 0.8;\n this.autoRotation();\n }\n this.car.x += this.car.v * Math.cos(this.car.rotation) * delta;\n this.car.y += this.car.v * Math.sin(this.car.rotation) * delta;\n this.car.mx = Math.floor(this.car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.my = Math.floor(this.car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.checkAndsetNewRoad();\n this.lidar.x = this.car.x;\n this.lidar.y = this.car.y;\n this.lidar.rotation = this.car.rotation;\n var _a = this.detectInteractions(), agent_col = _a.agent_col, on_road = _a.on_road;\n if (agent_col.length > 0) {\n this.car.v = 0;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n return BotMotionEngine;\n}(_motion_engine__WEBPACK_IMPORTED_MODULE_0__[\"MotionEngine\"]));\n\n\n\n//# sourceURL=webpack://metacar/./src/bot_motion_engine.ts?"); + +/***/ }), + +/***/ "./src/car.ts": +/*!********************!*\ + !*** ./src/car.ts ***! + \********************/ +/*! exports provided: Car */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Car\", function() { return Car; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar Global_carId = 0;\nvar Car = (function () {\n function Car(level, info, textures, options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n this.level = level;\n options.image = options.image || _global__WEBPACK_IMPORTED_MODULE_0__[\"CAR_IMG\"].DEFAULT;\n options.lidar = options.lidar || false;\n options.lidarInfo = options.lidarInfo || { pts: 5, width: 4, height: 5, pos: 0 };\n this.core = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"](textures[options.image]);\n this.info = info;\n this.core.scale.x = 0.8;\n this.core.scale.y = 0.8;\n this.core.anchor.x = 0.5;\n this.core.anchor.y = 0.5;\n this.core.road = undefined;\n this.core.carId = Global_carId;\n Global_carId += 1;\n this.core.agent = false;\n this.core.obstacle = true;\n this.core.mapId = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].CAR;\n if (options.lidar) {\n this.createLidar(options.lidarInfo);\n this.core.lidar = this.lidar;\n }\n if (options.motionEngine) {\n this.motion = options.motionEngine;\n this.motion.setUp(this.core, this.lidar);\n this.core.rotationStep = 0.5;\n }\n else {\n this.core.rotationStep = 0.5;\n }\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n this.core.x = (this.info.mx) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.y = (this.info.my) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.checkAndsetNewRoad = function (road) { return _this.checkAndsetNewRoad(road); };\n var road = this.level.getRoad(this.core.my, this.core.mx);\n this.core.line = 0;\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n }\n Car.prototype.checkAndsetNewRoad = function (n_road) {\n var current_road = this.core.road;\n if (!n_road) {\n n_road = this.level.getRoad(this.core.my, this.core.mx);\n ;\n }\n if (n_road != current_road) {\n if (current_road) {\n current_road.cars.splice(current_road.cars.indexOf(this.core.carId), 1);\n }\n this.core.road = n_road;\n this.core.haveTurned = false;\n this.turnedRandom = undefined;\n if (n_road)\n n_road.cars.push(this.core.carId);\n }\n };\n Car.prototype.reset = function () {\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n var road = this.level.getRoad(this.core.my, this.core.mx);\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n };\n Car.prototype.getState = function () {\n return this.motion.state.map(function (arr) { return arr.slice(); });\n };\n Car.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n if (action == null) {\n var _a = this.motion.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n }\n else {\n var _b = this.motion.actionStep(delta, action), agent_col = _b.agent_col, on_road = _b.on_road;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n Car.prototype.createLidar = function (lidarOptions) {\n this.lidar = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Container\"]();\n var area = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n area.pt = false;\n area.alpha = 0.5;\n area.beginFill(0x515151);\n area.drawRect(0, 0, this.core.width * lidarOptions.width, this.core.height * lidarOptions.height);\n area.endFill();\n var x_step = area.width / lidarOptions.pts;\n var y_step = area.height / lidarOptions.pts;\n for (var xs = lidarOptions.pts - 1; xs >= 0; xs--) {\n for (var ys = 0; ys < lidarOptions.pts; ys++) {\n var x = (x_step / 4) + xs * x_step;\n var y = (y_step / 4) + ys * y_step;\n var pt = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n pt.pt = true;\n pt.beginFill(0xffffff);\n pt.drawRect(x, y, 5, 5);\n pt.endFill();\n this.lidar.addChild(pt);\n }\n }\n this.lidar.pts = lidarOptions.pts;\n this.lidar.addChild(area);\n this.lidar.x = this.core.x;\n this.lidar.y = this.core.y;\n this.lidar.pivot.y = this.lidar.height / 2;\n this.lidar.pivot.x = this.core.width / 2 - (lidarOptions.pos * this.core.width);\n this.lidar.rotation = this.core.rotation;\n };\n return Car;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/car.ts?"); + +/***/ }), + +/***/ "./src/control_motion_engine.ts": +/*!**************************************!*\ + !*** ./src/control_motion_engine.ts ***! + \**************************************/ +/*! exports provided: ControlMotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ControlMotionEngine\", function() { return ControlMotionEngine; });\n/* harmony import */ var _motion_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./motion_engine */ \"./src/motion_engine.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\nvar __extends = (undefined && undefined.__extends) || (function () {\n var extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\n return function (d, b) {\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\n\n\n\nvar ControlMotionEngine = (function (_super) {\n __extends(ControlMotionEngine, _super);\n function ControlMotionEngine(level) {\n var _this = _super.call(this, level) || this;\n _this.level = level;\n _this.actions = [\"SteeringAngle\", \"Throttle\"];\n return _this;\n }\n ControlMotionEngine.prototype.setUp = function (car, lidar) {\n this.car = car;\n this.lidar = lidar;\n this.state = [];\n for (var y = 0; y < lidar.pts; y++) {\n var line = [];\n for (var x = 0; x < lidar.pts; x++) {\n line.push(_global__WEBPACK_IMPORTED_MODULE_1__[\"MAP\"].DEFAULT);\n }\n this.state.push(line);\n }\n this.setUpKeyboard();\n this.car.v = 0;\n this.car.a = 0;\n this.car.yaw_rate = 0;\n this.detectInteractions();\n };\n ControlMotionEngine.prototype.setUpKeyboard = function () {\n var _this = this;\n var left = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](37);\n var up = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](38);\n var right = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](39);\n var down = _utils__WEBPACK_IMPORTED_MODULE_2__[\"keyboard\"](40);\n left.press = function () {\n _this.turn(-0.5);\n };\n left.release = function () {\n _this.turn(0);\n };\n right.press = function () {\n _this.turn(0.5);\n };\n right.release = function () {\n _this.turn(0);\n };\n up.press = function () { _this.move(1); };\n up.release = function () {\n _this.car.a = 0;\n };\n down.press = function () { _this.move(-1); };\n down.release = function () {\n _this.car.a = 0;\n };\n };\n ControlMotionEngine.prototype.turn = function (value) {\n this.car.yaw_rate = value;\n };\n ControlMotionEngine.prototype.move = function (throttle) {\n this.car.a = throttle;\n };\n ControlMotionEngine.prototype.actionStep = function (delta, actions) {\n this.car.a = Math.min(Math.max(parseInt(actions[0].toString()), -1), 1);\n this.car.yaw_rate = Math.min(Math.max(parseInt(actions[1].toString()), -1), 1);\n var _a = this.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n this.car.a = 0;\n this.car.yaw_rate = 0;\n return { agent_col: agent_col, on_road: on_road };\n };\n ControlMotionEngine.prototype.actionSpace = function () {\n return Array.apply(null, { length: this.actions.length }).map(Number.call, Number);\n };\n ControlMotionEngine.prototype.step = function (delta) {\n if (this.car.v > 0)\n this.car.v = Math.max(0, this.car.v - 0.01);\n else if (this.car.v < 0)\n this.car.v = Math.min(0, this.car.v + 0.01);\n if (this.car.a > 0)\n this.car.v = Math.min(2., this.car.v + this.car.a * 0.02);\n else\n this.car.v = Math.max(-2., this.car.v + this.car.a * 0.02);\n if (this.car.yaw_rate == 0) {\n this.car.x += this.car.v * Math.cos(this.car.rotation) * delta;\n this.car.y += this.car.v * Math.sin(this.car.rotation) * delta;\n }\n else {\n var yr = this.car.yaw_rate * 0.01 * (this.car.v + 0.001) * Math.PI;\n this.car.x += (this.car.v / yr) * (Math.sin(this.car.rotation + (yr * delta)) - Math.sin(this.car.rotation));\n this.car.y += (this.car.v / yr) * (Math.cos(this.car.rotation) - Math.cos(this.car.rotation + (yr * delta)));\n this.car.rotation += yr * delta;\n }\n this.car.mx = Math.floor(this.car.x / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.my = Math.floor(this.car.y / _global__WEBPACK_IMPORTED_MODULE_1__[\"ROADSIZE\"]);\n this.car.checkAndsetNewRoad();\n this.lidar.x = this.car.x;\n this.lidar.y = this.car.y;\n this.lidar.rotation = this.car.rotation;\n var _a = this.detectInteractions(), agent_col = _a.agent_col, on_road = _a.on_road;\n if (agent_col.length > 0) {\n this.car.v = 0;\n this.car.vy = 0;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n return ControlMotionEngine;\n}(_motion_engine__WEBPACK_IMPORTED_MODULE_0__[\"MotionEngine\"]));\n\n\n\n//# sourceURL=webpack://metacar/./src/control_motion_engine.ts?"); + +/***/ }), + +/***/ "./src/embedded.ts": +/*!*************************!*\ + !*** ./src/embedded.ts ***! + \*************************/ +/*! exports provided: embeddedUrl, embeddedContent */ +/***/ (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?"); + +/***/ }), + +/***/ "./src/embedded/level/full_city.ts": +/*!*****************************************!*\ + !*** ./src/embedded/level/full_city.ts ***! + \*****************************************/ +/*! exports provided: fullCity */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"fullCity\", function() { return fullCity; });\nvar fullCity = {\n \"cars\": [\n {\n \"mx\": 2,\n \"my\": 5,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 3,\n \"my\": 4,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 3,\n \"my\": 4,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 6,\n \"my\": 3,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 6,\n \"my\": 3,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 8,\n \"my\": 2,\n \"line\": 0,\n \"auto\": true\n },\n {\n \"mx\": 8,\n \"my\": 2,\n \"line\": 1,\n \"auto\": true\n },\n {\n \"mx\": 2,\n \"my\": 7,\n \"line\": 0,\n \"auto\": true\n }\n ],\n \"house\": [\n {\n \"x\": 9,\n \"y\": 409\n },\n {\n \"x\": 146,\n \"y\": 162\n },\n {\n \"x\": 439,\n \"y\": 39\n }\n ],\n \"house2\": [\n {\n \"x\": 425,\n \"y\": 192\n },\n {\n \"x\": 431,\n \"y\": 354\n }\n ],\n \"house3\": [\n {\n \"x\": 426,\n \"y\": 281\n },\n {\n \"x\": 51,\n \"y\": 157\n },\n {\n \"x\": 553,\n \"y\": 34\n }\n ],\n \"bench\": [\n {\n \"x\": 259,\n \"y\": 206\n },\n {\n \"x\": 8,\n \"y\": 205\n }\n ],\n \"tree\": [\n {\n \"x\": 1,\n \"y\": 303\n },\n {\n \"x\": 54,\n \"y\": 357\n },\n {\n \"x\": 215,\n \"y\": 325\n },\n {\n \"x\": 230,\n \"y\": 400\n },\n {\n \"x\": 282,\n \"y\": 368\n },\n {\n \"x\": 182,\n \"y\": 433\n },\n {\n \"x\": 285,\n \"y\": 309\n },\n {\n \"x\": 576,\n \"y\": 233\n },\n {\n \"x\": 581,\n \"y\": 300\n },\n {\n \"x\": 519,\n \"y\": 388\n },\n {\n \"x\": 582,\n \"y\": 391\n },\n {\n \"x\": 256,\n \"y\": 69\n },\n {\n \"x\": 151,\n \"y\": 43\n },\n {\n \"x\": 77,\n \"y\": 77\n },\n {\n \"x\": 26,\n \"y\": 24\n },\n {\n \"x\": 189,\n \"y\": 98\n }\n ],\n \"map\": [\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↠\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↦\",\n \"↔\",\n \"↔\",\n \"↟\",\n \"↔\"\n ],\n [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n \"↔\",\n \"↔\",\n \"↧\",\n \"↔\",\n \"↠\",\n \"↔\",\n \"↤\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n \"↠\",\n 0,\n 0,\n 0,\n \"↠\",\n 0,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n \"↕\",\n 0,\n 0,\n 0,\n 0\n ]\n ]\n};\n\n\n//# sourceURL=webpack://metacar/./src/embedded/level/full_city.ts?"); + +/***/ }), + +/***/ "./src/global.ts": +/*!***********************!*\ + !*** ./src/global.ts ***! + \***********************/ +/*! exports provided: Application, Loader, Resources, Sprite, Graphics, Container, JSON_TEXTURES, LEVEL_FOLDER, ROADSIZE, CAR_IMG, MAP, ASSETS */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Application\", function() { return Application; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Loader\", function() { return Loader; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Resources\", function() { return Resources; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Sprite\", function() { return Sprite; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Graphics\", function() { return Graphics; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Container\", function() { return Container; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"JSON_TEXTURES\", function() { return JSON_TEXTURES; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LEVEL_FOLDER\", function() { return LEVEL_FOLDER; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ROADSIZE\", function() { return ROADSIZE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"CAR_IMG\", function() { return CAR_IMG; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MAP\", function() { return MAP; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ASSETS\", function() { return ASSETS; });\n/* harmony import */ var pixi_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! pixi.js */ \"pixi.js\");\n/* harmony import */ var pixi_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(pixi_js__WEBPACK_IMPORTED_MODULE_0__);\n\nvar Application = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Application\"];\nvar Loader = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"loader\"];\nvar Resources = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"loader\"].resources;\nvar Sprite = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"];\nvar Graphics = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"];\nvar Container = pixi_js__WEBPACK_IMPORTED_MODULE_0__[\"Container\"];\nvar JSON_TEXTURES = \"public/textures/textures.json\";\nvar LEVEL_FOLDER = \"/level/\";\nvar ROADSIZE = 60;\nvar CAR_IMG = {\n DEFAULT: \"car.png\",\n AGENT: \"car_agent.png\"\n};\nvar MAP = {\n ROAD: -1,\n DEFAULT: 0,\n CAR: 1,\n AGENT: 1,\n};\nvar ASSETS = {\n ROADS: {\n \"↕\": {\n \"image\": \"road_u.png\",\n \"orientation\": 1.5\n },\n \"↔\": {\n \"image\": \"road_r.png\",\n \"orientation\": 0.\n },\n \"↱\": {\n \"image\": \"road_rotate_ld.png\",\n \"orientation\": 1.25\n },\n \"↰\": {\n \"image\": \"road_rotate_ul.png\",\n \"orientation\": 0.75\n },\n \"↲\": {\n \"image\": \"road_rotate_rl.png\",\n \"orientation\": 0.25\n },\n \"↳\": {\n \"image\": \"road_rotate_dl.png\",\n \"orientation\": 1.75\n },\n \"↟\": {\n \"image\": \"road_up.png\",\n \"orientation\": 1.5\n },\n \"↠\": {\n \"image\": \"road_rp.png\",\n \"orientation\": 0.\n },\n \"↤\": {\n \"image\": \"road_r2.png\",\n \"orientation\": 0.\n },\n \"↦\": {\n \"image\": \"road_l2.png\",\n \"orientation\": 1.\n },\n \"↥\": {\n \"image\": \"road_d2.png\",\n \"orientation\": 0.5\n },\n \"↧\": {\n \"image\": \"road_u2.png\",\n \"orientation\": 1.5\n },\n },\n \"house\": {\n \"image\": \"house.png\"\n },\n \"house2\": {\n \"image\": \"house2.png\"\n },\n \"house3\": {\n \"image\": \"house3.png\"\n },\n \"bench\": {\n \"image\": \"bench.png\"\n },\n \"tree\": {\n \"image\": \"tree.png\"\n }\n};\n\n\n//# sourceURL=webpack://metacar/./src/global.ts?"); + +/***/ }), + +/***/ "./src/index.ts": +/*!**********************!*\ + !*** ./src/index.ts ***! + \**********************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _metacar__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./metacar */ \"./src/metacar.ts\");\n/* harmony import */ var _embedded__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./embedded */ \"./src/embedded.ts\");\n\n\nvar metacar = {\n env: _metacar__WEBPACK_IMPORTED_MODULE_0__[\"MetaCar\"],\n level: _embedded__WEBPACK_IMPORTED_MODULE_1__[\"embeddedUrl\"]\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (metacar);\n\n\n//# sourceURL=webpack://metacar/./src/index.ts?"); + +/***/ }), + +/***/ "./src/level.ts": +/*!**********************!*\ + !*** ./src/level.ts ***! + \**********************/ +/*! exports provided: Level */ +/***/ (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?"); + +/***/ }), + +/***/ "./src/metacar.ts": +/*!************************!*\ + !*** ./src/metacar.ts ***! + \************************/ +/*! exports provided: MetaCar */ +/***/ (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?"); + +/***/ }), + +/***/ "./src/motion_engine.ts": +/*!******************************!*\ + !*** ./src/motion_engine.ts ***! + \******************************/ +/*! exports provided: MotionEngine */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MotionEngine\", function() { return MotionEngine; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar MotionEngine = (function () {\n function MotionEngine(level) {\n this.level = level;\n }\n MotionEngine.prototype.boxesIntersect = function (a, b) {\n var ab = a.getBounds();\n var bb = b.getBounds();\n return ab.x + ab.width > bb.x && ab.x < bb.x + bb.width && ab.y + ab.height > bb.y && ab.y < bb.y + bb.height;\n };\n MotionEngine.prototype.detectInteractions = function () {\n var envs = this.level.getEnvs();\n var agent_col = [];\n var lidar_collisions = [];\n var on_road = false;\n for (var i = 0; i < envs.length; i++) {\n if (envs[i] != this.car && envs[i].obstacle && this.boxesIntersect(envs[i], this.car)) {\n agent_col.push(envs[i]);\n }\n else if (envs[i].mapId == _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].ROAD && this.boxesIntersect(envs[i], this.car)) {\n on_road = true;\n }\n if (this.boxesIntersect(envs[i], this.lidar)) {\n lidar_collisions.push(envs[i]);\n }\n }\n this.setState(lidar_collisions);\n return { agent_col: agent_col, on_road: on_road };\n };\n MotionEngine.prototype.setState = function (lidar_collisions) {\n var pt_id = 0;\n for (var i = 0; i < this.lidar.children.length; i++) {\n this.lidar.children[i].alpha = 0.1;\n if (this.lidar.children[i].pt) {\n var pt_y = Math.floor(pt_id / this.lidar.pts);\n var pt_x = Math.floor(pt_id % this.lidar.pts);\n this.state[pt_y][pt_x] = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].DEFAULT;\n for (var a = 0; a < lidar_collisions.length; a++) {\n if (lidar_collisions[a] != this.car) {\n var touch = this.boxesIntersect(lidar_collisions[a], this.lidar.children[i]);\n if (touch && lidar_collisions[a].obstacle) {\n this.lidar.children[i].alpha = 1.;\n }\n if (touch && (lidar_collisions[a].mapId > this.state[pt_y][pt_x] || (lidar_collisions[a].mapId == _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].ROAD && this.state[pt_y][pt_x] == _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].DEFAULT))) {\n this.state[pt_y][pt_x] = lidar_collisions[a].mapId;\n }\n }\n }\n pt_id += 1;\n }\n }\n };\n return MotionEngine;\n}());\n\n;\n\n\n//# sourceURL=webpack://metacar/./src/motion_engine.ts?"); + +/***/ }), + +/***/ "./src/utils.ts": +/*!**********************!*\ + !*** ./src/utils.ts ***! + \**********************/ +/*! exports provided: loadJSON, loadEmbeddedURL, loadLocalStorageURL, loadCustomURL, mod, argMax, mean, saveAs, 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?"); + +/***/ }), + +/***/ "pixi.js": +/*!***********************!*\ + !*** external "PIXI" ***! + \***********************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +eval("(function() { module.exports = window[\"PIXI\"]; }());\n\n//# sourceURL=webpack://metacar/external_%22PIXI%22?"); + +/***/ }) + +/******/ })["default"]; \ No newline at end of file diff --git a/package.json b/package.json index 15f9a03..c1a7d3b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "scripts": { "build": "./node_modules/.bin/webpack-cli --mode production", + "build-dev": "./node_modules/.bin/webpack-cli --mode development", "watch": "./node_modules/.bin/webpack-cli --watch --mode development" } } diff --git a/src/asset_manager.ts b/src/asset_manager.ts index 61df32c..5ccbb2b 100644 --- a/src/asset_manager.ts +++ b/src/asset_manager.ts @@ -14,6 +14,7 @@ import {CarOptions, Car} from "./car"; import {BasicMotionEngine} from "./basic_motion_engine"; import {ControlMotionEngine} from "./control_motion_engine"; import {BotMotionEngine} from "./bot_motion_engine"; +import { Editor } from "./editor"; export interface AssetInfo { readonly mx?: number; @@ -38,6 +39,7 @@ export interface RoadSprite extends PIXI.Sprite { // (x, y position) Relatif to the map mx?: number; my?: number; + isremove?: boolean; } export interface SimpleSprite extends PIXI.Sprite { @@ -45,17 +47,18 @@ export interface SimpleSprite extends PIXI.Sprite { // name of the asset (not the name of the image) type?: string; mapId?: number; + isremove?: boolean; } export class AssetManger { - private level: Level; + private level: Level|Editor; // Used to list the differents MotionEngine possible to add on the car private motion: any; // List of all items on the map - private assets: SimpleSprite[] = []; + public assets: SimpleSprite[] = []; - constructor(level: Level) { + constructor(level: Level|Editor) { this.level = level; this.motion = { "BasicMotionEngine": BasicMotionEngine, @@ -111,7 +114,8 @@ export class AssetManger { */ if (line == undefined) line = 0; - if (road.cars.length >= 1 && this.level.findCarById(road.cars[0]).core.line == line){ + let carById = this.level.findCarById(road.cars[0]); + if (road.cars.length >= 1 && carById && carById.core.line == line){ line = line == 0 ? 1:0; } if (road.cars.length >= 2){ @@ -129,10 +133,10 @@ export class AssetManger { let y_margin = (ROADSIZE*1/4); // transform to map x coordinate // transform to map y coordinate - road.orientation = (Math.floor(road.orientation / car.rotation_step)*car.rotation_step); - let theta = -road.orientation*(Math.PI); - let x_m = (Math.cos(theta) * x_margin) - (y_margin * Math.sin(theta)); - let y_m = (Math.cos(theta) * y_margin) + (x_margin * Math.sin(theta)); + road.orientation = (Math.floor(road.orientation / car.rotationStep)*car.rotationStep); + let th = -road.orientation*(Math.PI); // theta + let x_m = (Math.cos(th) * x_margin) - (y_margin * Math.sin(th)); + let y_m = (Math.cos(th) * y_margin) + (x_margin * Math.sin(th)); let line_side_factor = line == 0 ? 1:-1; let line_side_factor_t = line == 0 ? 0:Math.PI; @@ -143,7 +147,7 @@ export class AssetManger { car.mx = Math.floor(car.x / ROADSIZE); car.my = Math.floor(car.y / ROADSIZE); // Car rotation - car.rotation = (theta+line_side_factor_t); + car.rotation = (th+line_side_factor_t); // Set the new road of the car car.checkAndsetNewRoad(road); } @@ -169,7 +173,7 @@ export class AssetManger { this.assets.push(asset); } - createMap(map: (string|number)[][], info: LevelInfo, textures: PIXI.Texture, roadside:boolean=true){ + createMap(map: (string|number)[][], info: LevelInfo, textures: (PIXI.Texture|PIXI.loaders.TextureDictionary), roadside:boolean=true){ /* Method used to create the map with all assets (except the cars) @map (2dim Array) @@ -204,7 +208,7 @@ export class AssetManger { } } - createCars(map: (string|number)[][], info: LevelInfo, textures: PIXI.Texture){ + createCars(map: (string|number)[][], info: any, textures: (PIXI.Texture|PIXI.loaders.TextureDictionary)){ /* Method used to create all the cars @map (2dim Array) @@ -213,7 +217,7 @@ export class AssetManger { */ // Go through all the bot cars on the map for (let c in info.cars){ - let options: CarOptions = {lidar: false, lidarInfo: {pts: 2, width: 0.5, height: 1, pos: 1}}; + let options: CarOptions = {lidar: true, lidarInfo: {pts: 2, width: 0.5, height: 1, pos: 1}}; if (info.cars[c].auto){ options.lidar = true; options.motionEngine = new BotMotionEngine(this.level); @@ -221,10 +225,11 @@ export class AssetManger { let n_car = new Car(this.level, info.cars[c], textures, options); // Append the car to the canvas this.level.addCar(n_car); + //this.level.addChild(n_car.lidar); } } - createAgent(map: (string|number)[][], info: LevelInfo, textures: PIXI.Texture){ + createAgent(map: (string|number)[][], info: any, textures: (PIXI.Texture|PIXI.loaders.TextureDictionary)){ /* Method used to create the agent's car. @map (2dim Array) @@ -244,6 +249,10 @@ export class AssetManger { return agent; } + addAsset(asset: any){ + this.assets.push(asset); + } + exportMap(width: number, height: number, file_name: string){ /* Export the map @@ -251,8 +260,9 @@ export class AssetManger { @height (Integer) Height of the new map @file_name (String) name of the file to export */ - var file = {"cars": []}; + var file: any = {"cars": []}; let map = []; + let envs = this.level.getEnvs(); for (var y = 0; y < height; y++) { let line = []; for (var x = 0; x < width; x++) { @@ -260,8 +270,8 @@ export class AssetManger { } map.push(line); } - for (var e = 0; e < this.level.envs.length; e++) { - let elem = this.level.envs[e]; + for (var e = 0; e < envs.length; e++) { + let elem = envs[e]; if (!elem.isremove){ // Add the cars if (elem.mapId == MAP.CAR && !elem.agent && elem.is_valid){ @@ -300,7 +310,7 @@ export class AssetManger { "motion": { "type": "BasicMotionEngine", "options":{ - "rotation_step": 0.5, + "rotationStep": 0.5, "actions": ["UP", "LEFT", "RIGHT", "DOWN", "WAIT"] } } diff --git a/src/bot_motion_engine.ts b/src/bot_motion_engine.ts index 13fd653..dd93a3a 100644 --- a/src/bot_motion_engine.ts +++ b/src/bot_motion_engine.ts @@ -4,6 +4,7 @@ import {Level} from "./level"; import { MAP, ROADSIZE } from "./global"; +import { Editor } from "./editor"; export class BotMotionEngine extends MotionEngine { /* @@ -18,7 +19,7 @@ export class BotMotionEngine extends MotionEngine { private map: (string|number)[][]; private rotationToNextCase: any; - constructor(level: Level) { + constructor(level: Level|Editor) { super(level); this.map = this. level.getMap(); @@ -35,7 +36,7 @@ export class BotMotionEngine extends MotionEngine { this.rotationToNextCase[-0.5] = {"mx": 0, "my": -1}; this.rotationToNextCase[-1.0] = {"mx": -1, "my": 0}; this.rotationToNextCase[-1.5] = {"mx": 0, "my": 1}; - // this.rotationToNextCase[null] = {"mx": 0, "my": 0}; + //this.rotationToNextCase[undefined] = {"mx": 0, "my": 0}; } setUp(car: any, lidar: any){ @@ -93,7 +94,7 @@ export class BotMotionEngine extends MotionEngine { Method used to check is there a road is present at this potion on the map */ - if (ny < 0 || ny >= this.mapSizeY || nx < 0 || nx >= this.mapSizeX || this.level.map[ny][nx] == 0){ + if (ny < 0 || ny >= this.mapSizeY || nx < 0 || nx >= this.mapSizeX || this.map[ny][nx] == 0){ return false; } return true; @@ -114,7 +115,7 @@ export class BotMotionEngine extends MotionEngine { if (this.car.next_road.rotation_type == 0){ // Turn right if (y_dist < right_dist && x_dist < right_dist){ - this.car.have_turned = true; + this.car.haveTurned = true; this.car.rotation = this.car.rotation += Math.PI/2; this.car.rotation = this.car.rotation % (2*Math.PI); this.car.next_road = undefined; @@ -124,7 +125,7 @@ export class BotMotionEngine extends MotionEngine { if (this.car.next_road.rotation_type == 1){ // Turn left if (y_dist < left_dist && x_dist < left_dist){ - this.car.have_turned = true; + this.car.haveTurned = true; this.car.rotation = this.car.rotation -= Math.PI/2; this.car.rotation = this.car.rotation % (2*Math.PI); this.car.next_road = undefined; @@ -134,7 +135,7 @@ export class BotMotionEngine extends MotionEngine { if (this.car.next_road.rotation_type == 2){ // Rotation if (y_dist < same_dist && x_dist < same_dist){ - this.car.have_turned = true; + this.car.haveTurned = true; this.car.rotation = this.car.rotation -= Math.PI; this.car.rotation = this.car.rotation % (2*Math.PI); @@ -176,19 +177,24 @@ export class BotMotionEngine extends MotionEngine { if (!this.isRoad(nx, ny)){ turn = true; } - else if (!this.car.have_turned && !this.car.turn_random){ - this.car.turn_random = Math.random(); + else if (!this.car.haveTurned && !this.car.turnedRandom){ + this.car.turnedRandom = Math.random(); } - else if(!this.car.have_turned && this.car.turn_random < 0.33 && this.isRoad(this.car.mx + is_next_pos_r.mx, this.car.my + is_next_pos_r.my)){ + else if(!this.car.haveTurned && this.car.turnedRandom < 0.33 && this.isRoad(this.car.mx + is_next_pos_r.mx, this.car.my + is_next_pos_r.my)){ turn = true; } - else if(!this.car.have_turned && this.car.turn_random > 0.66 && this.isRoad(this.car.mx + is_next_pos_l.mx, this.car.my + is_next_pos_l.my)){ + else if(!this.car.haveTurned && this.car.turnedRandom > 0.66 && this.isRoad(this.car.mx + is_next_pos_l.mx, this.car.my + is_next_pos_l.my)){ turn = true; } if (turn){ let possibles_rotations = [(key+0.5) % 2., (key-0.5) % 2., null]; for (let p = 0; p < possibles_rotations.length; p++){ - let next_pos = this.rotationToNextCase[possibles_rotations[p]]; + let next_pos; + if (possibles_rotations[p] != null){ + next_pos = this.rotationToNextCase[possibles_rotations[p]]; + } else{ + next_pos = {"mx": 0, "my": 0}; + } let px = this.car.mx + next_pos.mx; let py = this.car.my + next_pos.my; if (this.isRoad(px, py)){ diff --git a/src/car.ts b/src/car.ts index 6563c07..c0f85d4 100644 --- a/src/car.ts +++ b/src/car.ts @@ -4,7 +4,8 @@ This class create the agent and the associated sensor (lidar) */ -import {Level, LevelInfo} from "./level"; +import {Level} from "./level"; +import {Editor} from "./editor"; import { CAR_IMG, Sprite, MAP, ROADSIZE, Container, Graphics @@ -49,17 +50,22 @@ export interface CarSprite extends PIXI.Sprite { agent?: boolean; } +export interface LidarChild extends PIXI.Graphics { + // Is a lidar point + pt?: boolean; +} + export class Car { - public level: Level; + public level: Level|Editor; public core: CarSprite; public lidar: any; private info: CarInfo; private motion: any; - private turnedRandom: any; + public turnedRandom: any; - constructor(level: Level, info: CarInfo, textures: any, options:CarOptions={}) { + constructor(level: Level|Editor, info: CarInfo, textures: any, options:CarOptions={}) { /* @level (Level class) @info: (CarInfo) Info from the json file about the car @@ -200,9 +206,9 @@ export class Car { @height: Height of the lidar (in proportion to the car) */ this.lidar = new Container(); - // Area of the lidar - let area = new Graphics(); + let area: LidarChild = new Graphics(); + area.pt = false; area.alpha = 0.5; area.beginFill(0x515151); area.drawRect(0, 0, this.core.width*lidarOptions.width, this.core.height*lidarOptions.height); @@ -216,8 +222,8 @@ export class Car { let x = (x_step/4) + xs * x_step; let y = (y_step/4) + ys * y_step; - - let pt = new Graphics(); + let pt: LidarChild = new Graphics(); + pt.pt = true; pt.beginFill(0xffffff); pt.drawRect(x, y, 5, 5); pt.endFill(); @@ -227,8 +233,10 @@ export class Car { this.lidar.pts = lidarOptions.pts; this.lidar.addChild(area); + this.lidar.x = this.core.x; this.lidar.y = this.core.y; + this.lidar.pivot.y = this.lidar.height/2; this.lidar.pivot.x = this.core.width/2 - (lidarOptions.pos*this.core.width); this.lidar.rotation = this.core.rotation; diff --git a/src/editor.ts b/src/editor.ts new file mode 100644 index 0000000..351dc6a --- /dev/null +++ b/src/editor.ts @@ -0,0 +1,332 @@ +import { LevelInfo, Roads } from "./level"; +import { AssetManger, RoadSprite } from "./asset_manager"; +import { Car} from "./car"; +import {Loader, Sprite, JSON_TEXTURES, ROADSIZE, MAP, LEVEL_FOLDER} from "./global"; +import * as U from "./utils"; + +/* + @Level class + This is the core of game, the class is used create all the differents + services in the game (assets, map, agents...). +*/ + +export class Editor { + + public app: PIXI.Application = null; // The pixi app. + // Informations on the level + private levelName: string; + private info: LevelInfo = null; + private envs: any[] = [] // Used to list all elements the car can crash with + public am: AssetManger; + public map: (string|number)[][] = null; // Use the roads positions of the level + public agent: any = null; // (@Car class) for the agent + // Object to store all the roads assets + // Each road is accesible as follow this.roads[[my, mx]] + // with my and mx the (x, y) position relative to the map (not pixel). + private cars: Car[] = []; // Array used to store all the cars assets + private loop: any = null; // Loop method called for each render + // Current selector items by the editor + public selectedItems: any = null; + private canvasId: string; // Id of the target canvas + private roads: Roads = {}; + + constructor(levelName: string, canvasId: string) { + /* + @levelName (String) Name of the level to load (.json) + */ + this.levelName = levelName; + this.canvasId = canvasId; + this.am = new AssetManger(this); + } + + selectedItem(item: any){ + /* + Method to select an items. + Once an item is selected, the item stick to the current + mouse position + @items (Object) + @img (String) + @type (String) + */ + if(this.selectedItems){ + this.app.stage.removeChild(this.selectedItems); + } + let textures = Loader.resources[JSON_TEXTURES].textures; + this.selectedItems = new Sprite(textures[item.image]); + this.selectedItems.type = item.type; + this.selectedItems.image = item.image; + this.selectedItems.data = item.data; + // The road is not an obstacle + this.selectedItems.x = 0; + this.selectedItems.y = 0; + this.app.stage.addChild(this.selectedItems); + } + + removeItem(item: any){ + if (item.lidar){ + this.app.stage.removeChild(item.lidar); + } + if (item.map_id == MAP.CAR){ + item.road.cars.splice(item.road.cars.indexOf(item.car_id), 1); + } + if (item.agent) + this.agent = undefined; + this.app.stage.removeChild(item); + item.isremove = true; + } + + setCurrentItem(){ + this.am.addAsset(this.selectedItems); + let textures = Loader.resources[JSON_TEXTURES].textures; + var that = this; + if (this.selectedItems.type == "road"){ + this.am.createRoad({ + mx: Math.floor(this.selectedItems.x / ROADSIZE), + my: Math.floor(this.selectedItems.y / ROADSIZE), + type: this.selectedItems.data + }, textures); + this.envs[this.envs.length - 1].interactive = true; + this.envs[this.envs.length - 1].on("rightclick", function(this: any) {that.removeItem(this)}); + } + else if (this.selectedItems.type == "car"){ + this.am.createCars(this.map, {cars:[{ + "mx": Math.floor(this.selectedItems.x / ROADSIZE), + "my": Math.floor(this.selectedItems.y / ROADSIZE), + "rotation": 0, + "line": 0, + }]}, textures); + this.envs[this.envs.length - 1].interactive = true; + this.envs[this.envs.length - 1].on("rightclick", function(this: any) {that.removeItem(this)}); + } + else if (this.selectedItems.type == "agent" && this.agent == undefined){ + this.agent = this.am.createAgent(this.map, {agent:{ + "mx": Math.floor(this.selectedItems.x / ROADSIZE), + "my": Math.floor(this.selectedItems.y / ROADSIZE), + "rotation": 0, + "line": 0, + "motion": { + "type": "BasicMotionEngine", + "options":{ + "rotation_step": 0.5, + "actions": ["UP", "LEFT", "RIGHT", "DOWN", "WAIT"] + } + } + }}, textures); + this.envs[this.envs.length - 1].interactive = true; + this.envs[this.envs.length - 1].on("rightclick", function(this: any) {that.removeItem(this)}); + } + else if (this.selectedItems.type == "asset"){ + this.am.createAsset(this.selectedItems.image, {x: this.selectedItems.x, y: this.selectedItems.y} ,textures, this.selectedItems.data); + this.am.assets[this.am.assets.length - 1].interactive = true; + this.am.assets[this.am.assets.length - 1].on("rightclick", function(this: any) {that.removeItem(this)}); + } + this.app.stage.removeChild(this.selectedItems); + this.selectedItems = null; + } + + load(loop: any){ + /* + Load the map from the file given in the constructor of the class + @loop (Method) This method will be call for each render + */ + this.loop = loop; + return new Promise((resolve, reject) => { + // Load the level + U.loadJSON(LEVEL_FOLDER + this.levelName, (response: any) => { + // Parse JSON string into object + this.info = JSON.parse(response); + this.createLevel(this.info).then(() => resolve()); + }); + }); + } + + createLevel(info: LevelInfo){ + /* + Create the level + @info (Object) Level's json. + */ + this.map = info.map; // Store the map to let it accessible faster later on. + //Create the Pixi Application + this.app = new PIXI.Application({ + width: this.map[0].length * ROADSIZE, + height: this.map.length * ROADSIZE, + backgroundColor: 0x80bf3e + } + ); + // Append the app to the body + document.getElementById(this.canvasId).appendChild(this.app.view); + + return new Promise((resolve, reject) => { + Loader.add(["textures/textures.json", "textures/textures.png"]).load(() => { + this.setup(info); // Set up the level (Add assets) + resolve(); + }); + }); + } + + setup(info: any){ + /* + Setup all the element of the map + @info (Object) Level's json. + */ + // Load the textures file + let textures = Loader.resources[JSON_TEXTURES].textures; + // Load all elements of the car + this.am.createMap(this.map, info, textures, false); + this.am.createCars(this.map, info, textures); + if (info.agent) + this.agent = this.am.createAgent(this.map, info, textures); + + var that = this; + for (var i = 0; i < this.envs.length; i++) { + this.envs[i].interactive = true; + this.envs[i].on("rightclick", function(this: any) {that.removeItem(this)}); + } + for (var i = 0; i < this.am.assets.length; i++) { + this.am.assets[i].interactive = true; + this.am.assets[i].on("rightclick", function(this: any) {that.removeItem(this)}); + } + + // Set up the main loop + this.app.ticker.add(delta => this.loop(delta)); + } + + resize(width: number, height: number){ + /* + Resize the map + */ + this.app.renderer.resize(width * ROADSIZE, height * ROADSIZE); + } + + addChild(child: any){ + /** + * Add child to the app + */ + this.app.stage.addChild(child); + } + + addCar(car: Car){ + /** + * Add car to the level + */ + this.cars.push(car); + this.app.stage.addChild(car.core); + this.envs.push(car.core); + } + + getMap(): (string|number)[][] { + return this.map; + } + + getEnvs(): any[] { + /** + * Return the list of envs + * / + */ + return this.envs; + } + + addRoad(road: RoadSprite){ + /* + Add road using the mx and my positions + */ + this.roads[[road.my.toString(), road.mx.toString()].toString()] = road; + this.envs.push(road); + this.app.stage.addChild(road); + } + + findCarById(id: number){ + /* + Find car by @id + */ + return this.cars.find((e: any) => {return e.car_id == id}); + } + + getRoad(my: number, mx: number){ + return this.roads[[my.toString(), mx.toString()].toString()]; + } + + getRoads(){ + return this.roads; + } +} + +/* +function createEditor(id: string){ + + // Get the DOM element to change the width/height of the map + const height_input = document.getElementById("height_input"); + const width_input = document.getElementById("width_input"); + var width = parseInt((width_input).value); + var height = parseInt((height_input).value); + + // Create the editor class + let file = window.location.hash || "template.json"; + file = file.slice(1, file.length) + console.log(file); + var editor = new Editor(file, "string"); + + // For the first init retrieve the widht and height of the map + var fist_init = false; + function init(){ + width = editor.map[0].length; + height = editor.map.length; + (width_input).value = width.toString(); + (height_input).value = height.toString(); + } + + function load(){ + if (!fist_init){ + fist_init = true; + init(); + } + let mouse_position = editor.app.renderer.plugins.interaction.mouse.global; + if (editor.selectedItems && editor.selectedItems.type == "asset"){ + editor.selectedItems.x = mouse_position.x; + editor.selectedItems.y = mouse_position.y; + } + else if (editor.selectedItems) { + editor.selectedItems.x = Math.floor(mouse_position.x/ROADSIZE) * ROADSIZE; + editor.selectedItems.y = Math.floor(mouse_position.y/ROADSIZE) * ROADSIZE; + } + } + + // Game loop + editor.load((delta: any) => { + load(); + }); + + var classname = document.getElementsByClassName("img_item"); + for (var i = 0; i < classname.length; i++) { + classname[i].addEventListener('click', function(this: any){ + editor.selectedItem({image : this.getAttribute('data-img'), type: this.getAttribute('data-type'), data: this.getAttribute("data-data")}); + }, false); + } + + width_input.onchange = () => { + width = parseInt((width_input).value); + editor.resize(width, height); + } + + height_input.onchange = () => { + height = parseInt((height_input).value); + editor.resize(width, height); + } + + document.getElementById("saveMap").onclick = () => { + editor.am.exportMap(width, height, file); + }; + + document.getElementById("canvas").addEventListener("click", () => { + if (editor.selectedItems){ + editor.setCurrentItem(); + } + }); + + document.getElementById("loadMap").addEventListener("click", () => { + window.location.href = "/editor.html#"+prompt("What is the name of the level ? (The file should be located in your level folder)"); + location.reload(); + }); + + document.getElementById("canvas").addEventListener('contextmenu', event => event.preventDefault()); +}*/ \ No newline at end of file diff --git a/src/embedded.ts b/src/embedded.ts new file mode 100644 index 0000000..2426558 --- /dev/null +++ b/src/embedded.ts @@ -0,0 +1,11 @@ +import {fullCity} from "./embedded/level/full_city"; + +export const embeddedUrl: any = { + fullCity: "embedded://level/fullCity" +} + +export const embeddedContent: any = { + level: { + fullCity: fullCity + } +} \ No newline at end of file diff --git a/src/embedded/level/full_city.ts b/src/embedded/level/full_city.ts new file mode 100644 index 0000000..71c3029 --- /dev/null +++ b/src/embedded/level/full_city.ts @@ -0,0 +1,272 @@ +export const fullCity: any = { + "cars": [ + { + "mx": 2, + "my": 5, + "line": 0, + "auto": true + }, + { + "mx": 3, + "my": 4, + "line": 0, + "auto": true + }, + { + "mx": 3, + "my": 4, + "line": 1, + "auto": true + }, + { + "mx": 6, + "my": 3, + "line": 0, + "auto": true + }, + { + "mx": 6, + "my": 3, + "line": 1, + "auto": true + }, + { + "mx": 8, + "my": 2, + "line": 0, + "auto": true + }, + { + "mx": 8, + "my": 2, + "line": 1, + "auto": true + }, + { + "mx": 2, + "my": 7, + "line": 0, + "auto": true + } + ], + "house": [ + { + "x": 9, + "y": 409 + }, + { + "x": 146, + "y": 162 + }, + { + "x": 439, + "y": 39 + } + ], + "house2": [ + { + "x": 425, + "y": 192 + }, + { + "x": 431, + "y": 354 + } + ], + "house3": [ + { + "x": 426, + "y": 281 + }, + { + "x": 51, + "y": 157 + }, + { + "x": 553, + "y": 34 + } + ], + "bench": [ + { + "x": 259, + "y": 206 + }, + { + "x": 8, + "y": 205 + } + ], + "tree": [ + { + "x": 1, + "y": 303 + }, + { + "x": 54, + "y": 357 + }, + { + "x": 215, + "y": 325 + }, + { + "x": 230, + "y": 400 + }, + { + "x": 282, + "y": 368 + }, + { + "x": 182, + "y": 433 + }, + { + "x": 285, + "y": 309 + }, + { + "x": 576, + "y": 233 + }, + { + "x": 581, + "y": 300 + }, + { + "x": 519, + "y": 388 + }, + { + "x": 582, + "y": 391 + }, + { + "x": 256, + "y": 69 + }, + { + "x": 151, + "y": 43 + }, + { + "x": 77, + "y": 77 + }, + { + "x": 26, + "y": 24 + }, + { + "x": 189, + "y": 98 + } + ], + "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, + 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 + ] + ] +} diff --git a/src/global.ts b/src/global.ts index f4edba2..bb68890 100644 --- a/src/global.ts +++ b/src/global.ts @@ -13,7 +13,7 @@ export const Graphics = PIXI.Graphics; export const Container = PIXI.Container; // Textures files -export const JSON_TEXTURES = "textures/textures.json"; +export const JSON_TEXTURES = "public/textures/textures.json"; // Level foler export const LEVEL_FOLDER = "/level/"; diff --git a/src/index.ts b/src/index.ts index 1cdfc07..77b4bfe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,9 @@ import {MetaCar} from "./metacar"; -export default MetaCar; \ No newline at end of file +import {embeddedUrl} from "./embedded"; + +const metacar = { + env: MetaCar, + level: embeddedUrl +} + +export default metacar; \ No newline at end of file diff --git a/src/level.ts b/src/level.ts index 0e84bb8..8d48093 100644 --- a/src/level.ts +++ b/src/level.ts @@ -8,9 +8,9 @@ import * as U from "./utils"; import { LEVEL_FOLDER, ROADSIZE, Loader, JSON_TEXTURES } from "./global"; -import {AssetManger, RoadSprite, SimpleSprite, AssetInfo, } from "./asset_manager"; +import {AssetManger, RoadSprite} from "./asset_manager"; -import {Car} from "./car"; +import {Car, CarSprite} from "./car"; export interface LevelInfo { map: (string|number)[][]; @@ -24,26 +24,27 @@ export interface Roads { export class Level { - private app: any = null; // The pixi app. - private name: string = null; // Name fo the level + public app: any = null; // The pixi app. private info: LevelInfo = null; // Information of the loaded level private envs: any[] = [] // Used to list all elements the car can crash with private map: (string|number)[][] = null; // Use the roads positions of the level - private agent: any = null; // (@Car class) for the agent + public agent: any = null; // (@Car class) for the agent // Object to store all the roads assets // Each road is accesible as follow this.roads[[my, mx]] // with my and mx the (x, y) position relative to the map (not pixel). - private roads: Roads; - private cars: any; // Array used to store all the cars assets + private roads: Roads = {}; + private cars: Car[] = []; // Array used to store all the cars assets private loop: any; // Loop method called for each render private am: AssetManger; // The AssetManger is used to set most of the elements on the map private canvasId: string; // Id of the target canvas - constructor(levelName: string, canvasId: string) { + constructor(levelContent: LevelInfo, canvasId: string) { /* - @levelName: Name of the level to load (.json) + @levelContent: Content of the level + @canvasID: HTML canvas id */ - this.name = levelName; + this.info = levelContent; + this.map = this.info.map; this.canvasId = canvasId; this.am = new AssetManger(this); } @@ -55,13 +56,7 @@ export class Level { */ this.loop = loop; return new Promise((resolve, reject) => { - // Load the level - U.loadJSON(LEVEL_FOLDER + this.name, (response: string) => { - // Parse JSON string into object - this.info = JSON.parse(response); - this.map = this.info.map; // Store the map to let it accessible faster later on. - this.createLevel(this.info).then(() => resolve()); - }); + this.createLevel(this.info).then(() => resolve()); }); } @@ -81,7 +76,7 @@ export class Level { document.getElementById(this.canvasId).appendChild(this.app.view); return new Promise((resolve, reject) => { - Loader.add(["textures/textures.json", "textures/textures.png"]).load(() => { + Loader.add(["public/textures/textures.json", "public/textures/textures.png"]).load(() => { this.setup(info); // Set up the level (Add assets) resolve(); }); @@ -193,6 +188,10 @@ export class Level { getRoad(my: number, mx: number){ return this.roads[[my.toString(), mx.toString()].toString()]; } + + getRoads(){ + return this.roads; + } findCarById(id: number){ /* diff --git a/src/metacar.ts b/src/metacar.ts index 971317b..88fd91f 100644 --- a/src/metacar.ts +++ b/src/metacar.ts @@ -2,26 +2,52 @@ Main class of the project */ -import {Level} from "./level"; +import {Level, LevelInfo} from "./level"; +import * as U from "./utils"; export class MetaCar { private isPlaying: boolean; private agent: any; private level: Level; + private canvasId: string; + private levelUrl: string; - constructor() { + constructor(canvasId: string, levelUrl: string) { + /** + * @canvasId: HTML canvas ID to used + * @level: URL or Local storage URL. + * localstorage://level-name + * embedded:// + * http(s):// + */ + if (!canvasId || this.levelUrl){ + console.error("You must specify the canvasId and the levelUrl"); + } + this.isPlaying = false; + this.canvasId = canvasId; + this.levelUrl = levelUrl; } - load(level: string, agent: any){ + load(level: string, agent: any): Promise{ /* Load the environement @level (String) Name of the json level to load @agent (Agent class) */ - this.isPlaying = false; + + return new Promise((resolve, reject) => { + U.loadCustomURL(this.levelUrl, (content: LevelInfo) => { + this.level = new Level(content, this.canvasId); + this.level.load((delta: number) => this.loop(delta)); + resolve(); + }); + }); + + /* + this.agent = agent; - this.level = new Level(level); + this.level = new Level(level, "canvas"); this.level.load((delta: number) => this.loop(delta)); document.getElementById("train").addEventListener("click", () => { @@ -45,6 +71,7 @@ export class MetaCar { document.getElementById("dumpFile").addEventListener("change", (e) => { //readDump(e, (content) => this.agent.restore(this, content)); }); + */ } render(){ @@ -59,7 +86,7 @@ export class MetaCar { /* Save the agent */ - saveAs(content, file_name); + U.saveAs(content, file_name); } actionSpace(){ @@ -97,10 +124,11 @@ export class MetaCar { This position */ this.level.agent.last_position = []; - let keys = Object.keys(this.level.roads); + let roads = this.level.getRoads(); + let keys = Object.keys(roads); keys.sort(function() {return Math.random()-0.5;}); for (let k in keys){ - let road = this.level.roads[keys[k]]; + let road = roads[keys[k]]; if (road.cars.length == 0){ road.setCarPosition(this.level.agent.core); break; @@ -115,7 +143,6 @@ export class MetaCar { else { this.level.step(delta); } - document.getElementById("rewardDisplay").innerHTML = this.level.last_reward; } } diff --git a/src/motion_engine.ts b/src/motion_engine.ts index 351574e..0ff9efc 100644 --- a/src/motion_engine.ts +++ b/src/motion_engine.ts @@ -8,6 +8,7 @@ import {Level} from "./level"; import { MAP } from "./global"; +import { Editor } from "./editor"; export interface MotionOption{ readonly rotationStep?: number; @@ -16,12 +17,12 @@ export interface MotionOption{ export class MotionEngine { - protected level: Level; + protected level: Level|Editor; protected car: any; protected lidar: any; protected state: any; - constructor(level: Level) { + constructor(level: Level|Editor) { this.level = level; } @@ -53,7 +54,7 @@ export class MotionEngine { if (envs[i] != this.car && envs[i].obstacle && this.boxesIntersect(envs[i], this.car)){ agent_col.push(envs[i]); } - else if (envs[i].map_id == MAP.ROAD && this.boxesIntersect(envs[i], this.car)){ + else if (envs[i].mapId == MAP.ROAD && this.boxesIntersect(envs[i], this.car)){ on_road = true; } if (this.boxesIntersect(envs[i], this.lidar)){ @@ -70,16 +71,14 @@ export class MotionEngine { Set up the current state of the agent @lidar_collisions List with all possible lidar collisions */ - let state = []; - let f = 0.1; let pt_id = 0; for (var i = 0; i < this.lidar.children.length; i++) { this.lidar.children[i].alpha = 0.1; if (this.lidar.children[i].pt){ // If this is a lidar point - let pt_y = Math.round(pt_id/this.lidar.pts); - let pt_x = Math.round(pt_id%this.lidar.pts); + let pt_y = Math.floor(pt_id/this.lidar.pts); + let pt_x = Math.floor(pt_id%this.lidar.pts); this.state[pt_y][pt_x] = MAP.DEFAULT; for (var a = 0; a < lidar_collisions.length; a++) { @@ -89,11 +88,11 @@ export class MotionEngine { // If this is an obstacle this.lidar.children[i].alpha = 1.; } - if (touch && (lidar_collisions[a].map_id > this.state[pt_y][pt_x] || (lidar_collisions[a].map_id == MAP.ROAD && this.state[pt_y][pt_x]==MAP.DEFAULT))){ + if (touch && (lidar_collisions[a].mapId > this.state[pt_y][pt_x] || (lidar_collisions[a].mapId == MAP.ROAD && this.state[pt_y][pt_x]==MAP.DEFAULT))){ // Add this interaction to the state // If this interaction is more important than the one befor // we kept the more important one - this.state[pt_y][pt_x] = lidar_collisions[a].map_id; + this.state[pt_y][pt_x] = lidar_collisions[a].mapId; } } } diff --git a/src/utils.ts b/src/utils.ts index c263f75..6a995ef 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,5 @@ +import {embeddedContent} from "./embedded"; + /* File with some usefull methods */ @@ -19,6 +21,33 @@ export function loadJSON(url: string, callback: any) { xobj.send(null); } +export function loadEmbeddedURL(url: string, callback: any):void { + let split = url.split("//"); + split = split[1].split("/"); + callback(embeddedContent[split[0]][split[1]]); +} + +export function loadLocalStorageURL(url: string, callback: any):void{ +} + +export function loadCustomURL(url: string, callback: any):void { + /** + * @url: CustomURL to load + * localstorage://level-name + * http(s):// + * embedded::// + @callback function onece the content is loaded + */ + const customCall: any = { + "embedded:": loadEmbeddedURL, + "http://": loadJSON, + "https://": loadJSON, + "localstorage://": loadLocalStorageURL + } + const split = url.split("//"); + customCall[split[0]](url, callback); +} + export function mod(n: number, m:number) { return ((n % m) + m) % m; } @@ -33,7 +62,7 @@ export function argMax(array: number[]) { return array.map((x, i) => [x, i]).reduce((r, a) => (a[0] > r[0] ? a : r))[1]; } -export function mean(array: number){ +export function mean(array: number[]){ /** * Return the mean of the array */ @@ -44,7 +73,7 @@ export function mean(array: number){ return avg; } -function saveAs(content: string, name: string) { +export function saveAs(content: string, name: string) { var a = document.createElement("a"); //a.style = "display: none"; document.body.appendChild(a); diff --git a/tsconfig.json b/tsconfig.json index cb7eb6b..1d7e967 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "target": "es5", "lib": ["es2015", "dom"], "outDir": "./dist-es6", - "noUnusedLocals": true, + "noUnusedLocals": false, "noImplicitReturns": true, "noImplicitThis": true, "alwaysStrict": true, diff --git a/webpack.config.js b/webpack.config.js index 2b334da..80ab419 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,4 +1,5 @@ const path = require('path'); +var webpack = require('webpack') var config = { entry: './src/index', @@ -7,26 +8,37 @@ var config = { { test: /\.ts$/, use: 'ts-loader', - }, + } ], }, resolve: { extensions: [ '.ts', ], - } + }, + externals: [ + // Don't bundle pixi.js, assume it'll be included in the HTML via a script + // tag, and made available in the global variable PIXI. + {"pixi.js": "PIXI"} + ] }; var packageConfig = Object.assign({}, config, { output: { filename: 'metacar.min.js', path: path.resolve(__dirname, './dist'), + library: 'metacar', + libraryTarget: 'window', + libraryExport: 'default' } }); var demoConfig = Object.assign({}, config,{ output: { filename: 'metacar.min.js', path: path.resolve(__dirname, './demo/dist'), + library: 'metacar', + libraryTarget: 'window', + libraryExport: 'default' } });