diff --git a/bundle.js b/bundle.js index 5892c5b..1cd444c 100644 --- a/bundle.js +++ b/bundle.js @@ -1,7 +1,7 @@ (() => { // lib/context.ts - var contextStack = []; var defaultContext = {}; + var contextStack = [defaultContext]; var debug = JSON.parse(localStorage.getItem("debug") || "false"); function setDefaultContext(context) { Object.assign(defaultContext, context); @@ -1350,8 +1350,8 @@ } calculateEvenlySpacedPoints(spacing, resolution = 1, targetLength) { const points = []; - points.push(this.points[0]); - let prev = points[0]; + points.push([this.points[0], this.tangent(0).heading()]); + let [prev] = points[0]; let distSinceLastEvenPoint = 0; let t = 0; const div = Math.ceil(this.length * resolution * 10); @@ -1366,7 +1366,7 @@ Vector.sub(point, prev).normalize().mult(overshoot) ); distSinceLastEvenPoint = overshoot; - points.push(evenPoint); + points.push([evenPoint, this.tangent(t).heading()]); prev = evenPoint; } prev = point; @@ -1383,7 +1383,7 @@ Vector.sub(point, prev).normalize().mult(overshoot) ); distSinceLastEvenPoint = overshoot; - points.push(evenPoint); + points.push([evenPoint, this.tangent(t).heading()]); prev = evenPoint; } prev = point; @@ -1403,7 +1403,7 @@ const curveLength = this.startingLength; const points = this.calculateEvenlySpacedPoints(1, 1, curveLength + 1); if (points.length >= curveLength) { - this.points[3].set(points[curveLength]); + this.points[3].set(points[curveLength][0]); } } draw() { @@ -1437,6 +1437,12 @@ segment.recalculateRailPoints(Math.round(percent * 100 / 4)); } } + recalculateAll() { + for (const segment of this.segments.values()) { + segment.recalculateRailPoints(); + segment.length = segment.calculateApproxLength(); + } + } registerSegment(segment) { segment.setTrack(this); this.segments.set(segment.id, segment); @@ -1447,6 +1453,9 @@ s.backNeighbours = s.backNeighbours.filter((n) => n !== segment); s.frontNeighbours = s.frontNeighbours.filter((n) => n !== segment); } + const ends = this.ends.get(segment); + this.ends.delete(segment); + this.endArray = this.endArray.filter((e) => !ends?.includes(e)); } draw(showControls = false) { for (const [i, segment] of this.segments.entries()) { @@ -1642,7 +1651,7 @@ setTrack(t) { this.track = t; } - draw(showControls = false) { + draw(showControls = false, recalculateRailPoints = false) { if (showControls) { this.doodler.deferDrawing(() => { this.doodler.fillCircle(this.points[0], 1, { @@ -1659,11 +1668,11 @@ }); }); } - const ties = Math.ceil(this.length / 10); - for (let i = 0; i < ties; i++) { - const t = i / ties; - const p = this.getPointAtT(t); - this.doodler.drawRotated(p, this.tangent(t).heading(), () => { + const spacing = Math.ceil(this.length / 10); + const points = this.calculateEvenlySpacedPoints(this.length / spacing); + for (let i = 0; i < points.length - 1; i++) { + const [p, t] = points[i]; + this.doodler.drawRotated(p, t, () => { this.doodler.line(p, p.copy().add(0, 10), { color: "#291b17", weight: 4 @@ -1674,6 +1683,9 @@ }); }); } + if (recalculateRailPoints) { + this.recalculateRailPoints(); + } this.doodler.deferDrawing( () => { this.doodler.drawLine(this.normalPoints, { @@ -2044,17 +2056,19 @@ ); this.ghostRotated = true; break; - case "back": + case "back": { this.ghostSegment.setPositionByPoint( this.closestEnd.pos, this.ghostSegment.points[3] ); + const ghostEndTangent = this.ghostSegment.tangent(1); !this.ghostRotated && this.ghostSegment.rotateAboutPoint( - this.closestEnd.tangent.heading(), + this.closestEnd.tangent.heading() - ghostEndTangent.heading(), this.ghostSegment.points[3] ); this.ghostRotated = true; break; + } } } else if (!this.closestEnd || !closestEnd) { this.ghostSegment = void 0; @@ -2082,11 +2096,11 @@ const doodler2 = getContextItem("doodler"); this.layers.push( doodler2.createLayer(() => { - this.selectedSegment?.draw(); + this.selectedSegment?.draw(false, true); if (this.ghostSegment) { doodler2.drawWithAlpha(0.5, () => { if (!this.ghostSegment) return; - this.ghostSegment.draw(); + this.ghostSegment.draw(false, true); if (getContextItemOrDefault("debug", false)) { const colors2 = getContextItem("colors"); for (const [i, point] of this.ghostSegment.points.entries() ?? []) { @@ -2182,6 +2196,8 @@ for (const layer of this.layers) { getContextItem("doodler").deleteLayer(layer); } + const track = getContextItem("track"); + track.recalculateAll(); const inputManager2 = getContextItem("inputManager"); inputManager2.offKey("e"); inputManager2.offKey("w"); @@ -2830,10 +2846,6 @@ fpsEl.id = "fps"; document.body.appendChild(fpsEl); } - const fPerc = frameRate / 60; - if (fPerc < 0.6) { - state.optimizePerformance(fPerc); - } fpsEl.textContent = frameRate.toFixed(1) + " fps"; }, 1e3); var gameLoop = new GameLoop(); diff --git a/lib/context.ts b/lib/context.ts index 9758aae..466ac72 100644 --- a/lib/context.ts +++ b/lib/context.ts @@ -1,7 +1,7 @@ type ContextStore = Record; -const contextStack: ContextStore[] = []; const defaultContext: ContextStore = {}; +const contextStack: ContextStore[] = [defaultContext]; const debug = JSON.parse(localStorage.getItem("debug") || "false"); diff --git a/main.ts b/main.ts index 7b4710b..a9840d8 100644 --- a/main.ts +++ b/main.ts @@ -74,10 +74,10 @@ setInterval(() => { fpsEl.id = "fps"; document.body.appendChild(fpsEl); } - const fPerc = frameRate / 60; - if (fPerc < 0.6) { - state.optimizePerformance(fPerc); - } + // const fPerc = frameRate / 60; + // if (fPerc < 0.6) { + // state.optimizePerformance(fPerc); + // } fpsEl.textContent = frameRate.toFixed(1) + " fps"; }, 1000); diff --git a/math/path.ts b/math/path.ts index f471093..18549b4 100644 --- a/math/path.ts +++ b/math/path.ts @@ -237,10 +237,10 @@ export class PathSegment { resolution = 1, targetLength?: number, ) { - const points: Vector[] = []; + const points: [Vector, number][] = []; - points.push(this.points[0]); - let prev = points[0]; + points.push([this.points[0], this.tangent(0).heading()]); + let [prev] = points[0]; let distSinceLastEvenPoint = 0; let t = 0; @@ -258,7 +258,7 @@ export class PathSegment { Vector.sub(point, prev).normalize().mult(overshoot), ); distSinceLastEvenPoint = overshoot; - points.push(evenPoint); + points.push([evenPoint, this.tangent(t).heading()]); prev = evenPoint; } @@ -278,7 +278,7 @@ export class PathSegment { Vector.sub(point, prev).normalize().mult(overshoot), ); distSinceLastEvenPoint = overshoot; - points.push(evenPoint); + points.push([evenPoint, this.tangent(t).heading()]); prev = evenPoint; } @@ -304,7 +304,7 @@ export class PathSegment { const curveLength = this.startingLength; const points = this.calculateEvenlySpacedPoints(1, 1, curveLength + 1); if (points.length >= curveLength) { - this.points[3].set(points[curveLength]); + this.points[3].set(points[curveLength][0]); } } diff --git a/state/states/EditTrackState.ts b/state/states/EditTrackState.ts index 47220da..9a47173 100644 --- a/state/states/EditTrackState.ts +++ b/state/states/EditTrackState.ts @@ -121,18 +121,20 @@ export class EditTrackState extends State { ); this.ghostRotated = true; break; - case "back": + case "back": { this.ghostSegment.setPositionByPoint( this.closestEnd.pos, this.ghostSegment.points[3], ); + const ghostEndTangent = this.ghostSegment.tangent(1); // this.ghostSegment.points[3] = this.closestEnd.pos; !this.ghostRotated && this.ghostSegment.rotateAboutPoint( - this.closestEnd.tangent.heading(), + this.closestEnd.tangent.heading() - ghostEndTangent.heading(), this.ghostSegment.points[3], ); this.ghostRotated = true; break; + } } // } else if (closestEnd) { // this.closestEnd = closestEnd; @@ -258,11 +260,11 @@ export class EditTrackState extends State { const doodler = getContextItem("doodler"); this.layers.push( doodler.createLayer(() => { - this.selectedSegment?.draw(); + this.selectedSegment?.draw(false, true); if (this.ghostSegment) { doodler.drawWithAlpha(0.5, () => { if (!this.ghostSegment) return; - this.ghostSegment.draw(); + this.ghostSegment.draw(false, true); if (getContextItemOrDefault("debug", false)) { const colors = getContextItem("colors"); for ( @@ -396,6 +398,9 @@ export class EditTrackState extends State { getContextItem("doodler").deleteLayer(layer); } + const track = getContextItem("track"); + track.recalculateAll(); + const inputManager = getContextItem("inputManager"); inputManager.offKey("e"); inputManager.offKey("w"); diff --git a/track/system.ts b/track/system.ts index b9258ca..a13da92 100644 --- a/track/system.ts +++ b/track/system.ts @@ -29,6 +29,13 @@ export class TrackSystem { } } + recalculateAll() { + for (const segment of this.segments.values()) { + segment.recalculateRailPoints(); + segment.length = segment.calculateApproxLength(); + } + } + registerSegment(segment: TrackSegment) { segment.setTrack(this); this.segments.set(segment.id, segment); @@ -39,6 +46,9 @@ export class TrackSystem { s.backNeighbours = s.backNeighbours.filter((n) => n !== segment); s.frontNeighbours = s.frontNeighbours.filter((n) => n !== segment); } + const ends = this.ends.get(segment); + this.ends.delete(segment); + this.endArray = this.endArray.filter((e) => !ends?.includes(e)); } draw(showControls = false) { @@ -291,7 +301,7 @@ export class TrackSegment extends PathSegment { this.track = t; } - override draw(showControls = false) { + override draw(showControls = false, recalculateRailPoints = false) { // if (showControls) { // this.doodler.drawBezier( // this.points[0], @@ -320,15 +330,17 @@ export class TrackSegment extends PathSegment { }); } - const ties = Math.ceil(this.length / 10); - for (let i = 0; i < ties; i++) { - const t = i / ties; - const p = this.getPointAtT(t); + const spacing = Math.ceil(this.length / 10); + const points = this.calculateEvenlySpacedPoints(this.length / spacing); + for (let i = 0; i < points.length - 1; i++) { + // const t = i / ties; + // const p = this.getPointAtT(t); + const [p, t] = points[i]; // this.doodler.drawCircle(p, 2, { // color: "red", // weight: 3, // }); - this.doodler.drawRotated(p, this.tangent(t).heading(), () => { + this.doodler.drawRotated(p, t, () => { this.doodler.line(p, p.copy().add(0, 10), { color: "#291b17", weight: 4, @@ -348,6 +360,9 @@ export class TrackSegment extends PathSegment { }); } + if (recalculateRailPoints) { + this.recalculateRailPoints(); + } this.doodler.deferDrawing( () => { this.doodler.drawLine(this.normalPoints, {