diff --git a/src/Station.ts b/src/Station.ts index d918d43..abac8a7 100644 --- a/src/Station.ts +++ b/src/Station.ts @@ -30,10 +30,12 @@ export default class Station { public connections: Station[]; public id: number; public label: PIXI.Text; + public color: number; - constructor(location: PIXI.Point, population: number, connections?: Station[]) { + constructor(location: PIXI.Point, population: number, color: number, connections?: Station[]) { this.location = location; this.population = population; + this.color = color; this.connections = connections; // for debugging diff --git a/src/transport.ts b/src/transport.ts index f22dcb9..39a633e 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -2,8 +2,8 @@ import * as PIXI from 'pixi.js'; import Line from './Line'; import Station from './Station'; import Train from './Train'; -import { distance, pointsAlmostEqual, pointsEqual, randomInt, randomPoint, - weightedRandom } from './utils'; +import { avgHexColor, distance, pointsAlmostEqual, pointsEqual, randomInt, randomPoint, + rangeMap, weightedRandom } from './utils'; import './style.css'; @@ -13,6 +13,7 @@ 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 trainTexts: PIXI.Text[] = []; @@ -40,20 +41,14 @@ const randomDistantPoint = (stations: Station[], minDistance: number): PIXI.Poin const initStations = (numStations: number): Station[] => { const stations: Station[] = []; for (let i = 0; i < numStations; i += 1) { - stations.push(new Station(randomDistantPoint(stations, 30), randomInt(100, 1000))); + stations.push(new Station( + randomDistantPoint(stations, 30), + randomInt(300, 2000), + randomInt(0x000000, 0xFFFFFF))); } return stations; }; -const drawStations = (stations: Station[], graphics: PIXI.Graphics) => { - for (const station of stations) { - const radius = station.population / 60; - graphics.drawCircle(station.location.x, station.location.y, radius); - station.label.x = station.location.x + radius + 1; - station.label.y = station.location.y + radius + 1; - } -}; - const initTrains = (numTrains: number, stations: Station[]): Train[] => { const trains = []; for (let i = 0; i < numTrains; i += 1) { @@ -75,11 +70,22 @@ const moveTrains = (trains: Train[], stations: Station[]) => { MAX_JOURNEY); const closeStationWeights = closeStations.map(station => station.population); train.destination = weightedRandom(closeStations, closeStationWeights); + + // board passengers + train.passengers += randomInt(0, TRAIN_CAPACITY); + train.origin.population -= randomInt(0, TRAIN_CAPACITY); } - // train reached destination, stop moving. + // train reached destination, stop moving and let passengers off if (pointsAlmostEqual(train.location, train.destination.location)) { train.speed = 0; + train.destination.population += train.passengers; + train.passengers = 0; + + // TODO: average colors + // train.destination.color = avgHexColor(train.origin.color, train.destination.color); + + // prepare for next journey train.origin = train.destination; train.destination = undefined; continue; @@ -103,9 +109,23 @@ const moveTrains = (trains: Train[], stations: Station[]) => { } }; +const drawStations = (stations: Station[], graphics: PIXI.Graphics) => { + for (const station of stations) { + const radius = station.population / 60; + graphics.beginFill(station.color, 0.5); + graphics.drawCircle(station.location.x, station.location.y, radius); + graphics.endFill(); + station.label.x = station.location.x + radius + 1; + station.label.y = station.location.y + radius + 1; + } +}; + const drawTrains = (trains: Train[], graphics: PIXI.Graphics) => { for (const train of trains) { - graphics.drawCircle(train.location.x, train.location.y, 2); + graphics.beginFill(train.origin.color, 0.8); + graphics.drawCircle(train.location.x, train.location.y, + rangeMap(train.passengers, 0, TRAIN_CAPACITY, 1, 5)); + graphics.endFill(); train.label.x = train.location.x + 1; train.label.y = train.location.y + 1; } @@ -134,7 +154,8 @@ const run = () => { fpsText.y = 0; const stations = initStations(30); - const trains = initTrains(15, stations); + const trains = initTrains(100, stations); + // const line = new Line(stations, 10); ticker.stop(); ticker.add((deltaTime) => { @@ -157,9 +178,9 @@ const run = () => { app.stage.addChild(graphics); app.stage.addChild(fpsText); // Add debug labels - for (const train of trains) { - app.stage.addChild(train.label); - } + // for (const train of trains) { + // app.stage.addChild(train.label); + // } for (const station of stations) { app.stage.addChild(station.label); } diff --git a/src/utils.ts b/src/utils.ts index c946193..e51e5c9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -37,3 +37,18 @@ export const distance = (pointA: PIXI.Point, pointB: PIXI.Point): number => { const distY = pointA.y - pointB.y; return Math.sqrt((distX * distX) + (distY * distY)); }; + +export const rangeMap = (num: number, inMin: number, inMax: number, + outMin: number, outMax: number): number => ( + (num - inMin) * (outMax - outMin) / (inMax - inMin) + outMin +); + +// tslint:disable no-bitwise +export const nthByte = (num: number, n: number): number => ((num >> (8 * n)) & 0xff); + +// FIXME: pretty sure this is wrong, just use a color library instead and then convert to hex +export const avgHexColor = (colorA: number, colorB: number): number => ( + (Math.round((nthByte(colorA, 2) + nthByte(colorB, 2)) / 2) & 0xFF) | + ((Math.round((nthByte(colorA, 1) + nthByte(colorB, 1)) / 2) & 0xFF) << 8) | + ((Math.round((nthByte(colorA, 0) + nthByte(colorB, 0)) / 2) & 0x0F) << 16) +);