Rework Line gen, add stats & viewport
Generate 4 separate lines. Trains now follow lines and only spawn on connected stations.
This commit is contained in:
parent
a79f501c5e
commit
df9ba6d5ea
81
package-lock.json
generated
81
package-lock.json
generated
@ -980,6 +980,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/pixi.js/-/pixi.js-4.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pixi.js/-/pixi.js-4.7.2.tgz",
|
||||||
"integrity": "sha512-ybrqVdncNCa81fCYCqxz/CISyMbXl8usszNv0mwdeYDyfDqmemQHJtf4GtduHva+3suhItPc9Akr/WfV19zWiQ=="
|
"integrity": "sha512-ybrqVdncNCa81fCYCqxz/CISyMbXl8usszNv0mwdeYDyfDqmemQHJtf4GtduHva+3suhItPc9Akr/WfV19zWiQ=="
|
||||||
},
|
},
|
||||||
|
"@types/stats.js": {
|
||||||
|
"version": "0.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.0.tgz",
|
||||||
|
"integrity": "sha512-9w+a7bR8PeB0dCT/HBULU2fMqf6BAzvKbxFboYhmDtDkKPiyXYbjoe2auwsXlEFI7CFNMF1dCv3dFH5Poy9R1w=="
|
||||||
|
},
|
||||||
"@types/tinycolor2": {
|
"@types/tinycolor2": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.0.tgz",
|
||||||
@ -4406,6 +4411,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"exists": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/exists/-/exists-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-/8vuKRQvJAVt8Bkk5zJicz2xC0k="
|
||||||
|
},
|
||||||
"exit-hook": {
|
"exit-hook": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
|
||||||
@ -9205,6 +9215,11 @@
|
|||||||
"sha.js": "2.4.11"
|
"sha.js": "2.4.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"penner": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/penner/-/penner-0.1.3.tgz",
|
||||||
|
"integrity": "sha1-C4tILU6bOa8vPXw3WSIpuKzClwU="
|
||||||
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||||
@ -9226,11 +9241,46 @@
|
|||||||
"pinkie": "2.0.4"
|
"pinkie": "2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pixi-ease": {
|
||||||
|
"version": "0.18.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pixi-ease/-/pixi-ease-0.18.0.tgz",
|
||||||
|
"integrity": "sha512-qC9ofPKHblNlkdKDFgXDcw1vTPg4zDTLBudk32lScafOB59QKE5duElA+XwaS5kEpumVfnlKtg3k4gCcGcat3Q==",
|
||||||
|
"requires": {
|
||||||
|
"eventemitter3": "3.0.1",
|
||||||
|
"penner": "0.1.3",
|
||||||
|
"yy-angle": "1.2.0",
|
||||||
|
"yy-color": "1.0.7"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-QOCPu979MMWX9XNlfRZoin+Wm+bK1SP7vv3NGUniYwuSJK/+cPA10blMaeRgzg31RvoSFk6FsCDVa4vNryBTGA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"pixi-gl-core": {
|
"pixi-gl-core": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/pixi-gl-core/-/pixi-gl-core-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/pixi-gl-core/-/pixi-gl-core-1.1.4.tgz",
|
||||||
"integrity": "sha1-i0tcQzsx5Bm8N53FZc4bg1qRs3I="
|
"integrity": "sha1-i0tcQzsx5Bm8N53FZc4bg1qRs3I="
|
||||||
},
|
},
|
||||||
|
"pixi-viewport": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pixi-viewport/-/pixi-viewport-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-hMPtka90PulpBLXBhE3RZvKaB1VTPFoXe4dSuqsYYBQeo8b1G3FTy7WAfgqkqj1ibrblEf0MmTzO9PzoXKLKXA==",
|
||||||
|
"requires": {
|
||||||
|
"eventemitter3": "3.0.1",
|
||||||
|
"exists": "1.0.1",
|
||||||
|
"pixi-ease": "0.18.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-QOCPu979MMWX9XNlfRZoin+Wm+bK1SP7vv3NGUniYwuSJK/+cPA10blMaeRgzg31RvoSFk6FsCDVa4vNryBTGA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"pixi.js": {
|
"pixi.js": {
|
||||||
"version": "4.7.1",
|
"version": "4.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-4.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-4.7.1.tgz",
|
||||||
@ -10595,6 +10645,11 @@
|
|||||||
"integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=",
|
"integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"seedrandom": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
|
||||||
|
"integrity": "sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw="
|
||||||
|
},
|
||||||
"select-hose": {
|
"select-hose": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
||||||
@ -11159,6 +11214,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"stats.js": {
|
||||||
|
"version": "0.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz",
|
||||||
|
"integrity": "sha1-scPcRtlEmLV4t/05hbgaznExzH0="
|
||||||
|
},
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
|
||||||
@ -12966,6 +13026,27 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"yy-angle": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yy-angle/-/yy-angle-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sf311F5zlItZA0dH/mD3MMG6mIIo1b+9XsFqpLhKCTqFFUL4ip+XWTaQLWLRDkh/Ag0GzAsGt6rWcq61OU9+zQ=="
|
||||||
|
},
|
||||||
|
"yy-color": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/yy-color/-/yy-color-1.0.7.tgz",
|
||||||
|
"integrity": "sha1-P5IxiCQ/q8zqJNNy9Li24wk8Zak=",
|
||||||
|
"requires": {
|
||||||
|
"yy-random": "1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yy-random": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yy-random/-/yy-random-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-oMIO8eo4BVed+o8NDMGj9scboHWBFtOdip1oDpXhxYw3A03lYqDqtlwPLg8SOK0q95Fsdzj9EdCQMWFWRk3p7A==",
|
||||||
|
"requires": {
|
||||||
|
"seedrandom": "2.4.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/pixi.js": "^4.7.2",
|
"@types/pixi.js": "^4.7.2",
|
||||||
|
"@types/stats.js": "^0.17.0",
|
||||||
"@types/tinycolor2": "^1.4.0",
|
"@types/tinycolor2": "^1.4.0",
|
||||||
|
"pixi-viewport": "^1.5.0",
|
||||||
"pixi.js": "^4.7.1",
|
"pixi.js": "^4.7.1",
|
||||||
|
"stats.js": "^0.17.0",
|
||||||
"tinycolor2": "^1.4.1"
|
"tinycolor2": "^1.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
80
src/Line.ts
80
src/Line.ts
@ -1,72 +1,58 @@
|
|||||||
import * as tinycolor from 'tinycolor2';
|
import * as tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
import Direction, { getPointDirection } from './Direction';
|
import Direction, { getPointDirection } from './Direction';
|
||||||
|
import LineConnection from './LineConnection';
|
||||||
import Station from './Station';
|
import Station from './Station';
|
||||||
import { distance, randomInt, randomPoint } from './utils';
|
import { distance, randomInt, randomPoint } from './utils';
|
||||||
|
|
||||||
const CONNECTION_RADIUS = Math.floor(Math.sqrt(
|
const CONNECTION_RADIUS = Math.floor(Math.sqrt(
|
||||||
Math.pow(window.innerWidth, 2) + Math.pow(window.innerHeight, 2),
|
Math.pow(window.innerWidth, 2) + Math.pow(window.innerHeight, 2),
|
||||||
) / 4);
|
) / 8);
|
||||||
|
|
||||||
export default class Line {
|
export default class Line {
|
||||||
public static getLinesWithStation(lines: Line[], station: Station): Line[] {
|
public name: string;
|
||||||
return lines.filter(line => line.stations.indexOf(station) >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public stations: Station[];
|
|
||||||
public color: tinycolorInstance;
|
public color: tinycolorInstance;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
stations: Station[],
|
name: string,
|
||||||
start: PIXI.Point,
|
|
||||||
startDirection: Direction,
|
|
||||||
numStations: number,
|
|
||||||
color: tinycolorInstance,
|
color: tinycolorInstance,
|
||||||
) {
|
) {
|
||||||
|
this.name = name;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.stations = [];
|
}
|
||||||
let stationsLeft = stations.slice();
|
|
||||||
let currentStation = Station.randomCloseLargeStation(stationsLeft, start, CONNECTION_RADIUS);
|
|
||||||
stationsLeft = stationsLeft.filter(s => s !== currentStation);
|
|
||||||
this.stations.push(currentStation);
|
|
||||||
|
|
||||||
let direction = startDirection;
|
public connectStations(
|
||||||
while (this.stations.length < numStations) {
|
currentStation: Station,
|
||||||
const previousStation = this.stations[this.stations.length - 1];
|
stations: Station[],
|
||||||
let candidateStations = Station.stationsWithinRadius(
|
visitedStations: Station[],
|
||||||
stationsLeft,
|
connectionLimit: number,
|
||||||
|
) {
|
||||||
|
visitedStations.push(currentStation);
|
||||||
|
const otherStations = stations.filter(station => station !== currentStation);
|
||||||
|
const closeStations = Station.stationsWithinRadius(
|
||||||
|
otherStations,
|
||||||
currentStation.location,
|
currentStation.location,
|
||||||
CONNECTION_RADIUS,
|
CONNECTION_RADIUS,
|
||||||
);
|
);
|
||||||
|
for (let i = 0; i < connectionLimit; i += 1) {
|
||||||
if (this.stations.length > 1) {
|
if (closeStations.length < 1) {
|
||||||
const secondPreviousStation = this.stations[this.stations.length - 2];
|
|
||||||
direction = getPointDirection(secondPreviousStation.location,
|
|
||||||
previousStation.location);
|
|
||||||
}
|
|
||||||
|
|
||||||
const straightStations = Station.stationsInDirection(
|
|
||||||
candidateStations, previousStation.location, direction,
|
|
||||||
);
|
|
||||||
const leftStations = Station.stationsInDirection(
|
|
||||||
candidateStations, previousStation.location, (direction - 1) % 7,
|
|
||||||
);
|
|
||||||
const rightStations = Station.stationsInDirection(
|
|
||||||
candidateStations, previousStation.location, (direction + 1) % 7,
|
|
||||||
);
|
|
||||||
candidateStations = [
|
|
||||||
...straightStations,
|
|
||||||
...leftStations,
|
|
||||||
...rightStations,
|
|
||||||
];
|
|
||||||
|
|
||||||
currentStation = Station.randomCloseLargeStation(candidateStations, previousStation.location,
|
|
||||||
CONNECTION_RADIUS);
|
|
||||||
if (currentStation === null || currentStation === undefined) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stationsLeft = stationsLeft.filter(s => s !== currentStation);
|
const largest = Station.largestStation(closeStations);
|
||||||
this.stations.push(currentStation);
|
currentStation.connections.push(
|
||||||
|
new LineConnection(largest, this),
|
||||||
|
);
|
||||||
|
closeStations.splice(closeStations.indexOf(largest), 1);
|
||||||
|
}
|
||||||
|
for (const connectedStation of currentStation.connections) {
|
||||||
|
if (visitedStations.indexOf(connectedStation.station) === -1) {
|
||||||
|
this.connectStations(
|
||||||
|
connectedStation.station,
|
||||||
|
stations,
|
||||||
|
visitedStations,
|
||||||
|
connectionLimit,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/LineConnection.ts
Normal file
15
src/LineConnection.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Line from './Line';
|
||||||
|
import Station from './Station';
|
||||||
|
|
||||||
|
export default class LineConnection {
|
||||||
|
public station: Station;
|
||||||
|
public line: Line;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
station: Station,
|
||||||
|
line: Line,
|
||||||
|
) {
|
||||||
|
this.station = station;
|
||||||
|
this.line = line;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import * as tinycolor from 'tinycolor2';
|
import * as tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
import Direction, { getPointDirection } from './Direction';
|
import Direction, { getPointDirection } from './Direction';
|
||||||
|
import LineConnection from './LineConnection';
|
||||||
import { distance, randomPoint, weightedRandom } from './utils';
|
import { distance, randomPoint, weightedRandom } from './utils';
|
||||||
|
|
||||||
let stationCount = 0;
|
let stationCount = 0;
|
||||||
@ -65,7 +66,7 @@ export default class Station {
|
|||||||
|
|
||||||
public location: PIXI.Point;
|
public location: PIXI.Point;
|
||||||
public population: number;
|
public population: number;
|
||||||
public connections: Station[];
|
public connections: LineConnection[];
|
||||||
public id: number;
|
public id: number;
|
||||||
public label: PIXI.Text;
|
public label: PIXI.Text;
|
||||||
public color: tinycolorInstance;
|
public color: tinycolorInstance;
|
||||||
@ -74,12 +75,12 @@ export default class Station {
|
|||||||
location: PIXI.Point,
|
location: PIXI.Point,
|
||||||
population: number,
|
population: number,
|
||||||
color: tinycolorInstance,
|
color: tinycolorInstance,
|
||||||
connections?: Station[],
|
connections?: LineConnection[],
|
||||||
) {
|
) {
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.population = population;
|
this.population = population;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.connections = connections;
|
this.connections = connections || [];
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
stationCount += 1;
|
stationCount += 1;
|
||||||
|
129
src/transport.ts
129
src/transport.ts
@ -1,4 +1,6 @@
|
|||||||
|
import * as Viewport from 'pixi-viewport';
|
||||||
import * as PIXI from 'pixi.js';
|
import * as PIXI from 'pixi.js';
|
||||||
|
import * as Stats from 'stats.js';
|
||||||
import * as tinycolor from 'tinycolor2';
|
import * as tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
import Direction from './Direction';
|
import Direction from './Direction';
|
||||||
@ -16,10 +18,14 @@ const NODE_RES = 100;
|
|||||||
const MAX_SPEED = 10.0;
|
const MAX_SPEED = 10.0;
|
||||||
const ACCELERATION = 0.025;
|
const ACCELERATION = 0.025;
|
||||||
const APPROACH_DISTANCE = 3.0;
|
const APPROACH_DISTANCE = 3.0;
|
||||||
const MAX_JOURNEY = Math.floor(Math.sqrt(
|
|
||||||
Math.pow(window.innerWidth, 2) + Math.pow(window.innerHeight, 2),
|
|
||||||
) / 4);
|
|
||||||
const TRAIN_CAPACITY = 50;
|
const TRAIN_CAPACITY = 50;
|
||||||
|
const LINE_CONNECTION_LIMIT = 5;
|
||||||
|
const WORLD_WIDTH = 1000;
|
||||||
|
const WORLD_HEIGHT = 1000;
|
||||||
|
const ZOOM_MIN_WIDTH = 100;
|
||||||
|
const ZOOM_MIN_HEIGHT = 100;
|
||||||
|
const ZOOM_MAX_WIDTH = 4000;
|
||||||
|
const ZOOM_MAX_HEIGHT = 4000;
|
||||||
|
|
||||||
const trainTexts: PIXI.Text[] = [];
|
const trainTexts: PIXI.Text[] = [];
|
||||||
|
|
||||||
@ -36,8 +42,11 @@ const initStations = (numStations: number): Station[] => {
|
|||||||
|
|
||||||
const initTrains = (numTrains: number, stations: Station[]): Train[] => {
|
const initTrains = (numTrains: number, stations: Station[]): Train[] => {
|
||||||
const trains = [];
|
const trains = [];
|
||||||
|
const stationsWithConnections = stations.filter(station => station.connections.length > 0);
|
||||||
for (let i = 0; i < numTrains; i += 1) {
|
for (let i = 0; i < numTrains; i += 1) {
|
||||||
const originStation = stations[Math.floor(Math.random() * stations.length)];
|
const originStation = stationsWithConnections[
|
||||||
|
Math.floor(Math.random() * stationsWithConnections.length)
|
||||||
|
];
|
||||||
trains.push(new Train(
|
trains.push(new Train(
|
||||||
new PIXI.Point(originStation.location.x, originStation.location.y),
|
new PIXI.Point(originStation.location.x, originStation.location.y),
|
||||||
0, 0, originStation, undefined, tinycolor('grey')),
|
0, 0, originStation, undefined, tinycolor('grey')),
|
||||||
@ -46,15 +55,36 @@ const initTrains = (numTrains: number, stations: Station[]): Train[] => {
|
|||||||
return trains;
|
return trains;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initLines = (numLines: number, stations: Station[]): Line[] => {
|
||||||
|
const lines = [];
|
||||||
|
for (let i = 0; i < numLines; i += 1) {
|
||||||
|
let color = tinycolor.random();
|
||||||
|
while (color.isDark()) {
|
||||||
|
color = tinycolor.random();
|
||||||
|
}
|
||||||
|
const stationsWithoutConnections = stations.filter(station =>
|
||||||
|
station.connections.length === 0,
|
||||||
|
);
|
||||||
|
const centralHub = Station.largestStation(stationsWithoutConnections);
|
||||||
|
const line = new Line(`line-${i}`, tinycolor.random());
|
||||||
|
const stationsLeft = stations.slice(0);
|
||||||
|
line.connectStations(centralHub, stationsLeft, [], LINE_CONNECTION_LIMIT);
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
};
|
||||||
|
|
||||||
const moveTrains = (trains: Train[], stations: Station[]) => {
|
const moveTrains = (trains: Train[], stations: Station[]) => {
|
||||||
for (const train of trains) {
|
for (const train of trains) {
|
||||||
|
if (train.origin.connections.length === 0) {
|
||||||
|
// train is stuck at an orphaned station
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// choose a destination randomly with a bias towards larger stations
|
// choose a destination randomly with a bias towards larger stations
|
||||||
if (train.destination === undefined) {
|
if (train.destination === undefined) {
|
||||||
const otherStations = stations.filter(station => station !== train.origin);
|
const otherStations = train.origin.connections.map(conn => conn.station);
|
||||||
const closeStations = Station.stationsWithinRadius(otherStations, train.location,
|
const closeStationWeights = otherStations.map(station => station.population);
|
||||||
MAX_JOURNEY);
|
train.destination = weightedRandom(otherStations, closeStationWeights);
|
||||||
const closeStationWeights = closeStations.map(station => station.population);
|
|
||||||
train.destination = weightedRandom(closeStations, closeStationWeights);
|
|
||||||
|
|
||||||
// board passengers
|
// board passengers
|
||||||
const boardingPassengers = randomInt(0, Math.min(TRAIN_CAPACITY - train.passengers,
|
const boardingPassengers = randomInt(0, Math.min(TRAIN_CAPACITY - train.passengers,
|
||||||
@ -116,7 +146,7 @@ const moveTrains = (trains: Train[], stations: Station[]) => {
|
|||||||
|
|
||||||
const drawStations = (stations: Station[], graphics: PIXI.Graphics) => {
|
const drawStations = (stations: Station[], graphics: PIXI.Graphics) => {
|
||||||
for (const station of stations) {
|
for (const station of stations) {
|
||||||
const radius = station.population / 60;
|
const radius = station.population / 150;
|
||||||
graphics.beginFill(parseInt(station.color.toHex(), 16), 0.5);
|
graphics.beginFill(parseInt(station.color.toHex(), 16), 0.5);
|
||||||
graphics.drawCircle(station.location.x, station.location.y, radius);
|
graphics.drawCircle(station.location.x, station.location.y, radius);
|
||||||
graphics.endFill();
|
graphics.endFill();
|
||||||
@ -127,10 +157,6 @@ const drawStations = (stations: Station[], graphics: PIXI.Graphics) => {
|
|||||||
|
|
||||||
const drawTrains = (trains: Train[], graphics: PIXI.Graphics) => {
|
const drawTrains = (trains: Train[], graphics: PIXI.Graphics) => {
|
||||||
for (const train of trains) {
|
for (const train of trains) {
|
||||||
// graphics.beginFill(parseInt(train.color.toHex(), 16), 0.8);
|
|
||||||
// graphics.drawCircle(train.location.x, train.location.y,
|
|
||||||
// rangeMap(train.passengers, 0, TRAIN_CAPACITY, 1, 5));
|
|
||||||
// graphics.endFill();
|
|
||||||
const trainSize = rangeMap(train.passengers, 0, TRAIN_CAPACITY, 1, 5);
|
const trainSize = rangeMap(train.passengers, 0, TRAIN_CAPACITY, 1, 5);
|
||||||
const scale = trainSize / NODE_RES;
|
const scale = trainSize / NODE_RES;
|
||||||
train.sprite.x = train.location.x;
|
train.sprite.x = train.location.x;
|
||||||
@ -143,13 +169,18 @@ const drawTrains = (trains: Train[], graphics: PIXI.Graphics) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawLines = (lines: Line[], graphics: PIXI.Graphics) => {
|
const drawLines = (stations: Station[], graphics: PIXI.Graphics) => {
|
||||||
for (const line of lines) {
|
for (const station of stations) {
|
||||||
graphics.lineStyle(1, parseInt(line.color.toHex(), 16), 1);
|
for (const connection of station.connections) {
|
||||||
const start = line.stations[0].location;
|
let twoWay = false;
|
||||||
graphics.moveTo(start.x, start.y);
|
for (const conn of connection.station.connections) {
|
||||||
for (const station of line.stations.slice(1)) {
|
if (conn.station === station) {
|
||||||
graphics.lineTo(station.location.x, station.location.y);
|
twoWay = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
graphics.lineStyle(twoWay ? 2 : 1, parseInt(connection.line.color.toHex(), 16), 1);
|
||||||
|
graphics.moveTo(station.location.x, station.location.y);
|
||||||
|
graphics.lineTo(connection.station.location.x, connection.station.location.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -160,41 +191,29 @@ const run = () => {
|
|||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
});
|
});
|
||||||
|
const viewport = new Viewport({
|
||||||
|
screenHeight: window.innerHeight,
|
||||||
|
screenWidth: window.innerWidth,
|
||||||
|
worldHeight: WORLD_HEIGHT,
|
||||||
|
worldWidth: WORLD_WIDTH,
|
||||||
|
});
|
||||||
|
const stats = new Stats();
|
||||||
|
stats.showPanel(0);
|
||||||
|
document.body.appendChild(stats.dom);
|
||||||
const ticker = new PIXI.ticker.Ticker();
|
const ticker = new PIXI.ticker.Ticker();
|
||||||
const graphics = new PIXI.Graphics();
|
const graphics = new PIXI.Graphics();
|
||||||
const fpsText = new PIXI.Text('', { fontSize: '25px', fontFamily: 'monospace', fill: 'yellow' });
|
|
||||||
|
|
||||||
fpsText.anchor = new PIXI.ObservablePoint(null, 0, 1);
|
|
||||||
fpsText.x = window.innerWidth;
|
|
||||||
fpsText.y = 0;
|
|
||||||
|
|
||||||
const stations = initStations(30);
|
const stations = initStations(30);
|
||||||
|
const lines = initLines(4, stations);
|
||||||
const trains = initTrains(50, stations);
|
const trains = initTrains(50, stations);
|
||||||
const lines = [
|
|
||||||
new Line(
|
|
||||||
stations, new PIXI.Point(0, 0),
|
|
||||||
Direction.Southeast, 12, tinycolor('red'),
|
|
||||||
),
|
|
||||||
new Line(
|
|
||||||
stations, new PIXI.Point(window.innerWidth, 0),
|
|
||||||
Direction.Southwest, 12, tinycolor('darkcyan'),
|
|
||||||
),
|
|
||||||
new Line(
|
|
||||||
stations, new PIXI.Point(window.innerWidth, window.innerHeight),
|
|
||||||
Direction.Northwest, 12, tinycolor('yellow'),
|
|
||||||
),
|
|
||||||
new Line(
|
|
||||||
stations, new PIXI.Point(0, window.innerHeight),
|
|
||||||
Direction.Northeast, 12, tinycolor('green'),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
ticker.stop();
|
ticker.stop();
|
||||||
ticker.add((deltaTime) => {
|
ticker.add((deltaTime) => {
|
||||||
|
stats.begin();
|
||||||
|
|
||||||
moveTrains(trains, stations);
|
moveTrains(trains, stations);
|
||||||
|
|
||||||
graphics.clear();
|
graphics.clear();
|
||||||
fpsText.text = `${Math.round(ticker.FPS)}`;
|
|
||||||
|
|
||||||
graphics.lineStyle(1, 0xFFA500, 1);
|
graphics.lineStyle(1, 0xFFA500, 1);
|
||||||
drawStations(stations, graphics);
|
drawStations(stations, graphics);
|
||||||
@ -202,24 +221,32 @@ const run = () => {
|
|||||||
graphics.lineStyle(1, 0xAEAEAE, 1);
|
graphics.lineStyle(1, 0xAEAEAE, 1);
|
||||||
drawTrains(trains, graphics);
|
drawTrains(trains, graphics);
|
||||||
|
|
||||||
drawLines(lines, graphics);
|
drawLines(stations, graphics);
|
||||||
|
|
||||||
|
stats.end();
|
||||||
});
|
});
|
||||||
ticker.start();
|
ticker.start();
|
||||||
|
|
||||||
app.stage.addChild(graphics);
|
viewport.addChild(graphics);
|
||||||
app.stage.addChild(fpsText);
|
|
||||||
// add train sprites
|
// add train sprites
|
||||||
for (const train of trains) {
|
for (const train of trains) {
|
||||||
app.stage.addChild(train.sprite);
|
viewport.addChild(train.sprite);
|
||||||
}
|
}
|
||||||
// Add debug labels
|
// Add debug labels
|
||||||
for (const train of trains) {
|
for (const train of trains) {
|
||||||
app.stage.addChild(train.label);
|
viewport.addChild(train.label);
|
||||||
}
|
}
|
||||||
for (const station of stations) {
|
for (const station of stations) {
|
||||||
app.stage.addChild(station.label);
|
viewport.addChild(station.label);
|
||||||
}
|
}
|
||||||
document.body.appendChild(app.view);
|
document.body.appendChild(app.view);
|
||||||
|
app.stage.addChild(viewport);
|
||||||
|
viewport.drag().pinch().wheel().clampZoom({
|
||||||
|
maxHeight: ZOOM_MAX_HEIGHT,
|
||||||
|
maxWidth: ZOOM_MAX_WIDTH,
|
||||||
|
minHeight: ZOOM_MIN_HEIGHT,
|
||||||
|
minWidth: ZOOM_MIN_WIDTH,
|
||||||
|
}).decelerate();
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
app.renderer.resize(window.innerWidth, window.innerHeight);
|
app.renderer.resize(window.innerWidth, window.innerHeight);
|
||||||
|
@ -10,6 +10,7 @@ module.exports = {
|
|||||||
filename: 'transport.js',
|
filename: 'transport.js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
},
|
},
|
||||||
|
mode: env === 'production' ? 'production' : 'development',
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user