start rework coordinates

This commit is contained in:
sfja 2025-05-19 15:31:20 +02:00
parent 36b29bdcef
commit 91e8d7dc6c
2 changed files with 146 additions and 51 deletions

View File

@ -46,6 +46,7 @@ export class V2 {
export interface Geometry { export interface Geometry {
pointInside(thisPos: V2, pointPos: V2): boolean; pointInside(thisPos: V2, pointPos: V2): boolean;
collidesWith(thisPos: V2, other: Geometry, otherPos: V2): boolean; collidesWith(thisPos: V2, other: Geometry, otherPos: V2): boolean;
boundingRectSize(): V2;
render(r: Renderer, pos: V2, color: string): void; render(r: Renderer, pos: V2, color: string): void;
} }
@ -77,6 +78,10 @@ export class Rect implements Geometry {
return other.collidesWith(otherPos, this, thisPos); return other.collidesWith(otherPos, this, thisPos);
} }
boundingRectSize(): V2 {
return new V2(this.width, this.height);
}
render(r: Renderer, pos: V2, color: string): void { render(r: Renderer, pos: V2, color: string): void {
r.fillRect(pos.x, pos.y, this.width, this.height, color); r.fillRect(pos.x, pos.y, this.width, this.height, color);
} }
@ -114,6 +119,10 @@ export class Circle implements Geometry {
return other.collidesWith(otherPos, other, thisPos); return other.collidesWith(otherPos, other, thisPos);
} }
boundingRectSize(): V2 {
return new V2(this.radius, this.radius);
}
render(r: Renderer, pos: V2, color: string): void { render(r: Renderer, pos: V2, color: string): void {
r.fillCirc(pos.x, pos.y, this.radius, color); r.fillCirc(pos.x, pos.y, this.radius, color);
} }
@ -138,6 +147,16 @@ export class Shape implements Geometry {
); );
} }
boundingRectSize(): V2 {
return this.innerShapes
.reduce((size, [pos, shape]) => {
const shapeSize = shape.boundingRectSize();
size.x = Math.max(size.x, pos.x + shapeSize.x);
size.y = Math.max(size.y, pos.y + shapeSize.y);
return size;
}, new V2(0, 0));
}
render(r: Renderer, pos: V2, color: string): void { render(r: Renderer, pos: V2, color: string): void {
for (const [shapePos, shape] of this.innerShapes) { for (const [shapePos, shape] of this.innerShapes) {
shape.render(r, shapePos.add(pos), color); shape.render(r, shapePos.add(pos), color);

View File

@ -39,10 +39,15 @@ export class Simulator {
} }
} }
type Tool = {
component: Component;
offsetX: number;
};
class Toolbar { class Toolbar {
private tools: Component[] = [ private tools: Tool[] = [
new SwitchComponent(), { component: new SwitchComponent(), offsetX: 32 },
new LedComponent(), { component: new LedComponent(), offsetX: 256 },
]; ];
private lastWidth = 0; private lastWidth = 0;
@ -50,6 +55,8 @@ class Toolbar {
private hoveringComponentIdx?: number; private hoveringComponentIdx?: number;
private scale = 64;
constructor( constructor(
private mouse: Mouse, private mouse: Mouse,
private tooltip: Tooltip, private tooltip: Tooltip,
@ -64,14 +71,16 @@ class Toolbar {
return "bubble"; return "bubble";
} }
for (const [i, component] of this.tools.entries()) { for (const [i, tool] of this.tools.entries()) {
const compWidth = tool.component.width * this.scale;
const compHeight = tool.component.height * this.scale;
if ( if (
x >= i * 128 + 96 - 48 && x >= tool.offsetX &&
y >= this.lastHeight - 100 - 48 && y >= this.lastHeight - 100 - 48 &&
x < i * 128 + 96 + component.width * 32 + 32 && x < tool.offsetX + compWidth &&
y < this.lastHeight - 100 + component.height * 32 + 32 y < this.lastHeight - 100 + compHeight
) { ) {
this.tooltip.select(this.tools[i]); this.tooltip.select(this.tools[i].component);
return "stop"; return "stop";
} }
} }
@ -82,12 +91,14 @@ class Toolbar {
hover(): "continue" | "break" { hover(): "continue" | "break" {
const { x, y } = this.mouse; const { x, y } = this.mouse;
for (const [i, component] of this.tools.entries()) { for (const [i, tool] of this.tools.entries()) {
const compWidth = tool.component.width * this.scale;
const compHeight = tool.component.height * this.scale;
if ( if (
x >= i * 128 + 96 - 48 && x >= tool.offsetX &&
y >= this.lastHeight - 100 - 48 && y >= this.lastHeight - 100 &&
x < i * 128 + 96 + component.width * 32 + 32 && x < tool.offsetX + compWidth &&
y < this.lastHeight - 100 + component.height * 32 + 32 y < this.lastHeight - 100 + compHeight
) { ) {
this.hoveringComponentIdx = i; this.hoveringComponentIdx = i;
document.body.style.cursor = "pointer"; document.body.style.cursor = "pointer";
@ -103,25 +114,28 @@ class Toolbar {
this.lastHeight = r.height; this.lastHeight = r.height;
r.fillRect(0, r.height - 200, r.width, 200, "#aaa"); r.fillRect(0, r.height - 200, r.width, 200, "#aaa");
for (const [i, component] of this.tools.entries()) {
for (const [i, tool] of this.tools.entries()) {
const compWidth = tool.component.width * this.scale;
const compHeight = tool.component.height * this.scale;
r.strokeRect( r.strokeRect(
i * 128 + 96 - 48, tool.offsetX,
r.height - 100 - 48, r.height - 100,
96, compWidth,
96, compHeight,
"#777", "#777",
1, 1,
); );
if (i === this.hoveringComponentIdx) { if (i === this.hoveringComponentIdx) {
r.fillRect( r.fillRect(
i * 128 + 96 - 48, tool.offsetX,
r.height - 100 - 48, r.height - 100,
component.height * 32 + 64, compWidth,
component.width * 32 + 64, compHeight,
"#00000088", "#00000088",
); );
} }
component.render(r, i * 128 + 96, r.height - 100); tool.component.render(r, tool.offsetX, r.height - 100);
} }
} }
} }
@ -200,12 +214,16 @@ class Tooltip {
} }
render(r: Renderer): void { render(r: Renderer): void {
const x = Math.floor(this.mouse.x / 32);
const y = Math.floor(this.mouse.y / 32);
if (this.selectedComponent) { if (this.selectedComponent) {
const x = Math.floor(this.mouse.x / 32) * 32;
const y = Math.floor(this.mouse.y / 32) * 32;
if (this.shouldHover) { if (this.shouldHover) {
this.selectedComponent this.selectedComponent
.renderTransparent(r, x * 32 + 16, y * 32 + 16); .renderTransparent(
r,
x - this.selectedComponent.offsetX * 32,
y - this.selectedComponent.height * 32,
);
} }
} else if (!this.isWiring) { } else if (!this.isWiring) {
const output = this.selectedOutputTerm; const output = this.selectedOutputTerm;
@ -355,7 +373,11 @@ class Circuit {
r.strokeLine(source.x, source.y, dest.x, dest.y, "black", 3); r.strokeLine(source.x, source.y, dest.x, dest.y, "black", 3);
} }
for (const { component, x, y } of this.components) { for (const { component, x, y } of this.components) {
component.render(r, x * 32 + 16, y * 32 + 16); component.render(
r,
x * 32 - component.offsetX * 32,
y * 32 - component.offsetY * 32,
);
} }
} }
} }
@ -384,6 +406,8 @@ class ComponentWireTerm implements WireSource, WireDest {
} }
interface Component { interface Component {
get offsetX(): number;
get offsetY(): number;
get width(): number; get width(): number;
get height(): number; get height(): number;
@ -404,19 +428,45 @@ class SwitchComponent implements Component {
private switchOn = false; private switchOn = false;
public width = 1; private geometry = new Rect(1.5, 1);
public height = 1;
private geometry = new Rect(2, 1);
constructor() { constructor() {
this.graphicOff.fillRect(64, 30, 16, 4, "black"); this.graphicOff.strokeRect(
this.graphicOff.fillCirc(48 + 32, 32, 8, "black"); 0,
this.graphicOff.fillCirc(48, 32, 16, "black"); 0,
this.graphicOff.width,
this.graphicOff.height,
"#88000088",
2,
);
this.graphicOff.fillRect(48, 30, 16, 4, "black");
this.graphicOff.fillCirc(64, 32, 8, "black");
this.graphicOff.fillCirc(32, 32, 16, "black");
this.graphicOn.fillRect(64, 30, 16, 4, "black"); this.graphicOn.strokeRect(
this.graphicOn.fillCirc(48 + 32, 32, 8, "black"); 0,
this.graphicOn.fillCirc(48, 32, 16, "red"); 0,
this.graphicOn.width,
this.graphicOn.height,
"#88000088",
2,
);
this.graphicOn.fillRect(48, 30, 16, 4, "black");
this.graphicOn.fillCirc(64, 32, 8, "black");
this.graphicOn.fillCirc(32, 32, 16, "red");
}
get offsetX(): number {
return 0.5;
}
get offsetY(): number {
return 0.5;
}
get width(): number {
return this.geometry.width;
}
get height(): number {
return this.geometry.height;
} }
clone(): Component { clone(): Component {
@ -433,12 +483,12 @@ class SwitchComponent implements Component {
render(r: Renderer, x: number, y: number): void { render(r: Renderer, x: number, y: number): void {
const graphic = this.switchOn ? this.graphicOn : this.graphicOff; const graphic = this.switchOn ? this.graphicOn : this.graphicOff;
graphic.render(r, x - 48, y - 32); graphic.render(r, x, y);
} }
renderTransparent(r: Renderer, x: number, y: number): void { renderTransparent(r: Renderer, x: number, y: number): void {
const graphic = this.switchOn ? this.graphicOn : this.graphicOff; const graphic = this.switchOn ? this.graphicOn : this.graphicOff;
graphic.render(r, x - 48, y - 32, 0.5); graphic.render(r, x, y, 0.5);
} }
click(x: number, y: number): void { click(x: number, y: number): void {
@ -478,19 +528,45 @@ class LedComponent implements Component {
private switchOn = false; private switchOn = false;
public width = 1; private geometry = new Rect(1.5, 1);
public height = 1;
private geometry = new Rect(2, 1);
constructor() { constructor() {
this.graphicOff.fillRect(16, 30, 16, 4, "black"); this.graphicOff.strokeRect(
this.graphicOff.fillCirc(16, 32, 8, "black"); 0,
this.graphicOff.fillCirc(48, 32, 16, "black"); 0,
this.graphicOff.width,
this.graphicOff.height,
"#88000088",
2,
);
this.graphicOff.fillRect(32, 30, 16, 4, "black");
this.graphicOff.fillCirc(32, 32, 8, "black");
this.graphicOff.fillCirc(64, 32, 16, "black");
this.graphicOn.fillRect(16, 30, 16, 4, "black"); this.graphicOn.strokeRect(
this.graphicOn.fillCirc(16, 32, 8, "black"); 0,
this.graphicOn.fillCirc(48, 32, 16, "red"); 0,
this.graphicOn.width,
this.graphicOn.height,
"#88000088",
2,
);
this.graphicOn.fillRect(32, 30, 16, 4, "black");
this.graphicOn.fillCirc(32, 32, 8, "black");
this.graphicOn.fillCirc(64, 32, 16, "red");
}
get offsetX(): number {
return 1.5;
}
get offsetY(): number {
return 0.5;
}
get width(): number {
return this.geometry.width;
}
get height(): number {
return this.geometry.height;
} }
clone(): Component { clone(): Component {
@ -511,12 +587,12 @@ class LedComponent implements Component {
render(r: Renderer, x: number, y: number): void { render(r: Renderer, x: number, y: number): void {
const graphic = this.switchOn ? this.graphicOn : this.graphicOff; const graphic = this.switchOn ? this.graphicOn : this.graphicOff;
graphic.render(r, x - 48, y - 32); graphic.render(r, x, y);
} }
renderTransparent(r: Renderer, x: number, y: number): void { renderTransparent(r: Renderer, x: number, y: number): void {
const graphic = this.switchOn ? this.graphicOn : this.graphicOff; const graphic = this.switchOn ? this.graphicOn : this.graphicOff;
graphic.render(r, x - 48, y - 32, 0.5); graphic.render(r, x, y, 0.5);
} }
hoveredInputTerminal( hoveredInputTerminal(