From eb680c470fd14cbed0ebd609da169f92023a6e93 Mon Sep 17 00:00:00 2001 From: Emma Date: Sun, 16 Feb 2025 14:22:17 -0700 Subject: [PATCH] First iteration of the Large Lady --- public/blobs/snr/sprite/LargeLady.png | Bin 0 -> 1934 bytes src/state/states/LoadState.ts | 1 + src/state/states/RunningState.ts | 7 +- src/train/LargeLady.ts | 118 ++++++++++++++++++++++++++ src/train/train.ts | 7 +- 5 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 public/blobs/snr/sprite/LargeLady.png create mode 100644 src/train/LargeLady.ts diff --git a/public/blobs/snr/sprite/LargeLady.png b/public/blobs/snr/sprite/LargeLady.png new file mode 100644 index 0000000000000000000000000000000000000000..54166bdda8dd984345c696775daa090e6025b666 GIT binary patch literal 1934 zcmcgsi8mCA7ak+)OO`NMvae6kJdq_?2V=57M##jQu@ysxQ5f43l?uO*ilVXAWMmlA zWElw$F?O1 zm%kt^$m{p%A!h*qzQ4n4ZQY=@wklCK(ZOLiPym2VZc?s=W4o1N2g0*l%}dBU%LG}a z76g)sKI3&JEn~<#bhK@L$RKnm2Tw5(tq~BilznqTzn^MG5lx#F%K9*iUsBWL8tB$% zv1cjDKh`YPrul4Mef*Q8CtCFsg`We1pZUq~6D0;7sdR!>!Je*okm0%_g0s%v*8fOq zq92;>J#Oj-yl_-RQ3EB>67)!4v&E!22|cJN+mwyB25I2tsoypf7R%a!^y6|xBNwBy ze9pwxPPP${Ri6w$1wux35dTmKQPXn-?{Gq_EBE8I06%C<@q+N2j|~u-mE&$JC*zYf z@H#h04YCgwKdNQ9=E1b!a@mT%RoP_B|7<&&#Wn^9-tKW0?Mzt%F}bG%fFG<#k<6Jc z^3+AX13E2#YzMADo77(3Cd*y|3X)UruadQX@D-ZV2L7Wjm#4lPCYk|U$Jx(3<`+b# zP8&5gj$Lw5PB|XikjSs72>c7u6Tpebx`v>SO2W1|{6kYW`;z|#h4aoL7zA^$1FQp< z0FIHVub%J}ktoM2F#v$R`Y-Usms`g1L?H~+86va{l;D#V-eC_yc#<3j;)Ah8M?|0^ zF#y|}s6Y$~se%o|gsM0|o!#K6CqMvzKrqzK`p4SIN zTn*=@!+&tF3RSs&wJC7P0=uLhq{{bjO4|QY``PN{ZA zA8_;0(9jDmt#h&Rg)?d;**K%xlBJlDTNj?XhFc86gUclbgJFe{WW-qh8Yh-?SZC}< zMaoMeSOnvM)_sFoT}ocYJ6%69j;kw0^qcqf!Z*~@)#e4=*rN{XtFWDKg?*jO^9so@ zRyE$tcmeq&p{3)B?)1w&I!7|fOIh6h$S@4X4hF;a7Gw?v&1Jvg zNLm49n>N=H3W%`$%)uK?eWUxr=lCp-zIpbJm-n+CO@ zo-V2T8aPtevbd5ovJSq?e&i+983YzPzO`ET^~L#f14N%QTF`>8ajjrK)BKt3rpTZK zFP84A(MtSEjTG}uOXo650aq`#^w%kamM;wO<12%{8w3{B`*@7&X@!`*&$5_VwPHe%^fZ`urnqNjktrsHi;3Rey`U+%s`W#qykOv`2oW1zi#dRNmRXh5aDoVcm8s^2ITYefG=FH z(-ozy@-N_88<#tDLy(&x#oWz@#Dumu)|OsCWi)gsKV}p1VuGmR=D6eCuTBo$*e8(c9o1Cu*5Qj zS<2vj9h8&D!F#;wF)jH{d{t&b0c;X^y(#Ef_2q(3#K$S=y~9FgVS($;<03cXR}Q0Z zg&!#`(&3F6aQ{k1_2jBqIYXz0MYeqI4@bZD-T55*sHnUG)wtSXQ&emeXfYDaRCeiE zasOg8JG)Wu{yaY5EuXoT>}4p`aul)Q=})P6IoYu7R{3=2_Xf}Jv9T5c%1X;8v`dHk zV|$_IxKXxK4(CLNbfU@NJ%^9&tJbt($=VSeY;9t(QaVTdB?xg2;2`3-p*nC38Ieh= zyp|`Cnk=HbO({1qZJrR}<6Z#zYWlIS6XR@B^3<& zR8wT&2aNCD{_n*SKO{U0tl6Ax1IZAfs5<)wA^9e=pAvhz6lvZBf*HXrxYBU7^dXZQ z { // 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;