melonjs 20.7.0 → 20.9.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 +7 -3
- package/build/application/application.d.ts +66 -8
- package/build/application/application.d.ts.map +1 -1
- package/build/application/defaultApplicationSettings.d.ts +6 -0
- package/build/application/defaultApplicationSettings.d.ts.map +1 -1
- package/build/application/header.d.ts.map +1 -1
- package/build/application/resize.d.ts +25 -0
- package/build/application/resize.d.ts.map +1 -1
- package/build/application/scaleMethods.d.ts +13 -3
- package/build/application/scaleMethods.d.ts.map +1 -1
- package/build/application/settings.d.ts +144 -5
- package/build/application/settings.d.ts.map +1 -1
- package/build/audio/audio.d.ts +29 -5
- package/build/audio/audio.d.ts.map +1 -1
- package/build/audio/autopause.d.ts +36 -0
- package/build/audio/autopause.d.ts.map +1 -0
- package/build/audio/backend/engine.d.ts +10 -1
- package/build/audio/backend/engine.d.ts.map +1 -1
- package/build/audio/backend/sound.d.ts +0 -1
- package/build/audio/backend/sound.d.ts.map +1 -1
- package/build/audio/backend/spatial.d.ts.map +1 -1
- package/build/audio/context.d.ts +35 -0
- package/build/audio/context.d.ts.map +1 -0
- package/build/audio/playback.d.ts.map +1 -1
- package/build/audio/procedural.d.ts.map +1 -1
- package/build/audio/spatial.d.ts +87 -0
- package/build/audio/spatial.d.ts.map +1 -0
- package/build/audio/state.d.ts +1 -0
- package/build/audio/state.d.ts.map +1 -1
- package/build/audio/types.d.ts +46 -6
- package/build/audio/types.d.ts.map +1 -1
- package/build/camera/camera2d.d.ts.map +1 -1
- package/build/camera/camera3d.d.ts +95 -8
- package/build/camera/camera3d.d.ts.map +1 -1
- package/build/camera/effects/fade_effect.d.ts.map +1 -1
- package/build/camera/effects/mask_effect.d.ts.map +1 -1
- package/build/camera/effects/shake_effect.d.ts.map +1 -1
- package/build/geometries/box3d.d.ts +25 -7
- package/build/geometries/box3d.d.ts.map +1 -1
- package/build/geometries/ellipse.d.ts +15 -1
- package/build/geometries/ellipse.d.ts.map +1 -1
- package/build/geometries/line.d.ts +1 -1
- package/build/geometries/line.d.ts.map +1 -1
- package/build/geometries/point.d.ts +1 -1
- package/build/geometries/point.d.ts.map +1 -1
- package/build/geometries/polygon.d.ts +15 -1
- package/build/geometries/polygon.d.ts.map +1 -1
- package/build/geometries/rectangle.d.ts +1 -1
- package/build/geometries/rectangle.d.ts.map +1 -1
- package/build/geometries/roundrect.d.ts +1 -1
- package/build/geometries/roundrect.d.ts.map +1 -1
- package/build/geometries/sphere.d.ts +36 -7
- package/build/geometries/sphere.d.ts.map +1 -1
- package/build/index.d.ts +16 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +38172 -33633
- package/build/index.js.map +4 -4
- package/build/input/gamepad.d.ts +129 -3
- package/build/input/gamepad.d.ts.map +1 -1
- package/build/input/pointerevent.d.ts +8 -0
- package/build/input/pointerevent.d.ts.map +1 -1
- package/build/level/gltf/GLTFModel.d.ts +20 -33
- package/build/level/gltf/GLTFModel.d.ts.map +1 -1
- package/build/level/gltf/GLTFScene.d.ts +40 -1
- package/build/level/gltf/GLTFScene.d.ts.map +1 -1
- package/build/level/level.d.ts +35 -0
- package/build/level/level.d.ts.map +1 -1
- package/build/level/tiled/TMXLayer.d.ts +5 -2
- package/build/level/tiled/TMXLayer.d.ts.map +1 -1
- package/build/level/tiled/TMXObject.d.ts +0 -1
- package/build/level/tiled/TMXObjectFactory.d.ts +3 -2
- package/build/level/tiled/TMXObjectFactory.d.ts.map +1 -1
- package/build/level/tiled/TMXTile.d.ts +2 -1
- package/build/level/tiled/TMXTile.d.ts.map +1 -1
- package/build/level/tiled/TMXTileMap.d.ts +7 -4
- package/build/level/tiled/TMXTileMap.d.ts.map +1 -1
- package/build/level/tiled/TMXTileset.d.ts +1 -1
- package/build/level/tiled/TMXTileset.d.ts.map +1 -1
- package/build/level/tiled/TMXTilesetGroup.d.ts +5 -0
- package/build/level/tiled/TMXTilesetGroup.d.ts.map +1 -1
- package/build/level/tiled/factories/shape.d.ts +0 -1
- package/build/level/tiled/renderer/TMXHexagonalRenderer.d.ts +6 -5
- package/build/level/tiled/renderer/TMXHexagonalRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXIsometricRenderer.d.ts +5 -0
- package/build/level/tiled/renderer/TMXIsometricRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts +5 -7
- package/build/level/tiled/renderer/TMXObliqueRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXOrthogonalRenderer.d.ts +5 -0
- package/build/level/tiled/renderer/TMXOrthogonalRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/TMXRenderer.d.ts +19 -4
- package/build/level/tiled/renderer/TMXRenderer.d.ts.map +1 -1
- package/build/level/tiled/renderer/autodetect.d.ts +0 -4
- package/build/level/tiled/renderer/autodetect.d.ts.map +1 -1
- package/build/loader/cache.d.ts +220 -0
- package/build/loader/cache.d.ts.map +1 -1
- package/build/loader/loader.d.ts +20 -340
- package/build/loader/loader.d.ts.map +1 -1
- package/build/loader/loadingscreen.d.ts +1 -2
- package/build/loader/loadingscreen.d.ts.map +1 -1
- package/build/loader/parsers/gltf.d.ts +115 -0
- package/build/loader/parsers/gltf.d.ts.map +1 -1
- package/build/loader/parsers/shader.d.ts +0 -2
- package/build/math/color.d.ts +28 -5
- package/build/math/color.d.ts.map +1 -1
- package/build/math/matrix2d.d.ts +1 -1
- package/build/math/matrix2d.d.ts.map +1 -1
- package/build/math/matrix3d.d.ts +1 -1
- package/build/math/matrix3d.d.ts.map +1 -1
- package/build/math/observableVector2d.d.ts +14 -2
- package/build/math/observableVector2d.d.ts.map +1 -1
- package/build/math/observableVector3d.d.ts +15 -1
- package/build/math/observableVector3d.d.ts.map +1 -1
- package/build/math/vector2d.d.ts +31 -1
- package/build/math/vector2d.d.ts.map +1 -1
- package/build/math/vector3d.d.ts +38 -1
- package/build/math/vector3d.d.ts.map +1 -1
- package/build/math/vertex.d.ts.map +1 -1
- package/build/particles/emitter.d.ts.map +1 -1
- package/build/particles/particle.d.ts +29 -2
- package/build/particles/particle.d.ts.map +1 -1
- package/build/particles/settings.d.ts +104 -0
- package/build/particles/settings.d.ts.map +1 -1
- package/build/physics/adapter.d.ts +9 -1
- package/build/physics/adapter.d.ts.map +1 -1
- package/build/physics/bounds.d.ts +1 -1
- package/build/physics/bounds.d.ts.map +1 -1
- package/build/physics/broadphase/octree.d.ts +24 -0
- package/build/physics/broadphase/octree.d.ts.map +1 -1
- package/build/physics/broadphase/quadtree.d.ts +31 -0
- package/build/physics/broadphase/quadtree.d.ts.map +1 -1
- package/build/physics/builtin/body.d.ts +17 -2
- package/build/physics/builtin/body.d.ts.map +1 -1
- package/build/physics/builtin/builtin-adapter.d.ts.map +1 -1
- package/build/physics/builtin/detector.d.ts +0 -1
- package/build/physics/builtin/detector.d.ts.map +1 -1
- package/build/physics/builtin/sat.d.ts +0 -7
- package/build/physics/builtin/sat3d.d.ts +46 -0
- package/build/physics/builtin/sat3d.d.ts.map +1 -1
- package/build/physics/response.d.ts +45 -62
- package/build/physics/response.d.ts.map +1 -1
- package/build/pool.d.ts +4 -0
- package/build/pool.d.ts.map +1 -1
- package/build/renderable/collectable.d.ts +6 -1
- package/build/renderable/collectable.d.ts.map +1 -1
- package/build/renderable/colorlayer.d.ts +17 -4
- package/build/renderable/colorlayer.d.ts.map +1 -1
- package/build/renderable/container.d.ts +23 -17
- package/build/renderable/container.d.ts.map +1 -1
- package/build/renderable/entity/entity.d.ts +12 -16
- package/build/renderable/entity/entity.d.ts.map +1 -1
- package/build/renderable/frameAnimation.d.ts +1 -1
- package/build/renderable/groundshadow.d.ts +1 -0
- package/build/renderable/groundshadow.d.ts.map +1 -1
- package/build/renderable/imagelayer.d.ts +12 -5
- package/build/renderable/imagelayer.d.ts.map +1 -1
- package/build/renderable/instanced_mesh.d.ts +56 -7
- package/build/renderable/instanced_mesh.d.ts.map +1 -1
- package/build/renderable/mesh.d.ts +369 -4
- package/build/renderable/mesh.d.ts.map +1 -1
- package/build/renderable/nineslicesprite.d.ts +3 -13
- package/build/renderable/nineslicesprite.d.ts.map +1 -1
- package/build/renderable/renderable.d.ts +129 -28
- package/build/renderable/renderable.d.ts.map +1 -1
- package/build/renderable/sprite.d.ts +7 -20
- package/build/renderable/sprite.d.ts.map +1 -1
- package/build/renderable/sprite3d.d.ts +31 -16
- package/build/renderable/sprite3d.d.ts.map +1 -1
- package/build/renderable/text/bitmaptext.d.ts +76 -5
- package/build/renderable/text/bitmaptext.d.ts.map +1 -1
- package/build/renderable/text/bitmaptextdata.d.ts +1 -5
- package/build/renderable/text/bitmaptextdata.d.ts.map +1 -1
- package/build/renderable/text/glypheffect.d.ts +44 -0
- package/build/renderable/text/glypheffect.d.ts.map +1 -0
- package/build/renderable/text/text.d.ts +22 -3
- package/build/renderable/text/text.d.ts.map +1 -1
- package/build/renderable/text/textmetrics.d.ts +2 -0
- package/build/renderable/text/textmetrics.d.ts.map +1 -1
- package/build/renderable/trail.d.ts +0 -1
- package/build/renderable/trail.d.ts.map +1 -1
- package/build/renderable/trail3d.d.ts +174 -0
- package/build/renderable/trail3d.d.ts.map +1 -0
- package/build/renderable/trigger.d.ts +28 -5
- package/build/renderable/trigger.d.ts.map +1 -1
- package/build/renderable/ui/panelpaint.d.ts +5 -0
- package/build/renderable/ui/panelpaint.d.ts.map +1 -0
- package/build/renderable/ui/progressbar.d.ts +192 -0
- package/build/renderable/ui/progressbar.d.ts.map +1 -0
- package/build/renderable/ui/uibaseelement.d.ts +48 -3
- package/build/renderable/ui/uibaseelement.d.ts.map +1 -1
- package/build/renderable/ui/uipanel.d.ts +245 -0
- package/build/renderable/ui/uipanel.d.ts.map +1 -0
- package/build/renderable/ui/uispriteelement.d.ts +19 -3
- package/build/renderable/ui/uispriteelement.d.ts.map +1 -1
- package/build/renderable/ui/uitextbutton.d.ts +30 -1
- package/build/renderable/ui/uitextbutton.d.ts.map +1 -1
- package/build/state/state.d.ts.map +1 -1
- package/build/system/bootstrap.d.ts.map +1 -1
- package/build/system/legacy_pool.d.ts +24 -4
- package/build/system/legacy_pool.d.ts.map +1 -1
- package/build/system/pool.d.ts +15 -8
- package/build/system/pool.d.ts.map +1 -1
- package/build/tweens/tween.d.ts +50 -3
- package/build/tweens/tween.d.ts.map +1 -1
- package/build/video/canvas/canvas_renderer.d.ts +34 -23
- package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
- package/build/video/effects/blendEffect.d.ts +0 -1
- package/build/video/effects/bloom.d.ts +72 -0
- package/build/video/effects/bloom.d.ts.map +1 -0
- package/build/video/effects/blur.d.ts +3 -2
- package/build/video/effects/blur.d.ts.map +1 -1
- package/build/video/effects/chromaticAberration.d.ts +3 -2
- package/build/video/effects/chromaticAberration.d.ts.map +1 -1
- package/build/video/effects/colorMatrix.d.ts +3 -2
- package/build/video/effects/colorMatrix.d.ts.map +1 -1
- package/build/video/effects/desaturate.d.ts +10 -2
- package/build/video/effects/desaturate.d.ts.map +1 -1
- package/build/video/effects/dissolve.d.ts +3 -2
- package/build/video/effects/dissolve.d.ts.map +1 -1
- package/build/video/effects/dropShadow.d.ts +3 -2
- package/build/video/effects/dropShadow.d.ts.map +1 -1
- package/build/video/effects/flash.d.ts +3 -2
- package/build/video/effects/flash.d.ts.map +1 -1
- package/build/video/effects/glow.d.ts +3 -2
- package/build/video/effects/glow.d.ts.map +1 -1
- package/build/video/effects/hologram.d.ts +3 -2
- package/build/video/effects/hologram.d.ts.map +1 -1
- package/build/video/effects/invert.d.ts +10 -2
- package/build/video/effects/invert.d.ts.map +1 -1
- package/build/video/effects/outline.d.ts +3 -2
- package/build/video/effects/outline.d.ts.map +1 -1
- package/build/video/effects/pixelate.d.ts +3 -2
- package/build/video/effects/pixelate.d.ts.map +1 -1
- package/build/video/effects/radialGradient.d.ts +8 -3
- package/build/video/effects/radialGradient.d.ts.map +1 -1
- package/build/video/effects/scanline.d.ts +3 -2
- package/build/video/effects/scanline.d.ts.map +1 -1
- package/build/video/effects/sepia.d.ts +10 -2
- package/build/video/effects/sepia.d.ts.map +1 -1
- package/build/video/effects/shadereffect.d.ts +10 -4
- package/build/video/effects/shadereffect.d.ts.map +1 -1
- package/build/video/effects/shine.d.ts +3 -2
- package/build/video/effects/shine.d.ts.map +1 -1
- package/build/video/effects/tintPulse.d.ts +3 -7
- package/build/video/effects/tintPulse.d.ts.map +1 -1
- package/build/video/effects/tonemap.d.ts +121 -0
- package/build/video/effects/tonemap.d.ts.map +1 -0
- package/build/video/effects/vignette.d.ts +3 -2
- package/build/video/effects/vignette.d.ts.map +1 -1
- package/build/video/effects/wave.d.ts +3 -7
- package/build/video/effects/wave.d.ts.map +1 -1
- package/build/video/gpu/batcher.d.ts +8 -2
- package/build/video/gpu/batcher.d.ts.map +1 -1
- package/build/video/gpu/vertexformat.d.ts +26 -0
- package/build/video/gpu/vertexformat.d.ts.map +1 -1
- package/build/video/gradient.d.ts +1 -1
- package/build/video/gradient.d.ts.map +1 -1
- package/build/video/renderer.d.ts +111 -7
- package/build/video/renderer.d.ts.map +1 -1
- package/build/video/renderstate.d.ts +2 -0
- package/build/video/renderstate.d.ts.map +1 -1
- package/build/video/rendertarget/canvasrendertarget.d.ts +3 -4
- package/build/video/rendertarget/canvasrendertarget.d.ts.map +1 -1
- package/build/video/rendertarget/render_target_pool.d.ts +0 -1
- package/build/video/rendertarget/rendertarget.d.ts +12 -5
- package/build/video/rendertarget/rendertarget.d.ts.map +1 -1
- package/build/video/rendertarget/webglrendertarget.d.ts +0 -1
- package/build/video/rendertarget/webglrendertarget.d.ts.map +1 -1
- package/build/video/rendertarget/webgpurendertarget.d.ts +24 -14
- package/build/video/rendertarget/webgpurendertarget.d.ts.map +1 -1
- package/build/video/texture/atlas.d.ts +2 -1
- package/build/video/texture/atlas.d.ts.map +1 -1
- package/build/video/texture/cache.d.ts +1 -3
- package/build/video/texture/frametexture.d.ts +0 -1
- package/build/video/texture/frametexture.d.ts.map +1 -1
- package/build/video/texture/noise_texture2d.d.ts +1 -0
- package/build/video/texture/noise_texture2d.d.ts.map +1 -1
- package/build/video/texture/texture2d.d.ts +6 -0
- package/build/video/texture/texture2d.d.ts.map +1 -1
- package/build/video/utils/autodetect.d.ts +0 -2
- package/build/video/webgl/batchers/batcher.d.ts +0 -9
- package/build/video/webgl/batchers/batcher.d.ts.map +1 -1
- package/build/video/webgl/batchers/lit_quad_batcher.d.ts +2 -0
- package/build/video/webgl/batchers/lit_quad_batcher.d.ts.map +1 -1
- package/build/video/webgl/batchers/material_batcher.d.ts +4 -2
- package/build/video/webgl/batchers/material_batcher.d.ts.map +1 -1
- package/build/video/webgl/batchers/mesh_batcher.d.ts +0 -3
- package/build/video/webgl/batchers/mesh_batcher.d.ts.map +1 -1
- package/build/video/webgl/batchers/quad_batcher.d.ts +4 -0
- package/build/video/webgl/batchers/quad_batcher.d.ts.map +1 -1
- package/build/video/webgl/buffer/index.d.ts +0 -1
- package/build/video/webgl/buffer/retained_geometry.d.ts +0 -1
- package/build/video/webgl/glshader.d.ts +5 -3
- package/build/video/webgl/glshader.d.ts.map +1 -1
- package/build/video/webgl/renderers/tmxlayer/orthogonal.d.ts +0 -4
- package/build/video/webgl/texture/store.d.ts +0 -1
- package/build/video/webgl/webgl_renderer.d.ts +63 -24
- package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
- package/build/video/webgpu/batchers/mesh_batcher.d.ts +0 -3
- package/build/video/webgpu/batchers/mesh_batcher.d.ts.map +1 -1
- package/build/video/webgpu/batchers/quad_batcher.d.ts +0 -2
- package/build/video/webgpu/batchers/quad_batcher.d.ts.map +1 -1
- package/build/video/webgpu/batchers/webgpu_batcher.d.ts +0 -2
- package/build/video/webgpu/batchers/webgpu_batcher.d.ts.map +1 -1
- package/build/video/webgpu/pipeline/cache.d.ts.map +1 -1
- package/build/video/webgpu/renderers/tmxlayer/orthogonal.d.ts +0 -2
- package/build/video/webgpu/texture/frametexture.d.ts +0 -2
- package/build/video/webgpu/texture/frametexture.d.ts.map +1 -1
- package/build/video/webgpu/texture/store.d.ts +0 -1
- package/build/video/webgpu/webgpu_renderer.d.ts +7 -75
- package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
- package/package.json +2 -2
- package/skills/AGENTS.md +1 -1
- package/skills/melonjs/SKILL.md +2 -0
- package/skills/melonjs-3d/SKILL.md +454 -22
- package/skills/melonjs-3d-assets/SKILL.md +111 -10
- package/skills/melonjs-audio/SKILL.md +229 -8
- package/skills/melonjs-camera-and-drawing/SKILL.md +127 -1
- package/skills/melonjs-display-and-scaling/SKILL.md +273 -0
- package/skills/melonjs-effects-and-shaders/SKILL.md +341 -29
- package/skills/melonjs-events/SKILL.md +8 -6
- package/skills/melonjs-input/SKILL.md +147 -7
- package/skills/melonjs-math/SKILL.md +313 -0
- package/skills/melonjs-particles-and-trails/SKILL.md +189 -13
- package/skills/melonjs-performance/SKILL.md +131 -23
- package/skills/melonjs-physics/SKILL.md +103 -28
- package/skills/melonjs-renderables/SKILL.md +8 -2
- package/skills/melonjs-scenes-and-state/SKILL.md +134 -3
- package/skills/melonjs-sprites-and-animation/SKILL.md +9 -4
- package/skills/melonjs-tilemaps/SKILL.md +40 -12
- package/skills/melonjs-ui-and-text/SKILL.md +546 -7
- package/build/level/gltf/srgb.d.ts +0 -20
- package/build/level/gltf/srgb.d.ts.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: melonjs-ui-and-text
|
|
3
|
-
description: "Use this skill for HUDs, buttons, menus, dialogue panels and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, Draggable and DropTarget, the floating screen-space container pattern, Text and BitmapText, web font loading, and NineSliceSprite panels. Triggers on: UI, HUD, button, UIBaseElement, UISpriteElement, UITextButton, Draggable, DropTarget, menu, dialogue, Text, BitmapText, font, fontface, wordWrapWidth, NineSliceSprite, score display, floating
|
|
3
|
+
description: "Use this skill for HUDs, buttons, menus, dialogue panels, progress bars and on-screen text in melonJS. Covers UIBaseElement/UISpriteElement/UITextButton, ProgressBar, UIPanel, 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, UIBaseElement, UISpriteElement, UITextButton, ProgressBar, progress bar, health bar, gauge, Draggable, DropTarget, menu, dialogue, overlapping panels, moveToTop, onOver, onClick, bindKey, keyboard shortcut, button keyboard, Tween, easing, animate a label, wavy text, per-glyph effect, glyphEffect, shake text, rainbow text, Text, BitmapText, fillStyle, fillGradient, gradient text, tint, font, fontface, wordWrapWidth, NineSliceSprite, score display, floating., fullscreen, full screen, requestFullscreen, exitFullscreen, isFullscreen, fullscreen button, fullscreen option"
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -51,8 +51,24 @@ deliberate fade across a two-line title wants.
|
|
|
51
51
|
|
|
52
52
|
The ramp colours the **fill only** — `Text` strokes in a separate pass, so
|
|
53
53
|
an outline keeps its own colour without any luminance trickery — and it works on
|
|
54
|
-
Canvas2D, which a post effect does not.
|
|
55
|
-
|
|
54
|
+
Canvas2D, which a post effect does not.
|
|
55
|
+
|
|
56
|
+
### The gradient does not live in `fillStyle`
|
|
57
|
+
|
|
58
|
+
`fillStyle` ACCEPTS a `Gradient`; it never HOLDS one. The constructor routes it
|
|
59
|
+
to `fillGradient` and leaves `fillStyle` as the pooled `Color` it always is,
|
|
60
|
+
which is what keeps `fillStyle.alpha` gating the fill and keeps the colour
|
|
61
|
+
owned by the pool.
|
|
62
|
+
|
|
63
|
+
So changing the ramp later means assigning the field it actually landed in:
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
label.fillGradient = ramp; // ✓
|
|
67
|
+
label.fillStyle = ramp; // ✗ TS2740: Gradient is not a Color
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The ramp is authored for ONE line height, so a label that changes size needs a
|
|
71
|
+
new one built at the new size; there is nothing that rescales it for you.
|
|
56
72
|
|
|
57
73
|
## BitmapText: `size` is a RATIO, not pixels
|
|
58
74
|
|
|
@@ -96,6 +112,163 @@ loader.preload([
|
|
|
96
112
|
Reach for it over `Text` when the text is mostly static, has to stay crisp at
|
|
97
113
|
integer scales, or wants recolouring without a re-bake.
|
|
98
114
|
|
|
115
|
+
### Do not build a throwaway label to measure a string
|
|
116
|
+
|
|
117
|
+
A `Text` owns a canvas bake and a GPU texture, and only `destroy()` frees
|
|
118
|
+
them — which is `@internal` and absent from the published types, so a game
|
|
119
|
+
cannot free a label it owns outside a container. A label built purely to
|
|
120
|
+
measure something therefore strands both, and if it is built in a stage's
|
|
121
|
+
`onResetEvent` it strands another on every entry to that state.
|
|
122
|
+
|
|
123
|
+
`measureText(text?)` measures any string on a label that already exists,
|
|
124
|
+
including one it is not currently holding:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
const widest = hudScore.measureText("00:00").width;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Advance widths scale linearly with the point size for one family, so measuring
|
|
131
|
+
on an existing label and scaling the result is exact. For labels you genuinely
|
|
132
|
+
spawn in bulk, `getPool("text")` recycles the bake.
|
|
133
|
+
|
|
134
|
+
### `fillStyle` means two different things
|
|
135
|
+
|
|
136
|
+
The name is shared and the behaviour is not, which is the trap when moving a
|
|
137
|
+
label from one class to the other:
|
|
138
|
+
|
|
139
|
+
| | `Text` | `BitmapText` |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| what `fillStyle` holds | a real `Color`, the fill | `Renderable#tint`, under another name |
|
|
142
|
+
| white | white glyphs | the ABSENCE of a tint |
|
|
143
|
+
| gradient | yes, via `fillGradient` | no: a tint is one colour over a page image |
|
|
144
|
+
| recolour it later | `label.fillStyle.parseCSS("#ff4040")` — the field is a `Color` with no setter, and ASSIGNING a string replaces it, after which the glyphs stop filling entirely and nothing is logged | `label.fillStyle = "#ff4040"` — a real setter that parses the string |
|
|
145
|
+
| stroke | `strokeStyle` + `lineWidth` | none |
|
|
146
|
+
| `size` | pixels | a RATIO of the authored size |
|
|
147
|
+
|
|
148
|
+
### Per-glyph wave, shake and colour: `glyphEffect`
|
|
149
|
+
|
|
150
|
+
Animating individual letters does **not** mean one renderable per character.
|
|
151
|
+
`BitmapText#glyphEffect` offsets and tints each glyph inside the batch the
|
|
152
|
+
label already draws, so an animated 100-character line stays one draw call and
|
|
153
|
+
costs no extra objects:
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
label.glyphEffect = (out, ctx) => {
|
|
157
|
+
// phase from the glyph's POSITION, not its index — see below
|
|
158
|
+
out.offsetY = Math.sin(ctx.time * 0.005 + ctx.x * 0.02) * 6; // wave
|
|
159
|
+
out.tint.setColor(255, 128, 128); // per glyph
|
|
160
|
+
};
|
|
161
|
+
label.glyphEffect = null; // back to the plain path
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`out` and `ctx` are **reused**: read `ctx` during the call and write `out`, but
|
|
165
|
+
never keep either. `out.offsetX` / `offsetY` start at zero and `out.tint` at
|
|
166
|
+
opaque white on every glyph, so an effect that only touches some glyphs leaves
|
|
167
|
+
the rest alone. `ctx` carries `index` (across lines, line breaks excluded),
|
|
168
|
+
`char`, `code`, `x`, `y` and `time`.
|
|
169
|
+
|
|
170
|
+
Four things that catch people:
|
|
171
|
+
|
|
172
|
+
- **`time` advances in `update`, not in `draw`.** A label drawn through two
|
|
173
|
+
cameras animates once, not twice. It is the milliseconds ACCUMULATED across
|
|
174
|
+
updates while an effect was set, and nothing resets it, so swapping the
|
|
175
|
+
callback continues the same clock rather than starting a new one.
|
|
176
|
+
- **Effects move pixels, not layout.** Metrics, wrapping, alignment,
|
|
177
|
+
`visibleCharacters` and the bounds all ignore the offsets, so the pen advance
|
|
178
|
+
and kerning are exactly as without one. The flip side is that **offsets do
|
|
179
|
+
not extend the culling bounds**: a big wave near the screen edge can clip, so
|
|
180
|
+
keep the measured text in view.
|
|
181
|
+
- **Canvas pays per distinct colour.** WebGL and WebGPU carry the tint in the
|
|
182
|
+
per-vertex colour, so batching survives. The Canvas renderer instead caches a
|
|
183
|
+
tinted copy of the whole font page per colour, and that cache is unbounded
|
|
184
|
+
for the renderer's life, so a colour driven by `ctx.time` allocates a
|
|
185
|
+
page-sized canvas every frame there. On Canvas, keep the palette finite or
|
|
186
|
+
animate only the offsets.
|
|
187
|
+
- **`tint` is multiplicative**, like `fillStyle` above: white leaves the glyph
|
|
188
|
+
alone, and `out.tint` multiplies whatever the label's own `fillStyle` is.
|
|
189
|
+
|
|
190
|
+
`Text` has no equivalent, since it rasterises the whole string into one texture.
|
|
191
|
+
|
|
192
|
+
### Making it read as motion
|
|
193
|
+
|
|
194
|
+
Three things decide whether a wave looks alive or mechanical, and none of them
|
|
195
|
+
is the amplitude.
|
|
196
|
+
|
|
197
|
+
- **Take the phase from `ctx.x`, not `ctx.index`.** This is the big one.
|
|
198
|
+
Stepping per glyph advances the wave as far across a narrow `I` as across a
|
|
199
|
+
wide `M`, so the wavelength stretches and squashes with whatever the line
|
|
200
|
+
happens to spell, and the eye reads the unevenness as a mechanism. `ctx.x`
|
|
201
|
+
gives the wave one fixed length in pixels and lets it travel through the
|
|
202
|
+
text at a constant rate, whatever the letters are.
|
|
203
|
+
- **Round the offsets if the frame is upscaled.** They are added to the glyph
|
|
204
|
+
destination unchanged, so a fractional offset in a small design resolution
|
|
205
|
+
that is then magnified with nearest sampling makes the glyph's OWN pixels
|
|
206
|
+
come out uneven — and differently uneven each frame. That is a shimmer, not
|
|
207
|
+
movement. `Math.round` the offset and it steps cleanly, for the same reason
|
|
208
|
+
`subPixel` defaults to false. Whole pixels mean few steps, so the amplitude
|
|
209
|
+
has to be large enough to give you several.
|
|
210
|
+
- **A shake is not a sine.** A sine moves the whole line as one body, which is
|
|
211
|
+
a wave however fast you run it. A shake gives each glyph a direction
|
|
212
|
+
unrelated to its neighbours: pick a random angle per glyph, hold it for a
|
|
213
|
+
tick, interpolate to the next, and scale the whole thing by a decay if it is
|
|
214
|
+
an impact rather than a state.
|
|
215
|
+
|
|
216
|
+
Starting points that look right across sizes, as fractions of the font size:
|
|
217
|
+
an amplitude around an eighth of it, a wavelength around ten times it, and a
|
|
218
|
+
little under 5 radians per second. For a shake, re-target each glyph roughly
|
|
219
|
+
20 to 40 times a second.
|
|
220
|
+
|
|
221
|
+
`ctx.time` starts when the effect is **assigned**, so attach it at the moment
|
|
222
|
+
you want to be t=0 — on the frame the hit lands, not when the label was built.
|
|
223
|
+
A label reused across lives carries the old clock, so a decay attached once
|
|
224
|
+
will already be spent the second time.
|
|
225
|
+
|
|
226
|
+
Both, whole:
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
import { BitmapText } from "melonjs";
|
|
230
|
+
|
|
231
|
+
const title = new BitmapText(app.viewport.width / 2, 60, {
|
|
232
|
+
font: "display",
|
|
233
|
+
textAlign: "center",
|
|
234
|
+
text: "JUNGLE RABBIT",
|
|
235
|
+
});
|
|
236
|
+
title.floating = true;
|
|
237
|
+
app.world.addChild(title);
|
|
238
|
+
|
|
239
|
+
// A wave: four pixels deep, a ~1.3s cycle, and a wavelength of roughly ten
|
|
240
|
+
// times the font size. Phase from ctx.x, offset rounded.
|
|
241
|
+
title.glyphEffect = (out, ctx) => {
|
|
242
|
+
out.offsetY = Math.round(Math.sin(ctx.time * 0.005 + ctx.x * 0.02) * 4);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// A shake: each glyph picks its own direction, holds it for a tick, slides to
|
|
246
|
+
// the next, and the whole thing decays. Deterministic, so the same hit shakes
|
|
247
|
+
// the same way every time.
|
|
248
|
+
const angle = (i, tick) => {
|
|
249
|
+
const h = Math.sin(i * 127.1 + tick * 311.7) * 43758.5453;
|
|
250
|
+
return (h - Math.floor(h)) * Math.PI * 2;
|
|
251
|
+
};
|
|
252
|
+
const impact = (amplitude, durationMs, rate) => (out, ctx) => {
|
|
253
|
+
const left = 1 - ctx.time / durationMs;
|
|
254
|
+
if (left <= 0) {
|
|
255
|
+
return; // settled; `out` is already zeroed
|
|
256
|
+
}
|
|
257
|
+
const amp = amplitude * left * left;
|
|
258
|
+
const tick = (ctx.time / 1000) * rate;
|
|
259
|
+
const held = Math.floor(tick);
|
|
260
|
+
const k = tick - held;
|
|
261
|
+
const a = angle(ctx.index, held);
|
|
262
|
+
const b = angle(ctx.index, held + 1);
|
|
263
|
+
out.offsetX = Math.round((Math.sin(a) + (Math.sin(b) - Math.sin(a)) * k) * amp);
|
|
264
|
+
out.offsetY = Math.round((Math.cos(a) + (Math.cos(b) - Math.cos(a)) * k) * amp);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// assigned at the moment of the hit, which is what makes ctx.time start here
|
|
268
|
+
banner.setText("CAPSIZED!");
|
|
269
|
+
banner.glyphEffect = impact(3, 650, 24);
|
|
270
|
+
```
|
|
271
|
+
|
|
99
272
|
## The HUD pattern
|
|
100
273
|
|
|
101
274
|
A HUD is a `floating` container at a high z, built once and re-added:
|
|
@@ -112,9 +285,10 @@ class HUD extends Container {
|
|
|
112
285
|
app.world.addChild(new HUD(app), 100); // explicit z — not `.z = Infinity`
|
|
113
286
|
```
|
|
114
287
|
|
|
115
|
-
There is no `UIContainer` class. Use `Container
|
|
116
|
-
|
|
117
|
-
`
|
|
288
|
+
There is no `UIContainer` class. Use `Container` for a bare grouping,
|
|
289
|
+
`UIPanel` for anything with a background or a border (see below), or
|
|
290
|
+
`UIBaseElement` when you want the pointer handling and nothing drawn — it is a
|
|
291
|
+
`Container` that already sets `floating = true` and `isKinematic = false`.
|
|
118
292
|
|
|
119
293
|
Three things matter here:
|
|
120
294
|
|
|
@@ -129,6 +303,161 @@ Three things matter here:
|
|
|
129
303
|
real accessor is `depth` (an alias for `pos.z`); `addChild(child, z)` sets it
|
|
130
304
|
for you.
|
|
131
305
|
|
|
306
|
+
### Bars and gauges: `ProgressBar`
|
|
307
|
+
|
|
308
|
+
A health bar, a shield gauge, a cooldown and a loading bar are one object. Set
|
|
309
|
+
`value`; it redraws.
|
|
310
|
+
|
|
311
|
+
```js
|
|
312
|
+
const hp = new ProgressBar(20, 20, {
|
|
313
|
+
width: 200, height: 24,
|
|
314
|
+
min: 0, max: 100, value: 100, // min/max default to 0 and 1
|
|
315
|
+
trackColor: "#0000001a",
|
|
316
|
+
fillColor: "#c0392b",
|
|
317
|
+
borderColor: "black", borderWidth: 2,
|
|
318
|
+
padding: 2, // inset of the fill inside the track
|
|
319
|
+
radius: 6, // 0 is square
|
|
320
|
+
});
|
|
321
|
+
hud.addChild(hp);
|
|
322
|
+
|
|
323
|
+
hp.value -= 15; // clamps; `ratio` reads back 0..1
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
`direction` takes `"left-to-right"` (the default), `"right-to-left"`,
|
|
327
|
+
`"top-to-bottom"` or `"bottom-to-top"`, each growing from its own edge.
|
|
328
|
+
|
|
329
|
+
**The colour follows the value by mutating the `Color` you passed.** This is
|
|
330
|
+
the one non-obvious part, and it is deliberate: every game wants a different
|
|
331
|
+
rule, and most want the colour somewhere else too, next to a shader uniform or
|
|
332
|
+
a glow. The bar re-reads `fillColor` every frame, so it never has to know:
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
const full = new Color().parseCSS("#7fe0ff");
|
|
336
|
+
const empty = new Color().parseCSS("#ff2a1e");
|
|
337
|
+
const mixed = new Color();
|
|
338
|
+
|
|
339
|
+
const shield = new ProgressBar(x, y, {
|
|
340
|
+
width: 190, height: 13,
|
|
341
|
+
trackColor: null, // hollow: the scene shows through
|
|
342
|
+
borderColor: "rgba(122, 190, 235, 0.8)",
|
|
343
|
+
padding: 2,
|
|
344
|
+
fillColor: mixed, // KEPT, not copied
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// each frame
|
|
348
|
+
mixed.copy(empty).lerp(full, hp); // the bar follows, and so can a shader
|
|
349
|
+
shield.value = hp;
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Blinking is the same story: `setOpacity()` already does it, on whatever clock
|
|
353
|
+
the game is already keeping. Neither is built in.
|
|
354
|
+
|
|
355
|
+
**`bindEvent` takes the value from an event instead**, and the subscription
|
|
356
|
+
then lives exactly as long as the bar:
|
|
357
|
+
|
|
358
|
+
```js
|
|
359
|
+
const bar = new ProgressBar(0, y, {
|
|
360
|
+
width: renderer.width, height: 4,
|
|
361
|
+
trackColor: "black", fillColor: "#55aa00",
|
|
362
|
+
bindEvent: event.LOADER_PROGRESS,
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Hold that subscription anywhere else and it outlives the bar, firing into a
|
|
367
|
+
renderable whose `pos` has already been released. The engine's own loading
|
|
368
|
+
screen is built on exactly this.
|
|
369
|
+
|
|
370
|
+
Two more worth knowing:
|
|
371
|
+
|
|
372
|
+
- **The border is four filled rects, not a stroke** (unless the bar is
|
|
373
|
+
rounded). A stroke is centred on the path, so half of it falls outside and a
|
|
374
|
+
bordered bar paints over its neighbour; and `strokeRect` adds corner joins
|
|
375
|
+
only above a line width of 1, so at exactly 1 a corner pixel goes missing.
|
|
376
|
+
- **`trackColor: null` leaves the bar hollow**, which is what a HUD over a busy
|
|
377
|
+
scene usually wants: the border is then the only chrome.
|
|
378
|
+
|
|
379
|
+
### Panels and cards: `UIPanel`
|
|
380
|
+
|
|
381
|
+
A dialog, a menu card, a HUD frame: a rectangle with a fill, an optional
|
|
382
|
+
border and children on top. `UIPanel` is a `UIBaseElement`, so it is a
|
|
383
|
+
container that carries pointer events.
|
|
384
|
+
|
|
385
|
+
```js
|
|
386
|
+
import { UIPanel, Text } from "melonjs";
|
|
387
|
+
|
|
388
|
+
const card = new UIPanel(cx - 200, cy - 120, {
|
|
389
|
+
width: 400, height: 240,
|
|
390
|
+
fillColor: "#0a1526", // null leaves it transparent
|
|
391
|
+
borderColor: "rgba(130, 200, 240, 0.55)", // null for none
|
|
392
|
+
borderWidth: 2,
|
|
393
|
+
radius: 14,
|
|
394
|
+
});
|
|
395
|
+
card.addChild(new Text(200, 24, { text: "PAUSED", textAlign: "center" }));
|
|
396
|
+
app.world.addChild(card, -150); // small depth: see the 3D section below
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**`fillColor`, not `backgroundColor`.** `Container` already has a
|
|
400
|
+
`backgroundColor` and it does something else entirely: it is handed to
|
|
401
|
+
`clearColor` and wipes the whole render target, so a panel setting it repaints
|
|
402
|
+
the screen. The names here match `ProgressBarSettings`.
|
|
403
|
+
|
|
404
|
+
**The border is drawn INSIDE the box.** `width` and `height` are the outer
|
|
405
|
+
size, border included, so a panel never paints past the rectangle you gave it
|
|
406
|
+
and its `getBounds()`, which is what the pointer dispatcher hit-tests, stays
|
|
407
|
+
that rectangle. One thing to know with a `radius`: keep `borderWidth` at 2 or
|
|
408
|
+
more. A rounded border has to be stroked, and a stroke at exactly 1 goes out as
|
|
409
|
+
plain lines, which drops a pixel where each arc meets its straight edge. A
|
|
410
|
+
square border is four fills and is fine at 1.
|
|
411
|
+
|
|
412
|
+
**`blocking` (default `true`)** makes the panel consume clicks and hovers that
|
|
413
|
+
miss its children, which is what a dialog wants — a click on the card, or on
|
|
414
|
+
the dimmed scene behind it, must not reach the game. Children are unaffected:
|
|
415
|
+
the dispatcher asks a child before the container holding it. Set it `false` for
|
|
416
|
+
a frame drawn over a playfield that still has to receive clicks.
|
|
417
|
+
|
|
418
|
+
A full-screen panel with a translucent `fillColor` and `borderColor: null` is
|
|
419
|
+
the veil behind a modal, and it blocks for free.
|
|
420
|
+
|
|
421
|
+
**`bobAmplitude` / `bobPeriod`** give the panel the slow float an idle
|
|
422
|
+
dialogue or pause panel usually has, so a screen waiting for input does not
|
|
423
|
+
look frozen:
|
|
424
|
+
|
|
425
|
+
```js
|
|
426
|
+
card.bobAmplitude = 3; // pixels either side; 2 to 4 is the usual range
|
|
427
|
+
card.bobPeriod = 2500; // ms for a full up-and-down cycle
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Three things to know. **The panel is clickable where it is drawn**: the offset
|
|
431
|
+
goes into `getAbsolutePosition()`, which is what the bounds pipeline reads, so
|
|
432
|
+
the hit area of the panel and of every widget inside it follows the float at
|
|
433
|
+
any depth. `pos` is left alone, so it still reads and writes the resting place.
|
|
434
|
+
It is fed from `update(dt)`, so it stops with the rest of the game on
|
|
435
|
+
`state.pause()` unless the panel sets `updateWhenPaused`, which a pause menu
|
|
436
|
+
does anyway. And do not go below an amplitude of 2: the offset is rounded to whole
|
|
437
|
+
pixels, so an amplitude of 1 has three positions to move through and twitches
|
|
438
|
+
instead of drifting.
|
|
439
|
+
|
|
440
|
+
One consequence worth knowing: `getBounds()` on a bobbing panel answers
|
|
441
|
+
differently each frame, so do not cache it or compare two children's bounds
|
|
442
|
+
while a bob is running.
|
|
443
|
+
|
|
444
|
+
### A pause overlay: `updateWhenPaused` cascades
|
|
445
|
+
|
|
446
|
+
`state.pause()` stops every world child stepping while rendering carries on, so
|
|
447
|
+
the overlay that reads the key to UNPAUSE has to opt out:
|
|
448
|
+
|
|
449
|
+
```js
|
|
450
|
+
const overlay = new UIPanel(0, 0, { width: w, height: h, fillColor: "rgba(4,8,16,0.72)" });
|
|
451
|
+
overlay.updateWhenPaused = true; // the whole subtree, not just this one
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
The flag covers the container's **entire subtree**, so nested labels, buttons
|
|
455
|
+
and the card inside the veil all keep stepping without being flagged one by
|
|
456
|
+
one. That matters for more than their `update`: `inViewport` is computed in the
|
|
457
|
+
same loop that honours the pause, so a skipped child keeps whatever it had —
|
|
458
|
+
`false` for one built while paused — and `Container.draw` then declines to draw
|
|
459
|
+
it, silently. A panel whose labels never appear while paused is this.
|
|
460
|
+
|
|
132
461
|
### Buttons: extend the handlers, do not bind listeners
|
|
133
462
|
|
|
134
463
|
`UISpriteElement` is a `Sprite` that already registers itself for pointer
|
|
@@ -139,7 +468,7 @@ events, so a button is made by overriding methods rather than by wiring
|
|
|
139
468
|
|---|---|---|
|
|
140
469
|
| `onClick(event)` | pressed | `false` to stop the event propagating |
|
|
141
470
|
| `onRelease(event)` | pressed and released | `false` to stop propagating |
|
|
142
|
-
| `onOver(event)` | pointer enters |
|
|
471
|
+
| `onOver(event)` | pointer enters | `false` to stop propagating |
|
|
143
472
|
| `onOut(event)` | pointer leaves | — |
|
|
144
473
|
| `onHold()` | pressed and held | — |
|
|
145
474
|
|
|
@@ -163,6 +492,210 @@ default on a plain `Renderable` — is skipped by the broadphase and receives
|
|
|
163
492
|
nothing. `UISpriteElement` and `UIBaseElement` clear it for you; anything else
|
|
164
493
|
you make clickable has to clear it itself.
|
|
165
494
|
|
|
495
|
+
### Keyboard shortcuts on a button: `bindKey`
|
|
496
|
+
|
|
497
|
+
A `UITextButton` can be activated from the keyboard as well as the pointer:
|
|
498
|
+
|
|
499
|
+
```js
|
|
500
|
+
const resume = new UITextButton(x, y, {
|
|
501
|
+
font: "PressStart2P", text: "RESUME",
|
|
502
|
+
bindKey: input.KEY.ENTER, // a keycode, or an action name you bound
|
|
503
|
+
});
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
It takes either an `input.KEY` keycode or the NAME of an action the game has
|
|
507
|
+
already bound. Neither form touches the global bindings, so a keycode works
|
|
508
|
+
even when nothing has called `input.bindKey` for it.
|
|
509
|
+
|
|
510
|
+
**The handlers fire with no `Pointer`.** This is the one that breaks existing
|
|
511
|
+
code: a button whose `onClick(event)` reads `event.gameX` worked for years
|
|
512
|
+
because only a pointer could ever press it, and the first key press throws.
|
|
513
|
+
Guard the argument, or keep pointer-only work out of the handler:
|
|
514
|
+
|
|
515
|
+
```js
|
|
516
|
+
onClick(event) {
|
|
517
|
+
if (event) { this.ripple(event.gameX, event.gameY); } // pointer only
|
|
518
|
+
this.resumeGame(); // either input
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Three more rules, each with a reason you can feel in a game:
|
|
523
|
+
|
|
524
|
+
- **The first input to press owns the button.** A pointer cannot release a key
|
|
525
|
+
press and a key cannot release a pointer press, so a button cannot be left
|
|
526
|
+
half pressed by using both at once.
|
|
527
|
+
- **Losing focus cancels a held key WITHOUT calling `onRelease()`.** If you
|
|
528
|
+
use the pair as press and depress, firing while held, also stop on
|
|
529
|
+
`event.BLUR` or the gun is still firing when the player alt-tabs back.
|
|
530
|
+
- **`isClickable` gates the press, not the release.** Disabling a button while
|
|
531
|
+
its key is down still releases it, so it cannot stick.
|
|
532
|
+
|
|
533
|
+
Shortcuts live only while the button is activated, and never start dragging or
|
|
534
|
+
tap-and-hold: those stay pointer gestures.
|
|
535
|
+
|
|
536
|
+
### A fullscreen option
|
|
537
|
+
|
|
538
|
+
Three methods on the `Application`, not on `device` (they moved there in
|
|
539
|
+
19.7.0):
|
|
540
|
+
|
|
541
|
+
```js
|
|
542
|
+
app.isFullscreen(); // boolean
|
|
543
|
+
app.requestFullscreen(); // needs a USER GESTURE
|
|
544
|
+
app.exitFullscreen(); // needs none
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**`requestFullscreen` only works from a click or a key press.** Called at
|
|
548
|
+
startup, or from a timer, the browser rejects it and nothing happens. That is
|
|
549
|
+
why a fullscreen option lives on a menu entry or a key, never in a scene's
|
|
550
|
+
setup:
|
|
551
|
+
|
|
552
|
+
```js
|
|
553
|
+
import { event, input } from "melonjs";
|
|
554
|
+
|
|
555
|
+
input.bindKey(input.KEY.F, "fullscreen");
|
|
556
|
+
event.on(event.KEYDOWN, (action, keyCode, edge) => {
|
|
557
|
+
// `edge` only: a held key auto-repeats, and a repeat toggles straight
|
|
558
|
+
// back out of what it just turned on
|
|
559
|
+
if (action !== "fullscreen" || !edge) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (app.isFullscreen()) {
|
|
563
|
+
app.exitFullscreen();
|
|
564
|
+
} else {
|
|
565
|
+
app.requestFullscreen();
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
One subscription on `KEYDOWN` covers every screen, where polling
|
|
571
|
+
`isKeyPressed` would need a copy in each menu that is up.
|
|
572
|
+
|
|
573
|
+
**It fullscreens the canvas's PARENT**, not the canvas, so a DOM HUD or
|
|
574
|
+
overlay inside that container goes with it. Pass an element to override.
|
|
575
|
+
|
|
576
|
+
**A menu entry showing `ON`/`OFF` must read the state back**, not cache it:
|
|
577
|
+
the player can leave fullscreen with Escape or the browser's own control
|
|
578
|
+
without your code hearing about it, and a remembered flag then lies.
|
|
579
|
+
|
|
580
|
+
```js
|
|
581
|
+
entry.setLabel(`FULLSCREEN: ${app.isFullscreen() ? "ON" : "OFF"}`);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**Nothing to branch on for support.** `requestFullscreen` checks
|
|
585
|
+
`device.hasFullscreenSupport` itself and no-ops without it, and
|
|
586
|
+
`exitFullscreen` no-ops when not fullscreen. Query
|
|
587
|
+
`device.hasFullscreenSupport` only to decide whether to *offer* the option at
|
|
588
|
+
all.
|
|
589
|
+
|
|
590
|
+
Fullscreen does not resize a fixed-resolution game: with
|
|
591
|
+
`new Application(w, h, { scale: "auto" })` the internal resolution is
|
|
592
|
+
unchanged and only the canvas scales, so a HUD built from
|
|
593
|
+
`renderer.width`/`height` needs no repositioning.
|
|
594
|
+
|
|
595
|
+
### `z` is container-local
|
|
596
|
+
|
|
597
|
+
`addChild(child, z)` writes a depth that means something **only among that
|
|
598
|
+
container's own children**. `autoDepth` numbers them from 1, so a button at
|
|
599
|
+
`z = 8` inside one panel and a whole second panel at `z = 2` are not comparable
|
|
600
|
+
numbers, and the second panel is still the one on top. Drawing and hit-testing
|
|
601
|
+
both resolve a cross-container pair the same way: walk up to the common parent
|
|
602
|
+
and compare the two siblings there.
|
|
603
|
+
|
|
604
|
+
So a panel is raised by raising **the panel**, not its contents:
|
|
605
|
+
|
|
606
|
+
```js
|
|
607
|
+
this.ancestor.moveToTop(panel); // reorders, and sets z past its neighbour
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Giving a child a huge `z` to "put it in front" lifts it only within its own
|
|
611
|
+
panel. This is also why a widget's `z` never has to be coordinated with
|
|
612
|
+
anything outside its own container.
|
|
613
|
+
|
|
614
|
+
### Panels and boxes that stretch: `NineSliceSprite`
|
|
615
|
+
|
|
616
|
+
A panel, dialogue box or button background drawn from one small image wants
|
|
617
|
+
`NineSliceSprite`, not a `Sprite` scaled up. It cuts the image into a 3×3 grid,
|
|
618
|
+
keeps the four corners at their own size, and stretches only the edges and the
|
|
619
|
+
middle, so the border stays crisp at any size. Do not hand-roll it from nine
|
|
620
|
+
sprites.
|
|
621
|
+
|
|
622
|
+
From a texture atlas, the third argument of `createSpriteFromName` asks for the
|
|
623
|
+
9-slice version. This is how the UI example's draggable panel draws itself:
|
|
624
|
+
|
|
625
|
+
```js
|
|
626
|
+
class Panel extends UIBaseElement {
|
|
627
|
+
constructor(x, y, width, height) {
|
|
628
|
+
super(x, y, width, height);
|
|
629
|
+
// `true` returns a NineSliceSprite stretched to the panel's size
|
|
630
|
+
this.addChild(
|
|
631
|
+
texture.createSpriteFromName("grey_panel", { width, height }, true),
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
From a loaded image, construct it directly (the Text example's dialogue box):
|
|
638
|
+
|
|
639
|
+
```js
|
|
640
|
+
const box = new NineSliceSprite(48, 640, {
|
|
641
|
+
image: "panel",
|
|
642
|
+
width: 900,
|
|
643
|
+
height: 256,
|
|
644
|
+
insetx: 36, // the border thickness in the source image
|
|
645
|
+
insety: 36,
|
|
646
|
+
tint: "#3a3f58", // tint works as on any sprite
|
|
647
|
+
});
|
|
648
|
+
box.anchorPoint.set(0, 0); // place it by its top-left corner
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
Three things trip people up:
|
|
652
|
+
|
|
653
|
+
- **`width` and `height` are mandatory.** They are the size to stretch *to*, not
|
|
654
|
+
the image's size, and the constructor throws without them.
|
|
655
|
+
- **Set `insetx` / `insety` to the art's border.** Left out, each defaults to a
|
|
656
|
+
quarter of the source image, which on most panel art cuts through the border:
|
|
657
|
+
the corners smear or the border thins out when the box grows.
|
|
658
|
+
- **The anchor is the centre**, as for any `Sprite`. Set it to `(0, 0)` to place
|
|
659
|
+
the box by its corner, as a layout usually wants.
|
|
660
|
+
|
|
661
|
+
It resizes live: set `width` / `height` and the next draw re-slices, so a box
|
|
662
|
+
that grows with its text, or a panel the player drags larger, needs no new
|
|
663
|
+
sprite.
|
|
664
|
+
|
|
665
|
+
### An opaque panel has to say so
|
|
666
|
+
|
|
667
|
+
The hit test asks the topmost renderable first and then keeps walking down, so
|
|
668
|
+
consuming is what stops a widget underneath answering too. A panel that can
|
|
669
|
+
overlap another one therefore wants both:
|
|
670
|
+
|
|
671
|
+
```js
|
|
672
|
+
class Panel extends UIBaseElement {
|
|
673
|
+
onClick() {
|
|
674
|
+
this.ancestor.moveToTop(this); // and bring it to the front
|
|
675
|
+
return false; // consumed
|
|
676
|
+
}
|
|
677
|
+
onOver() {
|
|
678
|
+
return false; // the frame the pointer crosses in
|
|
679
|
+
}
|
|
680
|
+
onActivateEvent() {
|
|
681
|
+
super.onActivateEvent();
|
|
682
|
+
// and every frame after that, when the pointer is ALREADY inside and
|
|
683
|
+
// `onOver` no longer fires
|
|
684
|
+
input.registerPointerEvent("pointermove", this, () => false);
|
|
685
|
+
}
|
|
686
|
+
onDeactivateEvent() {
|
|
687
|
+
input.releasePointerEvent("pointermove", this);
|
|
688
|
+
super.onDeactivateEvent();
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
Leave `onOut` alone: an element that suppresses its own leave stays lit after
|
|
694
|
+
the pointer has gone. It fires for the covered element too, not only when the
|
|
695
|
+
pointer leaves its bounds, so a button half under the panel goes dark as soon as
|
|
696
|
+
the pointer slides onto the panel, which never takes it out of the button's
|
|
697
|
+
bounds.
|
|
698
|
+
|
|
166
699
|
### In a 3D scene, a HUD needs a SMALL depth
|
|
167
700
|
|
|
168
701
|
`floating` opts a renderable out of the camera transform. It does **not** opt it
|
|
@@ -187,3 +720,9 @@ Give a HUD the huge z that would put it on top in 2D and it lands at the far end
|
|
|
187
720
|
of the level instead, with the scenery drawing over it. Both shipped idioms are
|
|
188
721
|
the same rule: afterBurner's HUD sits at `-150`, and the glTF, Billboard, Night
|
|
189
722
|
City and Instanced Forest examples park a floating sky at `-10000` or `100000`.
|
|
723
|
+
|
|
724
|
+
## Related skills
|
|
725
|
+
|
|
726
|
+
- `melonjs-scenes-and-state` — `Tween` and the easing families, for animating any of this
|
|
727
|
+
- `melonjs-input` — which object gets a pointer event, and how to consume it
|
|
728
|
+
- `melonjs-loading-assets` — web fonts have to be loaded before a `Text` bakes
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Color-space bridge for glTF material factors.
|
|
3
|
-
*
|
|
4
|
-
* glTF 2.0 defines `pbrMetallicRoughness.baseColorFactor` in **linear** space
|
|
5
|
-
* (spec §3.9.2), while a melonJS `tint` is an 8-bit **sRGB** value — the same
|
|
6
|
-
* space as a CSS color or a texel out of a PNG. Handing the linear number
|
|
7
|
-
* straight to `tint.setColor(f * 255)` therefore displays every untextured
|
|
8
|
-
* glTF material far too light and desaturated: a linear `0.29` shows up as
|
|
9
|
-
* sRGB `0.58`, so an authored mid-green renders as pale mint.
|
|
10
|
-
*
|
|
11
|
-
* The encode below is the standard sRGB transfer function.
|
|
12
|
-
* @module level/gltf/srgb
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Encode one linear channel (0..1) to an 8-bit sRGB value (0..255).
|
|
16
|
-
* @param {number} c - linear channel value
|
|
17
|
-
* @returns {number} the sRGB-encoded channel, rounded to 0..255
|
|
18
|
-
*/
|
|
19
|
-
export function linearToSrgb8(c: number): number;
|
|
20
|
-
//# sourceMappingURL=srgb.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"srgb.d.ts","sourceRoot":"","sources":["../../../src/level/gltf/srgb.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,iCAHW,MAAM,GACJ,MAAM,CAQlB"}
|