@unboxy/phaser-sdk 0.2.30 → 0.2.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -251,13 +251,19 @@ function createProgressBar(ctx, entity, pos) {
251
251
  const f = Math.max(0, Math.min(1, frac));
252
252
  g.clear();
253
253
  const radius = v.borderRadius ?? 0;
254
+ // Centered draw: the container is positioned by applyContainerOriginShift
255
+ // so child visuals at (0,0) sit at the resolved anchor; drawing the rect
256
+ // from (-w/2, -h/2) keeps the visual aligned with the editor's
257
+ // editorHit{Width,Height} bounds (which are computed center-based).
258
+ const x0 = -w / 2;
259
+ const y0 = -h / 2;
254
260
  // Background.
255
261
  if (v.backgroundColor) {
256
262
  g.fillStyle(parseColor(v.backgroundColor), 1);
257
263
  if (radius > 0)
258
- g.fillRoundedRect(0, 0, w, h, radius);
264
+ g.fillRoundedRect(x0, y0, w, h, radius);
259
265
  else
260
- g.fillRect(0, 0, w, h);
266
+ g.fillRect(x0, y0, w, h);
261
267
  }
262
268
  // Fill.
263
269
  const fillColor = v.fillColor ?? '#22c55e';
@@ -265,17 +271,17 @@ function createProgressBar(ctx, entity, pos) {
265
271
  const fillW = w * f;
266
272
  if (fillW > 0) {
267
273
  if (radius > 0)
268
- g.fillRoundedRect(0, 0, fillW, h, Math.min(radius, fillW / 2));
274
+ g.fillRoundedRect(x0, y0, fillW, h, Math.min(radius, fillW / 2));
269
275
  else
270
- g.fillRect(0, 0, fillW, h);
276
+ g.fillRect(x0, y0, fillW, h);
271
277
  }
272
278
  // Border.
273
279
  if (v.borderColor && (v.borderWidth ?? 0) > 0) {
274
280
  g.lineStyle(v.borderWidth ?? 1, parseColor(v.borderColor), 1);
275
281
  if (radius > 0)
276
- g.strokeRoundedRect(0, 0, w, h, radius);
282
+ g.strokeRoundedRect(x0, y0, w, h, radius);
277
283
  else
278
- g.strokeRect(0, 0, w, h);
284
+ g.strokeRect(x0, y0, w, h);
279
285
  }
280
286
  };
281
287
  const computeFrac = () => {
@@ -330,19 +336,22 @@ function createPanel(ctx, entity, pos) {
330
336
  const draw = () => {
331
337
  g.clear();
332
338
  const radius = v.borderRadius ?? 0;
339
+ // Centered draw — see createProgressBar for the rationale.
340
+ const x0 = -w / 2;
341
+ const y0 = -h / 2;
333
342
  if (v.backgroundColor) {
334
343
  g.fillStyle(parseColor(v.backgroundColor), v.backgroundAlpha ?? 1);
335
344
  if (radius > 0)
336
- g.fillRoundedRect(0, 0, w, h, radius);
345
+ g.fillRoundedRect(x0, y0, w, h, radius);
337
346
  else
338
- g.fillRect(0, 0, w, h);
347
+ g.fillRect(x0, y0, w, h);
339
348
  }
340
349
  if (v.borderColor && (v.borderWidth ?? 0) > 0) {
341
350
  g.lineStyle(v.borderWidth ?? 1, parseColor(v.borderColor), 1);
342
351
  if (radius > 0)
343
- g.strokeRoundedRect(0, 0, w, h, radius);
352
+ g.strokeRoundedRect(x0, y0, w, h, radius);
344
353
  else
345
- g.strokeRect(0, 0, w, h);
354
+ g.strokeRect(x0, y0, w, h);
346
355
  }
347
356
  };
348
357
  draw();
@@ -386,11 +395,32 @@ function applyOriginFromAnchor(go, side) {
386
395
  go.setOrigin(ox, oy);
387
396
  }
388
397
  /**
389
- * Containers don't support setOrigin; instead nudge their position by half
390
- * of (origin × size) so they end up positioned consistently with widgets
391
- * that DO have setOrigin. Called once at spawn.
398
+ * Compute the per-side origin-shift offset for a container widget. Containers
399
+ * don't support setOrigin, so we shift the container's position so its
400
+ * (centred) child visuals appear at the right place relative to the
401
+ * resolved anchor coord. Used both at spawn and during applyHudPatch when
402
+ * the anchor side changes.
392
403
  */
393
- function applyContainerOriginShift(container, side, w, h) {
404
+ /** Default container widths/heights must mirror the spawners' fallbacks. */
405
+ function defaultContainerWidth(entity) {
406
+ if (entity.kind === 'icon-button')
407
+ return entity.visual.width ?? 96;
408
+ if (entity.kind === 'progress-bar')
409
+ return entity.visual.width ?? 200;
410
+ if (entity.kind === 'panel')
411
+ return entity.visual.width ?? 200;
412
+ return 0;
413
+ }
414
+ function defaultContainerHeight(entity) {
415
+ if (entity.kind === 'icon-button')
416
+ return entity.visual.height ?? 48;
417
+ if (entity.kind === 'progress-bar')
418
+ return entity.visual.height ?? 16;
419
+ if (entity.kind === 'panel')
420
+ return entity.visual.height ?? 100;
421
+ return 0;
422
+ }
423
+ function originShiftFor(side, w, h) {
394
424
  const map = {
395
425
  'top-left': [0, 0],
396
426
  'top': [0.5, 0],
@@ -403,11 +433,12 @@ function applyContainerOriginShift(container, side, w, h) {
403
433
  'bottom-right': [1, 1],
404
434
  };
405
435
  const [ox, oy] = map[side];
406
- // Container's children are drawn relative to (0,0) inside the container,
407
- // and we drew bg at (0,0) (its setOrigin is 0.5/0.5). To shift the
408
- // container so the desired anchor corner lands at the resolved coord:
409
- container.x += (0.5 - ox) * w;
410
- container.y += (0.5 - oy) * h;
436
+ return { x: (0.5 - ox) * w, y: (0.5 - oy) * h };
437
+ }
438
+ function applyContainerOriginShift(container, side, w, h) {
439
+ const s = originShiftFor(side, w, h);
440
+ container.x += s.x;
441
+ container.y += s.y;
411
442
  }
412
443
  /**
413
444
  * Compute the rendered string for a text source. Static returns the literal;
@@ -645,27 +676,42 @@ export function applyHudPatch(game, entityId, patch) {
645
676
  if (typeof patch.anchor.offsetY === 'number')
646
677
  entity.anchor.offsetY = patch.anchor.offsetY;
647
678
  const pos = resolveAnchor(hud, entity.anchor, safeArea);
648
- go.x = pos.x;
649
- go.y = pos.y;
650
- // Text + image origins were set per anchor.side at spawn re-apply on
651
- // side change so e.g. switching top-left top-right re-pivots the
652
- // origin and the widget grows in the correct direction.
653
- if (typeof patch.anchor.side === 'string') {
654
- const sideMap = {
655
- 'top-left': [0, 0],
656
- 'top': [0.5, 0],
657
- 'top-right': [1, 0],
658
- 'left': [0, 0.5],
659
- 'center': [0.5, 0.5],
660
- 'right': [1, 0.5],
661
- 'bottom-left': [0, 1],
662
- 'bottom': [0.5, 1],
663
- 'bottom-right': [1, 1],
664
- };
665
- const o = sideMap[patch.anchor.side];
666
- if (o) {
667
- const setOrigin = go.setOrigin;
668
- setOrigin?.call(go, o[0], o[1]);
679
+ // Container-based widgets (icon-button, progress-bar, panel) have no
680
+ // setOrigin — they were shifted at spawn by `applyContainerOriginShift`
681
+ // so their centred child visuals appear at the right place. The same
682
+ // shift must be re-applied on every anchor change, otherwise the
683
+ // container ends up centred on the raw anchor coord and the visual is
684
+ // off by ±(w/2, h/2). Text + image have setOrigin so we use that path.
685
+ const isContainer = entity.kind === 'icon-button' || entity.kind === 'progress-bar' || entity.kind === 'panel';
686
+ if (isContainer) {
687
+ const visual = entity.visual;
688
+ const w = visual.width ?? defaultContainerWidth(entity);
689
+ const h = visual.height ?? defaultContainerHeight(entity);
690
+ const shift = originShiftFor(entity.anchor.side, w, h);
691
+ go.x = pos.x + shift.x;
692
+ go.y = pos.y + shift.y;
693
+ }
694
+ else {
695
+ go.x = pos.x;
696
+ go.y = pos.y;
697
+ // Re-pivot the origin for setOrigin-based widgets (text, image).
698
+ if (typeof patch.anchor.side === 'string') {
699
+ const sideMap = {
700
+ 'top-left': [0, 0],
701
+ 'top': [0.5, 0],
702
+ 'top-right': [1, 0],
703
+ 'left': [0, 0.5],
704
+ 'center': [0.5, 0.5],
705
+ 'right': [1, 0.5],
706
+ 'bottom-left': [0, 1],
707
+ 'bottom': [0.5, 1],
708
+ 'bottom-right': [1, 1],
709
+ };
710
+ const o = sideMap[patch.anchor.side];
711
+ if (o) {
712
+ const setOrigin = go.setOrigin;
713
+ setOrigin?.call(go, o[0], o[1]);
714
+ }
669
715
  }
670
716
  }
671
717
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboxy/phaser-sdk",
3
- "version": "0.2.30",
3
+ "version": "0.2.32",
4
4
  "description": "Unboxy Phaser 3 SDK — game infrastructure for the Unboxy platform",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",