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 {
pointInside(thisPos: V2, pointPos: V2): boolean;
collidesWith(thisPos: V2, other: Geometry, otherPos: V2): boolean;
boundingRectSize(): V2;
render(r: Renderer, pos: V2, color: string): void;
}
@ -77,6 +78,10 @@ export class Rect implements Geometry {
return other.collidesWith(otherPos, this, thisPos);
}
boundingRectSize(): V2 {
return new V2(this.width, this.height);
}
render(r: Renderer, pos: V2, color: string): void {
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);
}
boundingRectSize(): V2 {
return new V2(this.radius, this.radius);
}
render(r: Renderer, pos: V2, color: string): void {
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 {
for (const [shapePos, shape] of this.innerShapes) {
shape.render(r, shapePos.add(pos), color);

View File

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