@datamoc/mw_games 0.14.0 → 0.15.0

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/audio/Music.d.ts +27 -0
  3. package/dist/audio/Music.d.ts.map +1 -1
  4. package/dist/audio/Music.js +70 -2
  5. package/dist/audio/Music.js.map +1 -1
  6. package/dist/audio/Orchestrator.d.ts +4 -0
  7. package/dist/audio/Orchestrator.d.ts.map +1 -1
  8. package/dist/audio/Orchestrator.js +12 -0
  9. package/dist/audio/Orchestrator.js.map +1 -1
  10. package/dist/audio/Sound.d.ts +9 -0
  11. package/dist/audio/Sound.d.ts.map +1 -1
  12. package/dist/audio/Sound.js +18 -0
  13. package/dist/audio/Sound.js.map +1 -1
  14. package/dist/core/Settings.d.ts +96 -0
  15. package/dist/core/Settings.d.ts.map +1 -0
  16. package/dist/core/Settings.js +189 -0
  17. package/dist/core/Settings.js.map +1 -0
  18. package/dist/core/index.d.ts +2 -0
  19. package/dist/core/index.d.ts.map +1 -1
  20. package/dist/core/index.js +1 -0
  21. package/dist/core/index.js.map +1 -1
  22. package/dist/mw_games.global.js +115 -115
  23. package/dist/mwl/catalog.d.ts +42 -0
  24. package/dist/mwl/catalog.d.ts.map +1 -1
  25. package/dist/mwl/catalog.js +88 -0
  26. package/dist/mwl/catalog.js.map +1 -1
  27. package/dist/mwl/index.d.ts +1 -1
  28. package/dist/mwl/index.d.ts.map +1 -1
  29. package/dist/two-d/Game.d.ts +40 -0
  30. package/dist/two-d/Game.d.ts.map +1 -1
  31. package/dist/two-d/Game.js +66 -3
  32. package/dist/two-d/Game.js.map +1 -1
  33. package/dist/two-d/QualityScaler.d.ts +63 -0
  34. package/dist/two-d/QualityScaler.d.ts.map +1 -0
  35. package/dist/two-d/QualityScaler.js +92 -0
  36. package/dist/two-d/QualityScaler.js.map +1 -0
  37. package/dist/two-d/index.d.ts +3 -1
  38. package/dist/two-d/index.d.ts.map +1 -1
  39. package/dist/two-d/index.js +1 -0
  40. package/dist/two-d/index.js.map +1 -1
  41. package/dist/two-d/render/SpriteGroup.d.ts +83 -0
  42. package/dist/two-d/render/SpriteGroup.d.ts.map +1 -0
  43. package/dist/two-d/render/SpriteGroup.js +107 -0
  44. package/dist/two-d/render/SpriteGroup.js.map +1 -0
  45. package/dist/two-d/render/index.d.ts +2 -0
  46. package/dist/two-d/render/index.d.ts.map +1 -1
  47. package/dist/two-d/render/index.js +1 -0
  48. package/dist/two-d/render/index.js.map +1 -1
  49. package/dist/two-d/ui/Meter.d.ts +76 -0
  50. package/dist/two-d/ui/Meter.d.ts.map +1 -0
  51. package/dist/two-d/ui/Meter.js +134 -0
  52. package/dist/two-d/ui/Meter.js.map +1 -0
  53. package/dist/two-d/ui/SettingsScreen.d.ts +112 -0
  54. package/dist/two-d/ui/SettingsScreen.d.ts.map +1 -0
  55. package/dist/two-d/ui/SettingsScreen.js +338 -0
  56. package/dist/two-d/ui/SettingsScreen.js.map +1 -0
  57. package/dist/two-d/ui/index.d.ts +4 -0
  58. package/dist/two-d/ui/index.d.ts.map +1 -1
  59. package/dist/two-d/ui/index.js +2 -0
  60. package/dist/two-d/ui/index.js.map +1 -1
  61. package/dist/version.d.ts +1 -1
  62. package/dist/version.js +1 -1
  63. package/package.json +1 -1
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Frame-time-driven quality scaling over item 360's static fit: `fitResolution` answers
3
+ * what a device can afford once, and this watches what actually happens, stepping the
4
+ * backing-store ratio down when frames keep missing their budget and stepping back up
5
+ * only after a much longer streak inside it. Pure numbers in and out - the game (see
6
+ * `Game`'s `qualityScaling` option) applies the returned ratio to its renderer, so this
7
+ * stays renderer-free and headless-testable.
8
+ *
9
+ * Stepping up is deliberately an order of magnitude slower than stepping down: a frame
10
+ * inside budget at a reduced ratio proves nothing about the next ratio up, so recovery
11
+ * needs a sustained streak, not a good moment.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { QualityScaler } from '@datamoc/mw_games/two-d';
16
+ *
17
+ * const scaler = new QualityScaler({ ceiling: 2 });
18
+ * for (let i = 0; i < 60; i++) scaler.observe(1 / 30);
19
+ * console.log(scaler.ratio); // 1.75
20
+ * ```
21
+ */
22
+ export class QualityScaler {
23
+ constructor(options) {
24
+ this.over = 0;
25
+ this.under = 0;
26
+ this.ceiling = normalizeCeiling(options.ceiling);
27
+ const min = options.minRatio ?? 1;
28
+ this.floor = Number.isFinite(min) && min > 0 ? Math.min(min, this.ceiling) : Math.min(1, this.ceiling);
29
+ const fps = options.targetFps ?? 60;
30
+ this.budget = Number.isFinite(fps) && fps > 0 ? 1 / fps : 1 / 60;
31
+ this.downAfter = streakLength(options.overBudgetFrames, 60);
32
+ this.upAfter = streakLength(options.underBudgetFrames, 600);
33
+ this.step = Number.isFinite(options.step) && options.step > 0 ? options.step : 0.25;
34
+ this.ratio_ = this.ceiling;
35
+ }
36
+ /** the ratio the renderer should currently use */
37
+ get ratio() {
38
+ return this.ratio_;
39
+ }
40
+ /**
41
+ * A new device-fitted ceiling (rotation, display change): the current ratio is clamped
42
+ * down to it, never up - stepping back up stays the streak's job. Returns the ratio.
43
+ */
44
+ setCeiling(ceiling) {
45
+ this.ceiling = normalizeCeiling(ceiling);
46
+ if (this.ratio_ > this.ceiling) {
47
+ this.ratio_ = this.ceiling;
48
+ this.over = 0;
49
+ this.under = 0;
50
+ }
51
+ return this.ratio_;
52
+ }
53
+ /**
54
+ * Feeds one frame's seconds; returns the ratio the renderer should use, unchanged most
55
+ * frames. Non-finite or non-positive frames are ignored rather than counted either way,
56
+ * so a parked clock (a `timeScale` 0 pause) can never drive the policy.
57
+ */
58
+ observe(frameSeconds) {
59
+ if (!Number.isFinite(frameSeconds) || frameSeconds <= 0)
60
+ return this.ratio_;
61
+ if (frameSeconds > this.budget) {
62
+ this.over++;
63
+ this.under = 0;
64
+ if (this.over >= this.downAfter && this.ratio_ > this.floor) {
65
+ this.ratio_ = Math.max(this.floor, this.ratio_ - this.step);
66
+ this.over = 0;
67
+ }
68
+ }
69
+ else {
70
+ this.under++;
71
+ this.over = 0;
72
+ if (this.under >= this.upAfter && this.ratio_ < this.ceiling) {
73
+ this.ratio_ = Math.min(this.ceiling, this.ratio_ + this.step);
74
+ this.under = 0;
75
+ }
76
+ }
77
+ return this.ratio_;
78
+ }
79
+ /** back to the ceiling with both streaks cleared */
80
+ reset() {
81
+ this.ratio_ = this.ceiling;
82
+ this.over = 0;
83
+ this.under = 0;
84
+ }
85
+ }
86
+ function normalizeCeiling(ceiling) {
87
+ return Number.isFinite(ceiling) && ceiling > 0 ? ceiling : 1;
88
+ }
89
+ function streakLength(value, fallback) {
90
+ return Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
91
+ }
92
+ //# sourceMappingURL=QualityScaler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QualityScaler.js","sourceRoot":"","sources":["../../src/two-d/QualityScaler.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,9 @@
11
11
  * `mwg/two-d/stage`.
12
12
  */
13
13
  export { Game } from './Game.ts';
14
- export type { GameOptions } from './Game.ts';
14
+ export type { GameOptions, AudioSuspendRig } from './Game.ts';
15
+ export { QualityScaler } from './QualityScaler.ts';
16
+ export type { QualityScalerOptions } from './QualityScaler.ts';
15
17
  export { Scene2D } from './Scene2D.ts';
16
18
  export type { Scene2DClass } from './Scene2D.ts';
17
19
  export * from './render/index.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/two-d/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/two-d/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
@@ -11,6 +11,7 @@
11
11
  * `mwg/two-d/stage`.
12
12
  */
13
13
  export { Game } from './Game.js';
14
+ export { QualityScaler } from './QualityScaler.js';
14
15
  export { Scene2D } from './Scene2D.js';
15
16
  export * from './render/index.js';
16
17
  export * from './ui/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/two-d/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/two-d/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,83 @@
1
+ import type { Camera } from './Camera.ts';
2
+ /**
3
+ * Anything a `SpriteGroup` can gate: a position in the world units the camera sees, and a
4
+ * per-frame advance. Both `AnimatedSprite` and `ParticleEmitter` satisfy this structurally,
5
+ * so a crowd of goblins and the campfire between them can share one group.
6
+ */
7
+ export interface SpriteGroupMember {
8
+ x: number;
9
+ y: number;
10
+ update(dt: number): void;
11
+ }
12
+ /**
13
+ * Whether a world-space point is on screen, for skipping animation work nobody sees.
14
+ *
15
+ * The edges count as on screen, and `margin` grows the box by that many world units on
16
+ * every side, for sprites whose bodies spill past their anchor point. Under a rotated
17
+ * camera the checked box is the axis-aligned one around the turned viewport (the same
18
+ * over-inclusive box `TileMap.cull` uses), so this can only ever animate too much, never
19
+ * freeze something the player can see.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { Camera, isOnScreen } from '@datamoc/mw_games/two-d/render';
24
+ *
25
+ * declare const camera: Camera;
26
+ *
27
+ * if (isOnScreen(camera, 160, 160)) console.log('the market square, animate it');
28
+ * console.log(isOnScreen(camera, 10000, 10000, 32)); // far away, even with a margin
29
+ * ```
30
+ */
31
+ export declare function isOnScreen(camera: Camera, x: number, y: number, margin?: number): boolean;
32
+ /**
33
+ * A crowd that only animates its on-screen members.
34
+ *
35
+ * `TileMap.cull(camera)` keeps tile *rendering* cost to what is on screen; this is the
36
+ * same idea for per-frame *animation* cost. A scene with hundreds of animated inhabitants
37
+ * calls `group.update(camera, dt)` once per frame instead of updating each sprite itself,
38
+ * and members outside `camera.view` (plus `margin`) simply keep whatever frame they had
39
+ * until they come back into view. Skipped members are never touched: no `paused` flag is
40
+ * set, no state is rewritten, so a sprite that leaves the group animates exactly as
41
+ * before.
42
+ *
43
+ * Members are positioned in the camera's own world units, the way `GridMover` and
44
+ * `TileMap.tileCenter` already place things: direct children of `camera.world`, or
45
+ * anything else whose `x`/`y` already read as world coordinates. Members nested deeper
46
+ * (a sword in a hero's hand) report their *local* position, so they belong to no group,
47
+ * or to one updated unconditionally.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { SpriteGroup, AnimatedSprite, Camera } from '@datamoc/mw_games/two-d/render';
52
+ *
53
+ * declare const camera: Camera;
54
+ *
55
+ * const crowd = new SpriteGroup();
56
+ * const goblin = new AnimatedSprite();
57
+ * crowd.add(goblin);
58
+ *
59
+ * function onFrame(dt: number): void {
60
+ * crowd.update(camera, dt); // goblins off screen keep their frame, for free
61
+ * }
62
+ * ```
63
+ */
64
+ export declare class SpriteGroup {
65
+ private members;
66
+ /** how many members this group holds */
67
+ get size(): number;
68
+ /**
69
+ * Adds a member; adding the same one twice is a no-op, so a spawn loop can call this
70
+ * every frame without growing the group.
71
+ */
72
+ add(member: SpriteGroupMember): this;
73
+ /** removes a member; reports whether it was there */
74
+ remove(member: SpriteGroupMember): boolean;
75
+ /** empties the group, for a scene change */
76
+ clear(): void;
77
+ /**
78
+ * Advances every member on screen by `dt`, skipping the rest. `margin` grows the
79
+ * tested box the way `isOnScreen`'s does, for members larger than a point.
80
+ */
81
+ update(camera: Camera, dt: number, margin?: number): void;
82
+ }
83
+ //# sourceMappingURL=SpriteGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpriteGroup.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/SpriteGroup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAmBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,OAAO,CAEpF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAA2B;IAE1C,wCAAwC;IACxC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAGnC;IAED,qDAAqD;IACrD,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAKzC;IAED,4CAA4C;IAC5C,KAAK,IAAI,IAAI,CAEZ;IAED;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,IAAI,CAOnD;CACD"}
@@ -0,0 +1,107 @@
1
+ //the one rule both `isOnScreen` and `SpriteGroup.update` apply: the box is read once per
2
+ //frame by the caller, never once per member, since `Camera.view` re-derives its corners
3
+ //(and their trigonometry when rotated) on every read
4
+ function insideBox(box, x, y, margin) {
5
+ return (x >= box.x - margin &&
6
+ x <= box.x + box.width + margin &&
7
+ y >= box.y - margin &&
8
+ y <= box.y + box.height + margin);
9
+ }
10
+ /**
11
+ * Whether a world-space point is on screen, for skipping animation work nobody sees.
12
+ *
13
+ * The edges count as on screen, and `margin` grows the box by that many world units on
14
+ * every side, for sprites whose bodies spill past their anchor point. Under a rotated
15
+ * camera the checked box is the axis-aligned one around the turned viewport (the same
16
+ * over-inclusive box `TileMap.cull` uses), so this can only ever animate too much, never
17
+ * freeze something the player can see.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { Camera, isOnScreen } from '@datamoc/mw_games/two-d/render';
22
+ *
23
+ * declare const camera: Camera;
24
+ *
25
+ * if (isOnScreen(camera, 160, 160)) console.log('the market square, animate it');
26
+ * console.log(isOnScreen(camera, 10000, 10000, 32)); // far away, even with a margin
27
+ * ```
28
+ */
29
+ export function isOnScreen(camera, x, y, margin = 0) {
30
+ return insideBox(camera.view, x, y, margin);
31
+ }
32
+ /**
33
+ * A crowd that only animates its on-screen members.
34
+ *
35
+ * `TileMap.cull(camera)` keeps tile *rendering* cost to what is on screen; this is the
36
+ * same idea for per-frame *animation* cost. A scene with hundreds of animated inhabitants
37
+ * calls `group.update(camera, dt)` once per frame instead of updating each sprite itself,
38
+ * and members outside `camera.view` (plus `margin`) simply keep whatever frame they had
39
+ * until they come back into view. Skipped members are never touched: no `paused` flag is
40
+ * set, no state is rewritten, so a sprite that leaves the group animates exactly as
41
+ * before.
42
+ *
43
+ * Members are positioned in the camera's own world units, the way `GridMover` and
44
+ * `TileMap.tileCenter` already place things: direct children of `camera.world`, or
45
+ * anything else whose `x`/`y` already read as world coordinates. Members nested deeper
46
+ * (a sword in a hero's hand) report their *local* position, so they belong to no group,
47
+ * or to one updated unconditionally.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { SpriteGroup, AnimatedSprite, Camera } from '@datamoc/mw_games/two-d/render';
52
+ *
53
+ * declare const camera: Camera;
54
+ *
55
+ * const crowd = new SpriteGroup();
56
+ * const goblin = new AnimatedSprite();
57
+ * crowd.add(goblin);
58
+ *
59
+ * function onFrame(dt: number): void {
60
+ * crowd.update(camera, dt); // goblins off screen keep their frame, for free
61
+ * }
62
+ * ```
63
+ */
64
+ export class SpriteGroup {
65
+ constructor() {
66
+ this.members = [];
67
+ }
68
+ /** how many members this group holds */
69
+ get size() {
70
+ return this.members.length;
71
+ }
72
+ /**
73
+ * Adds a member; adding the same one twice is a no-op, so a spawn loop can call this
74
+ * every frame without growing the group.
75
+ */
76
+ add(member) {
77
+ if (!this.members.includes(member))
78
+ this.members.push(member);
79
+ return this;
80
+ }
81
+ /** removes a member; reports whether it was there */
82
+ remove(member) {
83
+ const index = this.members.indexOf(member);
84
+ if (index < 0)
85
+ return false;
86
+ this.members.splice(index, 1);
87
+ return true;
88
+ }
89
+ /** empties the group, for a scene change */
90
+ clear() {
91
+ this.members.length = 0;
92
+ }
93
+ /**
94
+ * Advances every member on screen by `dt`, skipping the rest. `margin` grows the
95
+ * tested box the way `isOnScreen`'s does, for members larger than a point.
96
+ */
97
+ update(camera, dt, margin = 0) {
98
+ const view = camera.view;
99
+ //a snapshot, so a member added or removed mid-frame (an onFinish hook spawning a
100
+ //replacement, say) cannot shift the array under this loop
101
+ for (const member of [...this.members]) {
102
+ if (insideBox(view, member.x, member.y, margin))
103
+ member.update(dt);
104
+ }
105
+ }
106
+ }
107
+ //# sourceMappingURL=SpriteGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpriteGroup.js","sourceRoot":"","sources":["../../../src/two-d/render/SpriteGroup.ts"],"names":[],"mappings":"AAaA,yFAAyF;AACzF,wFAAwF;AACxF,qDAAqD;AACrD,SAAS,SAAS,CACjB,GAA4D,EAC5D,CAAS,EACT,CAAS,EACT,MAAc;IAEd,OAAO,CACN,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM;QACnB,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,GAAG,MAAM;QAC/B,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM;QACnB,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,CAChC,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,CAAS,EAAE,CAAS,EAAE,MAAM,GAAG,CAAC;IAC1E,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,OAAO,WAAW;IAAxB;QACS,YAAO,GAAwB,EAAE,CAAC;IAyC3C,CAAC;IAvCA,wCAAwC;IACxC,IAAI,IAAI;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,MAAyB;QAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACb,CAAC;IAED,qDAAqD;IACrD,MAAM,CAAC,MAAyB;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,4CAA4C;IAC5C,KAAK;QACJ,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAc,EAAE,EAAU,EAAE,MAAM,GAAG,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACzB,iFAAiF;QACjF,0DAA0D;QAC1D,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC;gBAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpE,CAAC;IACF,CAAC;CACD"}
@@ -5,6 +5,8 @@ export { applyAllImageModifiers, applyImageModifiers, applyTextureModifiers, ble
5
5
  export type { ChannelSource, ImageModifier, ImageTextureProbe, ParsedImagePath, RotateMode, RotatedPixels, } from './ImageModifiers.ts';
6
6
  export { AnimatedSprite, Animation } from './AnimatedSprite.ts';
7
7
  export type { AnimationFrame, AnimationFrameInput, AnimationOptions } from './AnimatedSprite.ts';
8
+ export { SpriteGroup, isOnScreen } from './SpriteGroup.ts';
9
+ export type { SpriteGroupMember } from './SpriteGroup.ts';
8
10
  export { SpriteSheet } from './SpriteSheet.ts';
9
11
  export { Camera, createCamera, snapZoom } from './Camera.ts';
10
12
  export type { CameraOptions } from './Camera.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ export { ColorTransformBatcher, packColorAdd, packTintAdd, NO_COLOR_ADD } from '
2
2
  export { TintedSprite, registerColorTransform } from './TintedSprite.js';
3
3
  export { applyAllImageModifiers, applyImageModifiers, applyTextureModifiers, blendMatrix, blendPixels, channelScaleMatrix, channelSwapMatrix, colorShiftMatrix, croppedTexture, imageModifier, maskPixels, parseColorPairs, parseImagePath, parsePaletteLists, parseRotateMode, rotatePixels, spriteColorMatrix, } from './ImageModifiers.js';
4
4
  export { AnimatedSprite, Animation } from './AnimatedSprite.js';
5
+ export { SpriteGroup, isOnScreen } from './SpriteGroup.js';
5
6
  export { SpriteSheet } from './SpriteSheet.js';
6
7
  export { Camera, createCamera, snapZoom } from './Camera.js';
7
8
  export { Viewport, splitScreenHalves } from './Viewport.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EACN,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,UAAU,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG3F,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AASzE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAWzG,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASnG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEtG,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAUxG,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EACN,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,UAAU,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG3F,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AASzE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAWzG,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASnG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEtG,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAUxG,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { Container } from 'pixi.js';
2
+ import type { Texture2D } from '../render/Types2D.ts';
3
+ export interface MeterOptions {
4
+ /** total icons; fractional counts floor, below 1 becomes 1 */
5
+ count: number;
6
+ /** filled icons, fractions allowed (a half heart is 0.5); defaults to full */
7
+ value?: number;
8
+ /** icon diameter in pixels */
9
+ size?: number;
10
+ /** gap between icons in pixels */
11
+ gap?: number;
12
+ /** the filled icon's art; `emptyTexture` must come with it, or neither */
13
+ filledTexture?: Texture2D;
14
+ /** the empty icon's art; `filledTexture` must come with it, or neither */
15
+ emptyTexture?: Texture2D;
16
+ /** filled colour in flat mode; tints `filledTexture` too, when both are given */
17
+ color?: number;
18
+ /** empty colour in flat mode; the theme's panel fill when omitted */
19
+ emptyColor?: number;
20
+ }
21
+ /**
22
+ * A discrete meter: N icons with a value filled, the Zelda heart row or star rating to
23
+ * `Bar`'s continuous fill. Fractions clip mid-icon through a mask, so halves (or any
24
+ * fraction) work identically for flat shapes and game-supplied textures, with no extra
25
+ * half-state art to author.
26
+ *
27
+ * Flat icons are theme-drawn pips; game art arrives as a `filledTexture`/`emptyTexture`
28
+ * pair, which must come together - one without the other throws, since a half-drawn
29
+ * meter would only guess. Colour follows the theme the way `Bar` does unless the game
30
+ * passes its own, and a passed colour survives later theme changes.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { Meter } from '@datamoc/mw_games/two-d/ui';
35
+ *
36
+ * const hearts = new Meter({ count: 5, value: 3 });
37
+ *
38
+ * hearts.setValue(2.5); // down to two and a half hearts
39
+ * console.log(hearts.value); // 2.5
40
+ * ```
41
+ */
42
+ export declare class Meter extends Container {
43
+ private emptyLayer;
44
+ private filledLayer;
45
+ private maskShape;
46
+ private count_;
47
+ private size_;
48
+ private gap_;
49
+ private value_;
50
+ private explicitColor;
51
+ private fillColor;
52
+ private emptyColor_?;
53
+ private readonly filledTexture?;
54
+ private readonly emptyTexture?;
55
+ private readonly themeListener;
56
+ constructor(options: MeterOptions);
57
+ /** filled icons, fractions included */
58
+ get value(): number;
59
+ /** total icons */
60
+ get count(): number;
61
+ /** the resolved filled colour: the explicit one, or the theme's highlight */
62
+ get color(): number;
63
+ setValue(value: number, count?: number): void;
64
+ /**
65
+ * Recolours the fill at runtime, counting as explicit exactly as passing `color` does,
66
+ * so a later theme change cannot throw the game's own colour away.
67
+ */
68
+ setColor(color: number): void;
69
+ resize(size: number, gap?: number): void;
70
+ private get totalWidth();
71
+ private iconX;
72
+ private draw;
73
+ private icon;
74
+ destroy(options?: Parameters<Container['destroy']>[0]): void;
75
+ }
76
+ //# sourceMappingURL=Meter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Meter.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/Meter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,SAAS,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC5B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,0EAA0E;IAC1E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,0EAA0E;IAC1E,YAAY,CAAC,EAAE,SAAS,CAAC;IAEzB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,KAAM,SAAQ,SAAS;IACnC,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,SAAS,CAAkB;IAEnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAY;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAY;IAE1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IAEnD,YAAY,OAAO,EAAE,YAAY,EAuBhC;IAED,uCAAuC;IACvC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,kBAAkB;IAClB,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,6EAA6E;IAC7E,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAoB,GAAG,IAAI,CAIzD;IAED;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5B;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,IAAI,CAIlD;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,IAAI;IAkBZ,OAAO,CAAC,IAAI;IAeH,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAGpE;CACD"}
@@ -0,0 +1,134 @@
1
+ import { Container, Graphics, Sprite } from 'pixi.js';
2
+ import { theme, themeChanged } from './theme.js';
3
+ /**
4
+ * A discrete meter: N icons with a value filled, the Zelda heart row or star rating to
5
+ * `Bar`'s continuous fill. Fractions clip mid-icon through a mask, so halves (or any
6
+ * fraction) work identically for flat shapes and game-supplied textures, with no extra
7
+ * half-state art to author.
8
+ *
9
+ * Flat icons are theme-drawn pips; game art arrives as a `filledTexture`/`emptyTexture`
10
+ * pair, which must come together - one without the other throws, since a half-drawn
11
+ * meter would only guess. Colour follows the theme the way `Bar` does unless the game
12
+ * passes its own, and a passed colour survives later theme changes.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { Meter } from '@datamoc/mw_games/two-d/ui';
17
+ *
18
+ * const hearts = new Meter({ count: 5, value: 3 });
19
+ *
20
+ * hearts.setValue(2.5); // down to two and a half hearts
21
+ * console.log(hearts.value); // 2.5
22
+ * ```
23
+ */
24
+ export class Meter extends Container {
25
+ constructor(options) {
26
+ super();
27
+ this.emptyLayer = new Container();
28
+ this.filledLayer = new Container();
29
+ this.maskShape = new Graphics();
30
+ this.themeListener = () => this.draw();
31
+ if ((options.filledTexture === undefined) !== (options.emptyTexture === undefined)) {
32
+ throw new Error('a Meter takes filledTexture and emptyTexture together, or neither');
33
+ }
34
+ this.count_ = normalizeCount(options.count);
35
+ this.size_ = options.size ?? 16;
36
+ this.gap_ = options.gap ?? 4;
37
+ this.value_ = clampValue(options.value ?? this.count_, this.count_);
38
+ this.explicitColor = options.color !== undefined;
39
+ this.fillColor = options.color ?? theme().color.textHighlight;
40
+ this.emptyColor_ = options.emptyColor;
41
+ this.filledTexture = options.filledTexture;
42
+ this.emptyTexture = options.emptyTexture;
43
+ this.addChild(this.emptyLayer);
44
+ this.addChild(this.filledLayer);
45
+ this.addChild(this.maskShape);
46
+ this.filledLayer.mask = this.maskShape;
47
+ this.draw();
48
+ themeChanged.add(this.themeListener);
49
+ }
50
+ /** filled icons, fractions included */
51
+ get value() {
52
+ return this.value_;
53
+ }
54
+ /** total icons */
55
+ get count() {
56
+ return this.count_;
57
+ }
58
+ /** the resolved filled colour: the explicit one, or the theme's highlight */
59
+ get color() {
60
+ return this.fillColor;
61
+ }
62
+ setValue(value, count = this.count_) {
63
+ this.count_ = normalizeCount(count);
64
+ this.value_ = clampValue(value, this.count_);
65
+ this.draw();
66
+ }
67
+ /**
68
+ * Recolours the fill at runtime, counting as explicit exactly as passing `color` does,
69
+ * so a later theme change cannot throw the game's own colour away.
70
+ */
71
+ setColor(color) {
72
+ this.explicitColor = true;
73
+ this.fillColor = color;
74
+ this.draw();
75
+ }
76
+ resize(size, gap = this.gap_) {
77
+ this.size_ = size;
78
+ this.gap_ = gap;
79
+ this.draw();
80
+ }
81
+ get totalWidth() {
82
+ return this.count_ * this.size_ + (this.count_ - 1) * this.gap_;
83
+ }
84
+ iconX(index) {
85
+ const x = index * (this.size_ + this.gap_);
86
+ return theme().direction === 'rtl' ? this.totalWidth - x - this.size_ : x;
87
+ }
88
+ draw() {
89
+ const t = theme();
90
+ if (!this.explicitColor)
91
+ this.fillColor = t.color.textHighlight;
92
+ const empty = this.emptyColor_ ?? t.color.panelFill;
93
+ this.emptyLayer.removeChildren();
94
+ this.filledLayer.removeChildren();
95
+ for (let i = 0; i < this.count_; i++) {
96
+ const x = this.iconX(i);
97
+ this.emptyLayer.addChild(this.icon(x, empty, this.emptyTexture, false));
98
+ this.filledLayer.addChild(this.icon(x, this.fillColor, this.filledTexture, true));
99
+ }
100
+ const filledWidth = this.totalWidth * (this.count_ > 0 ? this.value_ / this.count_ : 0);
101
+ const maskX = t.direction === 'rtl' ? this.totalWidth - filledWidth : 0;
102
+ this.maskShape.clear().rect(maskX, 0, filledWidth, this.size_).fill({ color: 0xffffff });
103
+ }
104
+ icon(x, color, texture, tint) {
105
+ if (texture) {
106
+ const sprite = new Sprite(texture);
107
+ sprite.x = x;
108
+ sprite.width = this.size_;
109
+ sprite.height = this.size_;
110
+ if (tint && this.explicitColor)
111
+ sprite.tint = color;
112
+ return sprite;
113
+ }
114
+ const shape = new Graphics();
115
+ const radius = this.size_ / 2;
116
+ shape.circle(x + radius, radius, radius).fill({ color });
117
+ return shape;
118
+ }
119
+ destroy(options) {
120
+ themeChanged.remove(this.themeListener);
121
+ super.destroy(options);
122
+ }
123
+ }
124
+ function clampValue(value, count) {
125
+ if (!Number.isFinite(value))
126
+ return count;
127
+ return Math.max(0, Math.min(count, value));
128
+ }
129
+ function normalizeCount(count) {
130
+ if (!Number.isFinite(count))
131
+ return 1;
132
+ return Math.max(1, Math.floor(count));
133
+ }
134
+ //# sourceMappingURL=Meter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Meter.js","sourceRoot":"","sources":["../../../src/two-d/ui/Meter.ts"],"names":[],"mappings":"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"}