Fix findUsages/undo/node-lookup bugs, split Viewport and Editor, share command and inspector helpers
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1eb28314cf
commit
f140c2fd77
58 files changed
+1969
-1171
No files matched your search
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* How world coordinates map onto a viewport. Pure geometry – no Pixi, no editor state – so
|
||||
* both viewports share one definition of "where does this world point land on screen".
|
||||
*/
|
||||
import type { PropertyBag, Vec2 } from '../core/model/Properties';
|
||||
import { cameraFrame, rectAround, type WorldRect } from '../core/properties/camera';
|
||||
|
||||
/**
|
||||
* The world point (`x`, `y`) sits at the centre of the screen rectangle `rect` (viewport-local
|
||||
* pixels) at `scale` pixels per world unit. In the scene view the rectangle is the whole
|
||||
* viewport; in the game view it is the camera's frame fitted into it (letterboxed).
|
||||
*/
|
||||
export interface View {
|
||||
x: number;
|
||||
y: number;
|
||||
scale: number;
|
||||
rect: { x: number; y: number; w: number; h: number };
|
||||
}
|
||||
|
||||
/** Free-panning view: the whole viewport shows the world around (`x`, `y`) at `zoom`. */
|
||||
export function freeView(x: number, y: number, zoom: number, w: number, h: number): View {
|
||||
return { x, y, scale: zoom, rect: { x: 0, y: 0, w, h } };
|
||||
}
|
||||
|
||||
/**
|
||||
* The camera's frame scaled to fit inside `w`×`h` and centred – the remaining margin is the
|
||||
* letterbox, which is not part of the game area (see `isInside`).
|
||||
*/
|
||||
export function cameraView(camera: { x: number; y: number; props: PropertyBag }, w: number, h: number): View {
|
||||
const frame = cameraFrame(camera.props);
|
||||
const scale = Math.min(w / frame.w, h / frame.h);
|
||||
const fw = frame.w * scale;
|
||||
const fh = frame.h * scale;
|
||||
return { x: camera.x, y: camera.y, scale, rect: { x: (w - fw) / 2, y: (h - fh) / 2, w: fw, h: fh } };
|
||||
}
|
||||
|
||||
export function screenToWorld(view: View, sx: number, sy: number): Vec2 {
|
||||
const cx = view.rect.x + view.rect.w / 2;
|
||||
const cy = view.rect.y + view.rect.h / 2;
|
||||
return { x: (sx - cx) / view.scale + view.x, y: (sy - cy) / view.scale + view.y };
|
||||
}
|
||||
|
||||
export function worldToScreen(view: View, wx: number, wy: number): Vec2 {
|
||||
const cx = view.rect.x + view.rect.w / 2;
|
||||
const cy = view.rect.y + view.rect.h / 2;
|
||||
return { x: (wx - view.x) * view.scale + cx, y: (wy - view.y) * view.scale + cy };
|
||||
}
|
||||
|
||||
/** World region the view covers – what a redraw has to consider at all. */
|
||||
export function worldBounds(view: View): WorldRect {
|
||||
return rectAround(view.x, view.y, view.rect.w / view.scale, view.rect.h / view.scale);
|
||||
}
|
||||
|
||||
/** Whether a viewport-local point lies on the drawn rectangle rather than in the letterbox. */
|
||||
export function isInside(view: View, sx: number, sy: number): boolean {
|
||||
const { x, y, w, h } = view.rect;
|
||||
return sx >= x && sx <= x + w && sy >= y && sy <= y + h;
|
||||
}
|
||||
Reference in new issue
Block a user