Scene: ausgeschaltete Objekte behalten ihren Auswahlrahmen
Ein ausgeschaltetes Objekt zeichnet nichts, verschwand bisher aber auch aus der Auswahl - im Panel angeklickt blieb der Viewport leer, es gab kein Anzeichen, wo es liegt. Der Rahmen kommt jetzt, gedimmt auf 45 %, damit er sich nicht wie eine fehlgeschlagene Zeichnung liest. Ziehen bleibt aus: der Node ist weiterhin nicht interaktiv. Dazu __gm.gizmos() als Testhaken - Gizmos waren vorher gar nicht prüfbar. Es meldet das alpha, das wirklich in den Strich geht, kein daneben abgeleitetes Flag.
This commit is contained in:
1 parent
4b47741fac
commit
2218046738
6 files changed
+81
-7
No files matched your search
@@ -604,7 +604,7 @@ npm run check # typecheck + lint + format:check + tests, what CI would ru
|
||||
# code is lost (tail's is reported), so a red run reads as green
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
export GM_REMOTE=user@host # optional: run the browser elsewhere; see below
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 491 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 496 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 – a subset while working on one step
|
||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||
./e2e.sh status # live progress, or the last run's result
|
||||
|
||||
@@ -176,6 +176,8 @@ export function installDebugHook(app: Application, state: EditorState, editor: E
|
||||
assetRow: (id: string) => assets.rowGlobal(id),
|
||||
assetRowColor: (id: string) => assets.rowColor(id),
|
||||
gameInfo: () => gameView.debugInfo(),
|
||||
/** Selection outlines in the Scene tab: a switched-off object is invisible but still framed. */
|
||||
gizmos: () => viewport.gizmoInfo(),
|
||||
layerOf: (id: string) => viewport.layerOf(id),
|
||||
drawOrder: () => viewport.drawOrder(),
|
||||
objectScreen: (id: string) => viewport.objectScreen(id),
|
||||
|
||||
@@ -63,6 +63,15 @@ interface Marquee {
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
/** One selection outline that was drawn – `alpha` is the value the stroke really got. */
|
||||
export interface GizmoInfo {
|
||||
id: string;
|
||||
primary: boolean;
|
||||
alpha: number;
|
||||
}
|
||||
|
||||
const OFF_GIZMO_ALPHA = 0.45;
|
||||
|
||||
export class SceneViewport extends WorldViewport {
|
||||
private readonly grid = new Graphics();
|
||||
private readonly links = new Graphics();
|
||||
@@ -74,6 +83,7 @@ export class SceneViewport extends WorldViewport {
|
||||
private dragging: ObjectDrag | null = null;
|
||||
private marquee: Marquee | null = null;
|
||||
private dropPreview: DropPreview | null = null;
|
||||
private lastGizmos: GizmoInfo[] = [];
|
||||
|
||||
constructor(state: EditorState) {
|
||||
super(state);
|
||||
@@ -348,6 +358,11 @@ export class SceneViewport extends WorldViewport {
|
||||
this.gizmos.clear();
|
||||
}
|
||||
|
||||
/** The selection outlines currently drawn (test hook). */
|
||||
gizmoInfo(): GizmoInfo[] {
|
||||
return this.lastGizmos;
|
||||
}
|
||||
|
||||
protected override afterItems(items: DrawItem[], view: View): void {
|
||||
this.drawParentLinks(items, view.scale);
|
||||
this.drawGizmos(items, view);
|
||||
@@ -443,24 +458,32 @@ export class SceneViewport extends WorldViewport {
|
||||
|
||||
/** Selection outlines – only the primary object gets corner handles – and the rubber band. */
|
||||
private drawGizmos(items: DrawItem[], view: View): void {
|
||||
this.lastGizmos = [];
|
||||
const s = this.state.selection;
|
||||
if (s?.kind === 'object') {
|
||||
for (const id of s.objectIds) {
|
||||
const item = items.find((i) => i.id === id);
|
||||
if (!item || !item.enabled) continue;
|
||||
if (!item) continue;
|
||||
const { w, h } = footprintOf(item.type, item.props);
|
||||
const tl = worldToScreen(view, item.x - w / 2, item.y - h / 2);
|
||||
const sw = w * view.scale;
|
||||
const sh = h * view.scale;
|
||||
this.gizmos.rect(tl.x - 2, tl.y - 2, sw + 4, sh + 4).stroke({ width: 2, color: Theme.colors.gizmo });
|
||||
if (id !== s.objectId) continue;
|
||||
// A switched-off object draws nothing, so its outline is the only way to see where it
|
||||
// sits – dimmed, because the empty frame would otherwise read as a drawing that failed.
|
||||
const alpha = item.enabled ? 1 : OFF_GIZMO_ALPHA;
|
||||
const primary = id === s.objectId;
|
||||
this.lastGizmos.push({ id, primary, alpha });
|
||||
this.gizmos
|
||||
.rect(tl.x - 2, tl.y - 2, sw + 4, sh + 4)
|
||||
.stroke({ width: 2, color: Theme.colors.gizmo, alpha });
|
||||
if (!primary) continue;
|
||||
for (const [cx, cy] of [
|
||||
[tl.x, tl.y],
|
||||
[tl.x + sw, tl.y],
|
||||
[tl.x, tl.y + sh],
|
||||
[tl.x + sw, tl.y + sh],
|
||||
] as const) {
|
||||
this.gizmos.rect(cx - 3, cy - 3, 6, 6).fill(Theme.colors.gizmo);
|
||||
this.gizmos.rect(cx - 3, cy - 3, 6, 6).fill({ color: Theme.colors.gizmo, alpha });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
objects die nicht enabled sind, sind komplett unsichtbar, das passt
|
||||
aber: wenn ich sie im panel linksunten selektiere, sollte zumindest das "gizmo" (also der selektions rahmen) im scene viewport sichtbar sein
|
||||
|
||||
---
|
||||
|
||||
Gebaut. Drei Dinge, die weder oben stehen noch aus dem Commit hervorgehen:
|
||||
|
||||
**Der Rahmen ist gedimmt (45 %).** Ein ausgeschaltetes Objekt zeichnet nichts, ein Rahmen um leeren
|
||||
Raum in voller Stärke liest sich sonst wie eine Zeichnung, die fehlgeschlagen ist. Die Eckgriffe des
|
||||
primären Objekts kommen mit – sie sind reine Kennzeichnung, es gibt keinen Hit-Test daran, sie
|
||||
versprechen also keine Geste, die ein ausgeschaltetes Objekt nicht kann.
|
||||
|
||||
**Ziehen bleibt aus.** Der Rahmen sagt nur, wo das Objekt liegt; sein Node ist weiterhin unsichtbar
|
||||
und `eventMode: 'none'`, weil `onScreen` in `WorldViewport` "aus" und "außerhalb des Sichtfelds" in
|
||||
einem Ausdruck bündelt. Bewegen geht also nur über den Inspector – oder nach dem Einschalten.
|
||||
|
||||
**Es greift auch bei geerbtem Aus.** `DrawItem.enabled` ist `enabledAlongChain`, also das Objekt
|
||||
*und* alle seine Eltern. Ein Kind, das nur deshalb unsichtbar ist, weil sein Elternteil aus ist,
|
||||
bekommt denselben gedimmten Rahmen.
|
||||
|
||||
Nebenbei entstanden: `__gm.gizmos()` – vorher waren Gizmos überhaupt nicht prüfbar. Es meldet das
|
||||
`alpha`, das wirklich in den Strich geht, nicht ein daneben abgeleitetes Flag; sonst hätte der Test
|
||||
grün bleiben können, während gar nichts gedimmt wird (als Gegenprobe nachgestellt).
|
||||
@@ -1,2 +0,0 @@
|
||||
objects die nicht enabled sind, sind komplett unsichtbar, das passt
|
||||
aber: wenn ich sie im panel linksunten selektiere, sollte zumindest das "gizmo" (also der selektions rahmen) im scene viewport sichtbar sein
|
||||
@@ -40,6 +40,9 @@ export async function textAndEnabled(t) {
|
||||
const enabledRow = await evaluate(`__gm.locate('Enabled')`);
|
||||
check('the inspector shows the Enabled switch for a scene object', Boolean(enabledRow));
|
||||
const visibleBefore = (await json('__gm.viewportInfo()')).visibleItems;
|
||||
const gizmoOf = async (id) => (await json('__gm.gizmos()')).find((g) => g.id === id) ?? null;
|
||||
const gizmoOn = await gizmoOf('otext');
|
||||
check('a selected object is framed at full strength', gizmoOn?.alpha === 1, JSON.stringify(gizmoOn));
|
||||
// The checkbox sits right of the 64 px label column; locate() gives the label's text centre.
|
||||
await click(enabledRow.x + 55, enabledRow.y);
|
||||
await sleep(100);
|
||||
@@ -62,6 +65,31 @@ export async function textAndEnabled(t) {
|
||||
check('it stays selectable in the hierarchy, so its switch stays reachable', await has('Enabled'));
|
||||
await shot('30-disabled');
|
||||
|
||||
// 17a-2. It draws nothing, so its outline is the only thing left that says where it sits – which
|
||||
// is the whole point of being able to pick it in the hierarchy. Selecting another object
|
||||
// and coming back proves the outline follows the panel, not a leftover from before.
|
||||
const gizmoOff = await gizmoOf('otext');
|
||||
check(
|
||||
'a switched-off object is still framed, dimmed',
|
||||
gizmoOff?.primary === true && gizmoOff.alpha > 0 && gizmoOff.alpha < 1,
|
||||
JSON.stringify(gizmoOff),
|
||||
);
|
||||
const otherRow = await evaluate(`__gm.hierarchyRow('o3')`);
|
||||
await click(otherRow.x, otherRow.y);
|
||||
await sleep(100);
|
||||
check('selecting something else drops the frame', (await gizmoOf('otext')) === null);
|
||||
const offRow = await evaluate(`__gm.hierarchyRow('otext')`);
|
||||
await click(offRow.x, offRow.y);
|
||||
await sleep(100);
|
||||
const gizmoBack = await gizmoOf('otext');
|
||||
check(
|
||||
'picking the switched-off object in the hierarchy frames it again',
|
||||
gizmoBack?.alpha > 0 && gizmoBack.alpha < 1,
|
||||
JSON.stringify(gizmoBack),
|
||||
);
|
||||
check('and it is still not drawn', !(await json('__gm.drawOrder()')).includes('otext'));
|
||||
await shot('30b-disabled-gizmo');
|
||||
|
||||
// 17b. In the running game a switched-off object does not exist: it is not rendered, and
|
||||
// switching it back on brings it back.
|
||||
await play();
|
||||
|
||||
Reference in new issue
Block a user