mirror of
https://github.com/wassname/metacar.git
synced 2026-09-09 11:26:47 +08:00
Full city: ok
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
*.baseDir.ts*
|
||||
node_modules/*
|
||||
dist/dist-es6/*
|
||||
demo/dist/dist-es6/*
|
||||
demo/node_modules/
|
||||
*package-lock.json*
|
||||
+10
-22
@@ -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<files.length;i++){
|
||||
var filename=path.join(startPath,files[i]);
|
||||
var stat = fs.lstatSync(filename);
|
||||
if (stat.isDirectory()){
|
||||
fromDir(filename,filter); //recurse
|
||||
}
|
||||
else if (filename.indexOf(filter)>=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]
|
||||
|
||||
Vendored
+257
File diff suppressed because one or more lines are too long
+2
-1
@@ -9,6 +9,7 @@
|
||||
"author": "Thibault Neveu",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.16.3"
|
||||
"express": "^4.16.3",
|
||||
"pixi.js": "^4.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,26 @@
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="canvas" id="canvas"></div>
|
||||
|
||||
<div class="mainButton">
|
||||
<button id="train">Train</button>
|
||||
<button id="play">Play</button>
|
||||
<button id="stop">Stop</button>
|
||||
<button id="reset">Reset</button>
|
||||
<button id="saveAgent">Save</button>
|
||||
<button onclick="document.getElementById('dumpFile').click();">Load</button>
|
||||
<input id="dumpFile" type='file' accept='*/*' style="display: none">
|
||||
<br>
|
||||
<br>
|
||||
<span id="rewardDisplay"></span>
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.7.1/pixi.min.js"></script>
|
||||
<script src="/dist/metacar.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/public/js/full_city.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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
|
||||
|
||||
});
|
||||
@@ -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$"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Vendored
+257
File diff suppressed because one or more lines are too long
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
+27
-17
@@ -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"]
|
||||
}
|
||||
}
|
||||
|
||||
+17
-11
@@ -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)){
|
||||
|
||||
+16
-8
@@ -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;
|
||||
|
||||
+332
@@ -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((<HTMLInputElement>width_input).value);
|
||||
var height = parseInt((<HTMLInputElement>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;
|
||||
(<HTMLInputElement>width_input).value = width.toString();
|
||||
(<HTMLInputElement>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((<HTMLInputElement>width_input).value);
|
||||
editor.resize(width, height);
|
||||
}
|
||||
|
||||
height_input.onchange = () => {
|
||||
height = parseInt((<HTMLInputElement>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());
|
||||
}*/
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
]
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -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/";
|
||||
|
||||
|
||||
+8
-1
@@ -1,2 +1,9 @@
|
||||
import {MetaCar} from "./metacar";
|
||||
export default MetaCar;
|
||||
import {embeddedUrl} from "./embedded";
|
||||
|
||||
const metacar = {
|
||||
env: MetaCar,
|
||||
level: embeddedUrl
|
||||
}
|
||||
|
||||
export default metacar;
|
||||
+17
-18
@@ -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){
|
||||
/*
|
||||
|
||||
+36
-9
@@ -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<void>{
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-2
@@ -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);
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
"target": "es5",
|
||||
"lib": ["es2015", "dom"],
|
||||
"outDir": "./dist-es6",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedLocals": false,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"alwaysStrict": true,
|
||||
|
||||
+14
-2
@@ -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'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user