diff --git a/public/blobs/snr/sprite/LargeLady.png b/public/blobs/snr/sprite/LargeLady.png new file mode 100644 index 0000000..54166bd Binary files /dev/null and b/public/blobs/snr/sprite/LargeLady.png differ diff --git a/src/state/states/LoadState.ts b/src/state/states/LoadState.ts index c7f2268..363b853 100644 --- a/src/state/states/LoadState.ts +++ b/src/state/states/LoadState.ts @@ -36,6 +36,7 @@ export class LoadState extends State { // This should be driven by a manifest resources.set("snr:sprite/engine", new Image()); + resources.set("snr:sprite/LargeLady", new Image()); // resources.get("snr:sprite/engine")!.src = // "/sprites/EngineSprites.png"; resources.ready().then(() => { diff --git a/src/state/states/RunningState.ts b/src/state/states/RunningState.ts index 353ba67..2e24b48 100644 --- a/src/state/states/RunningState.ts +++ b/src/state/states/RunningState.ts @@ -8,6 +8,7 @@ import { DotFollower } from "../../train/newTrain.ts"; import { Train } from "../../train/train.ts"; import { State } from "../machine.ts"; import { States } from "./index.ts"; +import { LargeLady } from "../../train/LargeLady.ts"; export class RunningState extends State { override name: States = States.RUNNING; @@ -58,9 +59,11 @@ export class RunningState extends State { // const path = track.path; // const follower = new DotFollower(path, path.points[0].copy()); // ctx.trains.push(follower); - const train = new Train(track.path, [new RedEngine(), new Tender()]); - ctx.trains.push(train); + // const train = new Train(track.path, [new LargeLady(), new Tender()]); + // ctx.trains.push(train); }); + const train = new Train(track.path, [new LargeLady()], 1080); + ctx.trains.push(train); // const trainCount = 1000; // for (let i = 0; i < trainCount; i++) { // const train = new Train(track.path, [new RedEngine(), new Tender()]); diff --git a/src/train/LargeLady.ts b/src/train/LargeLady.ts new file mode 100644 index 0000000..88d5272 --- /dev/null +++ b/src/train/LargeLady.ts @@ -0,0 +1,118 @@ +import { Doodler, Vector } from "@bearmetal/doodler"; +import { TrainCar } from "./train.ts"; +import { getContextItem } from "../lib/context.ts"; +import { ResourceManager } from "../lib/resources.ts"; + +export class LargeLady extends TrainCar { + scale = 1; + constructor() { + const resources = getContextItem("resources"); + const img = resources.get("snr:sprite/LargeLady")!; + super(50, 10, img, 160, 23, { + at: new Vector(0, 0), + width: 160, + height: 23, + }); + + this.bogies = [ + { + pos: new Vector(0, 0), + angle: 0, + length: 35 * this.scale, + sprite: { + at: new Vector(0, 23), + width: 33, + height: 19, + offset: new Vector(-19, -9), + }, + }, + { + pos: new Vector(0, 0), + angle: 0, + length: 64 * this.scale, + // sprite: { + // at: new Vector(0, 23), + // width: 33, + // height: 19, + // offset: new Vector(-19, -9.5), + // }, + sprite: { + at: new Vector(34, 23), + width: 51, + height: 19, + offset: new Vector(-25.5, -9.5), + }, + }, + { + pos: new Vector(0, 0), + angle: 0, + length: 35 * this.scale, + sprite: { + at: new Vector(34, 23), + width: 60, + height: 19, + offset: new Vector(-25.5, -9.5), + }, + rotate: true, + }, + { + pos: new Vector(0, 0), + angle: 0, + length: 0, + sprite: { + at: new Vector(95, 23), + width: 16, + height: 19, + offset: new Vector(-8, -9.5), + }, + }, + ]; + } + + override draw(): void { + const doodler = getContextItem("doodler"); + for (const b of this.bogies) { + if (!b.sprite) continue; + doodler.drawRotated(b.pos, b.angle + (b.rotate ? 0 : Math.PI), () => { + doodler.drawSprite( + this.img, + b.sprite!.at, + b.sprite!.width, + b.sprite!.height, + b.pos.copy().add(b.sprite!.offset ?? new Vector(0, 0)), + b.sprite!.width, + b.sprite!.height, + ); + }); + } + + const c = this.bogies[2]; + const b = this.bogies[1]; + const origin = c.pos.copy().add(new Vector(18, 0).rotate(c.angle)); + const difAngle = Vector.sub(b.pos, c.pos).heading(); + const angle = c.angle; + const avgAngle = (difAngle + angle) / 2; + + doodler.drawCircle(origin, 4, { color: "blue" }); + + doodler.drawRotated(origin, avgAngle + Math.PI, () => { + this.sprite + ? doodler.drawSprite( + this.img, + this.sprite.at, + this.sprite.width, + this.sprite.height, + origin.copy().sub( + this.imgWidth * this.scale / 2, + this.imgHeight * this.scale / 2, + ), + this.imgWidth * this.scale, + this.imgHeight * this.scale, + ) + : doodler.drawImage( + this.img, + origin.copy().sub(this.imgWidth / 2, this.imgHeight / 2), + ); + }); + } +} diff --git a/src/train/train.ts b/src/train/train.ts index 77c258c..b0fd9fd 100644 --- a/src/train/train.ts +++ b/src/train/train.ts @@ -23,10 +23,10 @@ export class Train extends Debuggable { ); } - constructor(track: Spline, cars: TrainCar[]) { + constructor(track: Spline, cars: TrainCar[], t = 0) { super("train", "path"); this.path = track; - this.t = 0; + this.t = t; this.cars = cars; let currentOffset = 0; @@ -141,6 +141,8 @@ interface Bogie { pos: Vector; angle: number; length: number; + sprite?: ISprite & { offset?: Vector }; + rotate?: boolean; } export class TrainCar extends Debuggable { @@ -207,6 +209,7 @@ export class TrainCar extends Debuggable { const a = this.train.path.followEvenPoints(t - offset); offset += bogie.length; this.setBogiePosition(a.p, i); + bogie.angle = a.tangent.heading(); this.segments.add(a.segmentId); } return offset;