melonjs 20.13.0 → 20.14.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.
- package/README.md +65 -22
- package/build/application/application.d.ts +6 -1
- package/build/application/application.d.ts.map +1 -1
- package/build/application/header.d.ts.map +1 -1
- package/build/application/resize.d.ts.map +1 -1
- package/build/application/settings.d.ts +13 -8
- package/build/application/settings.d.ts.map +1 -1
- package/build/audio/audio.d.ts +8 -4
- package/build/audio/audio.d.ts.map +1 -1
- package/build/audio/backend/engine.d.ts.map +1 -1
- package/build/audio/playback.d.ts +2 -2
- package/build/audio/playback.d.ts.map +1 -1
- package/build/audio/spatial.d.ts.map +1 -1
- package/build/audio/types.d.ts +15 -5
- package/build/audio/types.d.ts.map +1 -1
- package/build/camera/camera2d.d.ts +10 -9
- package/build/camera/camera2d.d.ts.map +1 -1
- package/build/camera/camera3d.d.ts +11 -8
- package/build/camera/camera3d.d.ts.map +1 -1
- package/build/geometries/path2d.d.ts +9 -8
- package/build/geometries/path2d.d.ts.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +40993 -39738
- package/build/index.js.map +4 -4
- package/build/input/keyboard.d.ts.map +1 -1
- package/build/input/pointerevent.d.ts.map +1 -1
- package/build/level/gltf/GLTFModel.d.ts.map +1 -1
- package/build/level/level.d.ts.map +1 -1
- package/build/level/tiled/TMXLayer.d.ts +2 -1
- package/build/level/tiled/TMXLayer.d.ts.map +1 -1
- package/build/level/tiled/TMXTileMap.d.ts +13 -3
- package/build/level/tiled/TMXTileMap.d.ts.map +1 -1
- package/build/level/tiled/TMXTileset.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXHexagonalRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXIsometricRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts +1 -0
- package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXRenderer.d.ts +7 -3
- package/build/level/tiled/renderer/TMXRenderer.d.ts.map +1 -1
- package/build/lighting/light3d.d.ts +55 -0
- package/build/lighting/light3d.d.ts.map +1 -1
- package/build/loader/cache.d.ts +146 -97
- package/build/loader/cache.d.ts.map +1 -1
- package/build/loader/internal-types.d.ts +69 -0
- package/build/loader/internal-types.d.ts.map +1 -0
- package/build/loader/loader.d.ts +584 -292
- package/build/loader/loader.d.ts.map +1 -1
- package/build/loader/parsers/audio.d.ts.map +1 -1
- package/build/loader/parsers/fontface.d.ts.map +1 -1
- package/build/loader/parsers/gltf.d.ts.map +1 -1
- package/build/loader/parsers/tmx.d.ts.map +1 -1
- package/build/math/color.d.ts +4 -0
- package/build/math/color.d.ts.map +1 -1
- package/build/math/noise.d.ts +16 -16
- package/build/math/noise.d.ts.map +1 -1
- package/build/physics/adapter.d.ts +64 -25
- package/build/physics/adapter.d.ts.map +1 -1
- package/build/physics/builtin/body.d.ts +9 -0
- package/build/physics/builtin/body.d.ts.map +1 -1
- package/build/physics/builtin/builtin-adapter.d.ts +25 -3
- package/build/physics/builtin/builtin-adapter.d.ts.map +1 -1
- package/build/physics/builtin/detector.d.ts.map +1 -1
- package/build/physics/builtin/raycast.d.ts.map +1 -1
- package/build/physics/world.d.ts +40 -10
- package/build/physics/world.d.ts.map +1 -1
- package/build/renderable/container.d.ts +1 -0
- package/build/renderable/container.d.ts.map +1 -1
- package/build/renderable/draggable.d.ts.map +1 -1
- package/build/renderable/frameAnimation.d.ts.map +1 -1
- package/build/renderable/instanced_mesh.d.ts +16 -14
- package/build/renderable/instanced_mesh.d.ts.map +1 -1
- package/build/renderable/mesh.d.ts +62 -5
- package/build/renderable/mesh.d.ts.map +1 -1
- package/build/renderable/trigger.d.ts +5 -0
- package/build/renderable/trigger.d.ts.map +1 -1
- package/build/renderable/ui/uibaseelement.d.ts +8 -1
- package/build/renderable/ui/uibaseelement.d.ts.map +1 -1
- package/build/renderable/ui/uicheckbox.d.ts.map +1 -1
- package/build/system/device.d.ts +11 -2
- package/build/system/device.d.ts.map +1 -1
- package/build/system/fullscreen.d.ts.map +1 -1
- package/build/system/pool.d.ts.map +1 -1
- package/build/utils/utils.d.ts.map +1 -1
- package/build/video/canvas/canvas_renderer.d.ts +16 -14
- package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
- package/build/video/canvas_factory.d.ts.map +1 -1
- package/build/video/effects/shadereffect.d.ts +127 -0
- package/build/video/effects/shadereffect.d.ts.map +1 -1
- package/build/video/renderer.d.ts.map +1 -1
- package/build/video/webgl/batchers/lit_mesh_batcher.d.ts.map +1 -1
- package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
- package/build/video/webgpu/batchers/lit_mesh_batcher.d.ts.map +1 -1
- package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/melonjs/SKILL.md +38 -14
- package/skills/melonjs-20-migration/SKILL.md +50 -7
- package/skills/melonjs-3d/SKILL.md +138 -38
- package/skills/melonjs-3d-assets/SKILL.md +83 -33
- package/skills/melonjs-audio/SKILL.md +55 -14
- package/skills/melonjs-camera-and-drawing/SKILL.md +95 -8
- package/skills/melonjs-deployment/SKILL.md +92 -14
- package/skills/melonjs-display-and-scaling/SKILL.md +8 -3
- package/skills/melonjs-effects-and-shaders/SKILL.md +46 -15
- package/skills/melonjs-events/SKILL.md +3 -2
- package/skills/melonjs-getting-started/SKILL.md +5 -0
- package/skills/melonjs-input/SKILL.md +65 -15
- package/skills/melonjs-lighting/SKILL.md +13 -1
- package/skills/melonjs-loading-assets/SKILL.md +202 -27
- package/skills/melonjs-math/SKILL.md +12 -5
- package/skills/melonjs-particles-and-trails/SKILL.md +7 -3
- package/skills/melonjs-performance/SKILL.md +18 -8
- package/skills/melonjs-physics/SKILL.md +385 -127
- package/skills/melonjs-plugins/SKILL.md +45 -11
- package/skills/melonjs-renderables/SKILL.md +24 -7
- package/skills/melonjs-renderer-backends/SKILL.md +38 -17
- package/skills/melonjs-scenes-and-state/SKILL.md +30 -5
- package/skills/melonjs-sprites-and-animation/SKILL.md +23 -2
- package/skills/melonjs-tilemaps/SKILL.md +56 -18
- package/skills/melonjs-ui-and-text/SKILL.md +120 -25
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: melonjs-ui-and-text
|
|
3
|
-
description: "Use this skill for HUDs, buttons, menus, options screens, dialogue panels, progress bars and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, UICheckbox, UISlider, ProgressBar, UIPanel (skins, layout, scrolling), Draggable and DropTarget, the floating screen-space container pattern, which of two overlapping panels gets the pointer, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, checkbox, radio button,
|
|
3
|
+
description: "Use this skill for HUDs, buttons, menus, options screens, dialogue panels, progress bars and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, UICheckbox, UISlider, ProgressBar, UIPanel (skins, layout, scrolling), keyboard and gamepad focus, Draggable and DropTarget, the floating screen-space container pattern, which of two overlapping panels gets the pointer, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, checkbox, radio button, slider, volume slider, options menu, settings screen, scrolling list, UI skin, progress bar, health bar, menu, dialogue, moveToTop, onOver, onClick, bindKey, keyboard shortcut, Tween, animate a label, wavy text, glyphEffect, rainbow text, typewriter, visibleRatio, drag and drop, isDraggable, focus, fillStyle, fillGradient, gradient text, tint, font, fontface, wordWrapWidth, score display, fullscreen, requestFullscreen, fullscreen button."
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -204,6 +204,26 @@ const help = new Text(8, 8, {
|
|
|
204
204
|
// "CONTROLS" on its own line, then the sentence wrapped under it
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
+
### Typewriter reveal: `visibleRatio`
|
|
208
|
+
|
|
209
|
+
`visibleCharacters` (`-1`, the default, shows them all) and `visibleRatio`
|
|
210
|
+
(0 to 1) show a label a character at a time, on `Text` and `BitmapText` alike.
|
|
211
|
+
Tween the ratio: it takes the same time whatever the length of the string.
|
|
212
|
+
|
|
213
|
+
```js
|
|
214
|
+
line.setText("The door is locked. The keeper has the key.");
|
|
215
|
+
line.visibleRatio = 0;
|
|
216
|
+
new Tween(line).to({ visibleRatio: 1 }, { duration: 1500 }).start();
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Line breaks are not counted, and the wrapping and the bounds are those of the
|
|
220
|
+
whole string, so a word does not jump to the next line as it appears. The two
|
|
221
|
+
classes differ in two ways. A `BitmapText` keeps each glyph where the full line
|
|
222
|
+
puts it, while a centred or right-aligned `Text` aligns only the part shown so
|
|
223
|
+
far, so it slides sideways as it types: left-align a `Text` you reveal. And a
|
|
224
|
+
`Text` repaints and re-uploads its bake at every step, where a `BitmapText`
|
|
225
|
+
just draws fewer glyphs.
|
|
226
|
+
|
|
207
227
|
### `fillStyle` means two different things
|
|
208
228
|
|
|
209
229
|
The name is shared and the behaviour is not, which is the trap when moving a
|
|
@@ -291,10 +311,13 @@ an amplitude around an eighth of it, a wavelength around ten times it, and a
|
|
|
291
311
|
little under 5 radians per second. For a shake, re-target each glyph roughly
|
|
292
312
|
20 to 40 times a second.
|
|
293
313
|
|
|
294
|
-
`ctx.time`
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
314
|
+
`ctx.time` runs only while an effect is set and nothing resets it, so it is 0
|
|
315
|
+
only when a label gets its **first** effect. A label that already had one, or
|
|
316
|
+
is reused across lives, carries the old clock, and a decay measured from
|
|
317
|
+
`ctx.time` itself is already spent there. Note `ctx.time` on the effect's first
|
|
318
|
+
call and measure from that, as the shake below does, and attach it at the
|
|
319
|
+
moment you want to be t=0: on the frame the hit lands, not when the label was
|
|
320
|
+
built.
|
|
298
321
|
|
|
299
322
|
Both, whole:
|
|
300
323
|
|
|
@@ -322,22 +345,28 @@ const angle = (i, tick) => {
|
|
|
322
345
|
const h = Math.sin(i * 127.1 + tick * 311.7) * 43758.5453;
|
|
323
346
|
return (h - Math.floor(h)) * Math.PI * 2;
|
|
324
347
|
};
|
|
325
|
-
const impact = (amplitude, durationMs, rate) =>
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
348
|
+
const impact = (amplitude, durationMs, rate) => {
|
|
349
|
+
let start; // ctx.time on the first call
|
|
350
|
+
return (out, ctx) => {
|
|
351
|
+
start ??= ctx.time; // the label's clock never resets
|
|
352
|
+
const t = ctx.time - start;
|
|
353
|
+
const left = 1 - t / durationMs;
|
|
354
|
+
if (left <= 0) {
|
|
355
|
+
return; // settled; `out` is already zeroed
|
|
356
|
+
}
|
|
357
|
+
const amp = amplitude * left * left;
|
|
358
|
+
const tick = (t / 1000) * rate;
|
|
359
|
+
const held = Math.floor(tick);
|
|
360
|
+
const k = tick - held;
|
|
361
|
+
const a = angle(ctx.index, held);
|
|
362
|
+
const b = angle(ctx.index, held + 1);
|
|
363
|
+
out.offsetX = Math.round((Math.sin(a) + (Math.sin(b) - Math.sin(a)) * k) * amp);
|
|
364
|
+
out.offsetY = Math.round((Math.cos(a) + (Math.cos(b) - Math.cos(a)) * k) * amp);
|
|
365
|
+
};
|
|
338
366
|
};
|
|
339
367
|
|
|
340
|
-
//
|
|
368
|
+
// a new impact at the moment of each hit: it measures from its own first call,
|
|
369
|
+
// so it shakes again on a banner that has shown one before
|
|
341
370
|
banner.setText("CAPSIZED!");
|
|
342
371
|
banner.glyphEffect = impact(3, 650, 24);
|
|
343
372
|
```
|
|
@@ -462,6 +491,13 @@ hp.max = 50; // re-clamps the value into the new range
|
|
|
462
491
|
`direction` takes `"left-to-right"` (the default), `"right-to-left"`,
|
|
463
492
|
`"top-to-bottom"` or `"bottom-to-top"`, each growing from its own edge.
|
|
464
493
|
|
|
494
|
+
`showLabel: true` writes text centred over the bar, a percentage by default:
|
|
495
|
+
`` labelFormat: (value, ratio) => `${Math.round(value)} HP` `` changes what it says,
|
|
496
|
+
and `font` (a CSS family), `fontSize` and `labelFillStyle` how it looks.
|
|
497
|
+
`onChange(value, ratio, bar)` is called on every change of the value, from code
|
|
498
|
+
too, unlike a checkbox's or a slider's: a bar has no user input to tell apart.
|
|
499
|
+
Setting the value it already has calls nothing.
|
|
500
|
+
|
|
465
501
|
**The colour follows the value by mutating the `Color` you passed.** This is
|
|
466
502
|
the one non-obvious part, and it is deliberate: every game wants a different
|
|
467
503
|
rule, and most want the colour somewhere else too, next to a shader uniform or
|
|
@@ -667,7 +703,9 @@ scrolls with the wheel over the panel and by dragging, with momentum when
|
|
|
667
703
|
flung. A scrollbar shows while it does not fit. `scrollTo(x, y)`,
|
|
668
704
|
`scrollToChild(child)`, `scrollX` / `scrollY`, `maxScrollX` / `maxScrollY` and
|
|
669
705
|
an `onScroll(x, y, panel)` setting are there to drive it from code. Scrolling
|
|
670
|
-
from code stops a fling that is still coasting.
|
|
706
|
+
from code stops a fling that is still coasting. `clearChildren()` empties the
|
|
707
|
+
list and scrolls back to the start, ready to be filled again, and `autoSize`
|
|
708
|
+
is ignored on a scrolling panel.
|
|
671
709
|
|
|
672
710
|
What to know:
|
|
673
711
|
|
|
@@ -717,7 +755,7 @@ by default):
|
|
|
717
755
|
| `onClick(event)` | pressed | `false` to stop the event propagating |
|
|
718
756
|
| `onRelease(event)` | the press ends (up, left while held, or cancelled) | `false` to stop propagating |
|
|
719
757
|
| `onOver(event)` | pointer enters | `false` to stop propagating |
|
|
720
|
-
| `onOut(event)` | pointer leaves | — |
|
|
758
|
+
| `onOut(event)` | pointer leaves, or the element is removed while hovered (no event then) | — |
|
|
721
759
|
| `onHold()` | pressed and held | — |
|
|
722
760
|
|
|
723
761
|
```js
|
|
@@ -736,6 +774,12 @@ class MuteButton extends UISpriteElement {
|
|
|
736
774
|
}
|
|
737
775
|
```
|
|
738
776
|
|
|
777
|
+
Undo in `onOut` whatever `onOver` set up (a tooltip, a highlight, a cursor):
|
|
778
|
+
it also runs when the element leaves the world while the pointer is on it,
|
|
779
|
+
removed on its own, with the panel holding it, or with the scene, so nothing
|
|
780
|
+
is left behind. Keep effects that should only follow the pointer (a sound, a
|
|
781
|
+
tween) out of it, or check `event`, which is `undefined` for a removal.
|
|
782
|
+
|
|
739
783
|
The image is `button.sprite`: animations, tint and regions live there
|
|
740
784
|
(`setRegion`, `addAnimation`, `setCurrentAnimation` and `isCurrentAnimation`
|
|
741
785
|
are also on the element as shortcuts). As a `UIBaseElement` it has
|
|
@@ -777,7 +821,11 @@ as before, for subclasses.
|
|
|
777
821
|
|
|
778
822
|
`font` is a loaded bitmap font's name, drawn with `BitmapText` as before, or
|
|
779
823
|
any other name, drawn as a CSS font with `Text`. The label is
|
|
780
|
-
`button.label` (`bitmapText
|
|
824
|
+
`button.label` (`bitmapText`, its old name, is deprecated since 20.13.0).
|
|
825
|
+
|
|
826
|
+
With no skin it is a rounded rectangle in `hoverOffColor`, `hoverOnColor`
|
|
827
|
+
under the pointer and `pressedColor` while held (`hoverOnColor` when left
|
|
828
|
+
out), outlined in `borderColor`.
|
|
781
829
|
|
|
782
830
|
The button takes the same names as the other widgets: `width` and `height`
|
|
783
831
|
for its size, `fontSize` (pixels) and `labelFillStyle` for its text,
|
|
@@ -1024,7 +1072,8 @@ from art: the track and fill as nine-slices along its length, the thumb at its
|
|
|
1024
1072
|
own size.
|
|
1025
1073
|
|
|
1026
1074
|
Put work that should not run 60 times a second, such as saving or playing a
|
|
1027
|
-
test sound, in `onChangeEnd
|
|
1075
|
+
test sound, in `onChangeEnd`, which runs once on release and after each wheel
|
|
1076
|
+
or key step.
|
|
1028
1077
|
|
|
1029
1078
|
```js
|
|
1030
1079
|
// whole numbers: a step of 1 shows "7", not "7.00"
|
|
@@ -1103,6 +1152,47 @@ Fullscreen does not resize a fixed-resolution game: with
|
|
|
1103
1152
|
unchanged and only the canvas scales, so a HUD built from
|
|
1104
1153
|
`renderer.width`/`height` needs no repositioning.
|
|
1105
1154
|
|
|
1155
|
+
### Dragging: `isDraggable`, or `Draggable` and `DropTarget`
|
|
1156
|
+
|
|
1157
|
+
Any UI element follows the pointer while held once `isDraggable` is set:
|
|
1158
|
+
`onClick` is the pick-up, `onMove(event)` runs after each move with `pos`
|
|
1159
|
+
already following, and `onRelease` is the drop. It works by touch as by
|
|
1160
|
+
mouse, on a floating element as on one in the world. (`UIPanel` has its own
|
|
1161
|
+
`draggable` setting, above.)
|
|
1162
|
+
|
|
1163
|
+
```js
|
|
1164
|
+
class Token extends UISpriteElement {
|
|
1165
|
+
constructor(x, y) {
|
|
1166
|
+
super(x, y, { image: atlas, region: "token" });
|
|
1167
|
+
this.isDraggable = true;
|
|
1168
|
+
}
|
|
1169
|
+
onRelease() {
|
|
1170
|
+
this.pos.x = Math.round(this.pos.x / 32) * 32; // snap to the grid
|
|
1171
|
+
this.pos.y = Math.round(this.pos.y / 32) * 32;
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
When something else has to notice the drop, `Draggable` and `DropTarget` are
|
|
1178
|
+
the pair. Both are plain `Renderable`s, in the world unless you make them
|
|
1179
|
+
`floating`, that draw nothing until you give them a `draw()`. A `Draggable`
|
|
1180
|
+
follows the pointer while held (`dragStart(e)` / `dragEnd(e)` to override,
|
|
1181
|
+
calling `super`), and when it is let go every `DropTarget` its bounds overlap
|
|
1182
|
+
gets `drop(draggable)`; after `setCheckMethod(target.CHECKMETHOD_CONTAINS)`
|
|
1183
|
+
only one it lies wholly inside does.
|
|
1184
|
+
|
|
1185
|
+
```js
|
|
1186
|
+
class Slot extends DropTarget {
|
|
1187
|
+
drop(card) {
|
|
1188
|
+
card.pos.set(this.pos.x, this.pos.y, card.pos.z); // settle it in
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
The drop is checked on the draggable's own pointer-up (`event.DRAGEND` comes
|
|
1194
|
+
from it), so the release has to land on the draggable itself.
|
|
1195
|
+
|
|
1106
1196
|
### `z` is container-local
|
|
1107
1197
|
|
|
1108
1198
|
`addChild(child, z)` writes a depth that means something **only among that
|
|
@@ -1249,14 +1339,19 @@ City and Instanced Forest examples park a floating sky at `-10000` or `100000`.
|
|
|
1249
1339
|
| the arrow keys or the pad do nothing in a menu | no widget has the focus: nothing listens until one does | call `firstWidget.focus()` when the menu opens |
|
|
1250
1340
|
| the arrow keys stop moving the player after a menu | a widget still has the focus | `UIBaseElement.focusOwner?.blur()`, or remove the menu: a focused widget leaving the scene gives the keys back |
|
|
1251
1341
|
| a `bindKey: ENTER` button does not fire while another widget is focused | Enter and Space go to the focused widget, ring shown or not, so one press never clicks both | focus that button, `blur()` the focused one, or bind another key |
|
|
1342
|
+
| a tooltip or highlight shown in `onOver` stays after its widget is removed (before 20.14) | the pointer's leave never reaches a removed widget | update: a widget removed while hovered now gets `onOut()`, with no event |
|
|
1343
|
+
| an `onOut` sound or tween plays when a menu closes or the scene changes (since 20.14) | a widget removed while hovered gets `onOut()` | keep pointer-only effects out of `onOut`, or skip them when its `event` is `undefined` |
|
|
1252
1344
|
| a widget removed while held gets `onCancel()` and no `onRelease()` | the pointer-up never reaches a removed widget, so the press is called off (and `hover` cleared), leaving it at rest when added back | stop what `onClick()` started in `onCancel()` as well as in `onRelease()` |
|
|
1253
1345
|
| a `ProgressBar` fill runs past its track after `max` is lowered (before 20.13) | `min` and `max` did not re-clamp the value | update: they re-clamp it now (and call `onChange` if it moved); `ratio` stays within 0..1 |
|
|
1254
1346
|
| a skinned panel's shadow has square corners | the shadow follows `radius`, and a skin does not set it | set `radius` to the art's corner size |
|
|
1255
1347
|
| a wrapped label lost its `\n` line breaks, or starts with a blank line (before 20.13) | word wrap joined the lines with spaces, and closed an empty line before an over-wide first word | update: each line is now wrapped on its own and an over-wide word starts the first line |
|
|
1256
1348
|
| the second line of a multi-line `"bottom"` or `"middle"` `Text` is drawn below where you put it, or outside its bounds (before 20.13) | `Text` placed only the first line by its baseline | update: the whole block is placed by the baseline, as `BitmapText` does |
|
|
1257
|
-
| `setText("1,000")` leaves a label showing `["1", "000"]` on two lines, or the other way round (before 20.13) | the change test compared `toString()`, and an array's joins with commas
|
|
1258
|
-
| a centred or right-aligned label jumps sideways, or is clipped, after `label.measureText("…")` (before 20.13) | measuring another string overwrote the label's own metrics until its next `setText()
|
|
1349
|
+
| `setText("1,000")` leaves a label showing `["1", "000"]` on two lines, or the other way round (before 20.13) | the change test compared `toString()`, and an array's joins with commas | update |
|
|
1350
|
+
| a centred or right-aligned label jumps sideways, or is clipped, after `label.measureText("…")` (before 20.13) | measuring another string overwrote the label's own metrics until its next `setText()` | update, or measure on a label that is not displayed |
|
|
1259
1351
|
| `new UITextButton` with a font name draws in a plain font | the name is not a loaded bitmap font, so it is drawn as a CSS font | load the bitmap font (image and `.fnt`) under that name, or load the web font |
|
|
1352
|
+
| `UI skin: no region named "…" in the atlas` thrown where a widget is made | every region a `skin` names is looked up when the widget is built | fix the name, or re-export the atlas with that image |
|
|
1353
|
+
| a typewriter reveal on a centred `Text` slides sideways as it types | a `Text` aligns only the part shown so far | left-align it, or reveal a `BitmapText`, which keeps each glyph in its final place |
|
|
1354
|
+
| a `glyphEffect` decay or intro plays the first time and never again | `ctx.time` runs while any effect is set and never resets, so a later effect starts late | note `ctx.time` on the effect's first call and measure from that |
|
|
1260
1355
|
|
|
1261
1356
|
## Related skills
|
|
1262
1357
|
|