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-input
|
|
3
|
-
description: "Use this skill for keyboard, pointer, mouse, touch and gamepad input in melonJS. Covers the bindKey action indirection, registerPointerEvent on regions, the isKinematic requirement that silently blocks pointer events, world vs screen pointer coordinates, and gamepad mapping onto the same actions. Triggers on: input, bindKey, isKeyPressed, KEY, registerPointerEvent, releasePointerEvent, pointerdown, pointerup, POINTERMOVE, gamepad, bindGamepad, triggerKeyEvent, click, touch, drag."
|
|
3
|
+
description: "Use this skill for keyboard, pointer, mouse, touch and gamepad input in melonJS. Covers the bindKey action indirection, registerPointerEvent on regions, the isKinematic requirement that silently blocks pointer events, which of several overlapping objects receives an event and how to consume it, world vs screen pointer coordinates, and gamepad mapping onto the same actions. Triggers on: input, bindKey, isKeyPressed, KEY, registerPointerEvent, releasePointerEvent, pointerdown, pointerup, pointermove, POINTERMOVE, gamepad, bindGamepad, triggerKeyEvent, KEYDOWN, KEYUP, press any key, splash screen, click, touch, drag, hit test, event propagation, stop propagating, overlapping, which object gets the click."
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -29,6 +29,31 @@ wrong for jump or fire. A locked action stays consumed until the key is released
|
|
|
29
29
|
or you call `input.unlockKey("jump")`. Use `input.keyStatus(action)` when you
|
|
30
30
|
want the raw held/not-held state regardless of locking.
|
|
31
31
|
|
|
32
|
+
### A poll can miss a press entirely
|
|
33
|
+
|
|
34
|
+
`isKeyPressed` is sampled once per frame, and `keyup` decrements the key's
|
|
35
|
+
counter the moment it arrives — locked or not. A press that goes down and up
|
|
36
|
+
between two frames therefore leaves the counter back at zero and is never
|
|
37
|
+
seen. At 60fps that is anything under ~16ms: rare from a human finger, routine
|
|
38
|
+
from a synthetic event, and more likely the slower the frame rate.
|
|
39
|
+
|
|
40
|
+
For a screen where a missed press is a dead end — a splash, a "press any key",
|
|
41
|
+
a notice to acknowledge — listen for the event instead, which cannot be missed:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import { event } from "melonjs";
|
|
45
|
+
|
|
46
|
+
// action is the bound action name, or undefined for an unbound key
|
|
47
|
+
const onKey = (action) => { if (action === "menuSelect") continue(); };
|
|
48
|
+
event.on(event.KEYDOWN, onKey); // in onResetEvent
|
|
49
|
+
event.off(event.KEYDOWN, onKey); // in onDestroyEvent — it does not self-remove
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`KEYDOWN` fires for *every* key, bound or not, so matching on `action` is what
|
|
53
|
+
narrows it; it also repeats while the key is held, so guard anything that must
|
|
54
|
+
happen once. Keep polling for movement and for a menu cursor, where one step
|
|
55
|
+
per press and a key held across a state change are the things that matter.
|
|
56
|
+
|
|
32
57
|
The full signature is `bindKey(keyCode, action, lock?, preventDefault?)`;
|
|
33
58
|
`preventDefault` defaults to `input.preventDefault` (itself `true`). Pass the
|
|
34
59
|
fourth argument per binding, or change the global default with
|
|
@@ -64,9 +89,11 @@ subclasses with no body are the ones that catch people.
|
|
|
64
89
|
Register in `onActivateEvent` and release in `onDeactivateEvent`, not in the
|
|
65
90
|
constructor — pooled objects are reused and would otherwise accumulate handlers.
|
|
66
91
|
|
|
67
|
-
`app.viewport` works as a whole-screen region when you want global clicks
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
`app.viewport` works as a whole-screen region when you want global clicks. Note
|
|
93
|
+
it is asked **before** everything else, not as a fallback after nothing matched:
|
|
94
|
+
the dispatcher appends it to the candidate list and walks that list from the
|
|
95
|
+
end. So a viewport handler must not return `false` unless it really means to
|
|
96
|
+
swallow every pointer event in the game.
|
|
70
97
|
|
|
71
98
|
The accepted event names are exactly `"pointerdown"`, `"pointerup"`,
|
|
72
99
|
`"pointermove"`, `"pointercancel"`, `"pointerenter"`, `"pointerover"`,
|
|
@@ -76,6 +103,44 @@ throw `invalid event type`. melonJS maps the canonical name onto whichever
|
|
|
76
103
|
mouse/touch events the device actually supports, so you always register the
|
|
77
104
|
pointer name.
|
|
78
105
|
|
|
106
|
+
## Which object gets the event
|
|
107
|
+
|
|
108
|
+
The dispatcher collects the regions near the pointer from the broadphase,
|
|
109
|
+
bounds-checks each one, orders them **the way they are drawn** and asks the
|
|
110
|
+
topmost first, walking down until something consumes.
|
|
111
|
+
|
|
112
|
+
A handler consumes by returning `false`. This is the DOM sense and it reads
|
|
113
|
+
backwards: `false` means handled, and anything else, `undefined` included, lets
|
|
114
|
+
the walk carry on to whatever is underneath.
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
input.registerPointerEvent("pointerdown", this, () => {
|
|
118
|
+
this.fire();
|
|
119
|
+
return false; // nothing under this gets the click
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Three things decide the order, and only the first is obvious:
|
|
124
|
+
|
|
125
|
+
- **`pos.z`, among siblings of one container.** Higher is on top.
|
|
126
|
+
- **Across containers, the common ancestor decides.** `pos.z` is
|
|
127
|
+
container-local, since `autoDepth` numbers each container's children from 1,
|
|
128
|
+
so a button at `z = 8` inside one panel does not outrank a second panel at
|
|
129
|
+
`z = 2`. The pair is resolved by walking both up to their shared parent and
|
|
130
|
+
comparing the two siblings there, which is exactly how drawing resolves it.
|
|
131
|
+
Raise a whole panel with `ancestor.moveToTop(panel)`, not by inflating a
|
|
132
|
+
child's `z`.
|
|
133
|
+
- **A child is asked before the container holding it**, since it draws over it.
|
|
134
|
+
|
|
135
|
+
Equal `z` between siblings falls back to child order, lower index on top. Two
|
|
136
|
+
callbacks registered on the **same** region for the same event run
|
|
137
|
+
last-registered-first.
|
|
138
|
+
|
|
139
|
+
Consuming a **move** also takes the pointer away from the regions below: each
|
|
140
|
+
one still holding it gets its `pointerleave`, because it is covered now and
|
|
141
|
+
being inside its own bounds no longer decides. Consuming a press, a release or a
|
|
142
|
+
wheel does not, since none of those says where the pointer is.
|
|
143
|
+
|
|
79
144
|
## World coordinates versus screen coordinates
|
|
80
145
|
|
|
81
146
|
The pointer carries several, and picking the wrong one produces a feedback loop:
|
|
@@ -132,11 +197,80 @@ input.bindGamepad(0,
|
|
|
132
197
|
```
|
|
133
198
|
|
|
134
199
|
**Order matters:** `bindGamepad` throws `no action defined for keycode N` if the
|
|
135
|
-
keycode has not already been passed to `bindKey`.
|
|
136
|
-
|
|
137
|
-
|
|
200
|
+
keycode has not already been passed to `bindKey`.
|
|
201
|
+
|
|
202
|
+
Axes use the same call with a threshold, and bind **one half of the axis each**
|
|
203
|
+
— the sign selects which half:
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
input.bindGamepad(0, { type: "axes", code: input.GAMEPAD.AXES.LX, threshold: -0.15 }, input.KEY.LEFT);
|
|
207
|
+
input.bindGamepad(0, { type: "axes", code: input.GAMEPAD.AXES.LX, threshold: 0.15 }, input.KEY.RIGHT);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**`threshold` is added to the deadzone, it does not replace it.** The test is
|
|
211
|
+
`abs(value) >= deadzone + abs(threshold)`, so with the default deadzone of 0.1
|
|
212
|
+
a threshold of `0.5` does not fire until 0.6 of full travel, and `0.15` fires at
|
|
213
|
+
0.25. Pick the number you want the stick to break at and subtract the deadzone.
|
|
214
|
+
Raising `setGamepadDeadzone` moves every axis binding with it.
|
|
215
|
+
|
|
216
|
+
`unbindGamepad(index, button, type?)`, `setGamepadDeadzone(value)` and
|
|
138
217
|
`setGamepadMapping(id, mapping)` complete the surface.
|
|
139
218
|
|
|
219
|
+
### Which index to bind
|
|
220
|
+
|
|
221
|
+
Bindings are per pad **index**, and the index is plug order, not identity —
|
|
222
|
+
nothing reports which pad is "the" controller. Slot 0 is a guess: a wheel, a
|
|
223
|
+
spare pad or a keyboard-shaped device left plugged in can hold it for a whole
|
|
224
|
+
session while the player presses buttons on slot 1.
|
|
225
|
+
|
|
226
|
+
So a one-player game binds **every slot it will accept** to the same actions,
|
|
227
|
+
and lets `activeGamepad()` say which one is in use when something has to go
|
|
228
|
+
back the other way:
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
for (let pad = 0; pad < 4; pad++) {
|
|
232
|
+
input.bindGamepad(pad, { type: "buttons", code: input.GAMEPAD.BUTTONS.FACE_1 }, input.KEY.X);
|
|
233
|
+
}
|
|
234
|
+
input.activeGamepad(); // the last pad to produce a bound input, else the
|
|
235
|
+
// first connected one, else -1
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Binding spare slots costs nothing: the poll skips a bound index with no pad in
|
|
239
|
+
it. `activeGamepad()` follows **bound inputs only**, which is what makes it an
|
|
240
|
+
answer about the player rather than about electrical noise — a worn stick at
|
|
241
|
+
rest reports movement for ever and would otherwise claim to be the active pad.
|
|
242
|
+
|
|
243
|
+
### Rumble
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
input.vibrateGamepad(input.activeGamepad(), {
|
|
247
|
+
duration: 120, strongMagnitude: 0.6, weakMagnitude: 0.9,
|
|
248
|
+
});
|
|
249
|
+
input.stopGamepadVibration(index); // cut a long effect short
|
|
250
|
+
input.hasGamepadVibration(index); // for an options-screen toggle
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Safe to call blind: no pad, no motors, or no Gamepad API at all resolves
|
|
254
|
+
`false` and does nothing, so game code never branches on support. Magnitudes
|
|
255
|
+
default to **full** — the underlying web API defaults every parameter to zero,
|
|
256
|
+
which makes a bare `playEffect` a silent no-op. A second call preempts the
|
|
257
|
+
first on the same pad, so a rapid series of hits reads as a rapid series of
|
|
258
|
+
hits rather than as a queue. For a SUSTAINED rumble issue one effect with a
|
|
259
|
+
long `duration` instead of calling every frame.
|
|
260
|
+
|
|
261
|
+
Hot-plugging needs no polling of your own — the engine listens for the browser's
|
|
262
|
+
own events and republishes them:
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
import { event } from "melonjs";
|
|
266
|
+
|
|
267
|
+
event.on(event.GAMEPAD_CONNECTED, (gamepad) => { /* gamepad.id, .index */ });
|
|
268
|
+
event.on(event.GAMEPAD_DISCONNECTED, (gamepad) => { /* pause, show a prompt */ });
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Bindings survive a disconnect: they are attached to the index, not to the
|
|
272
|
+
device, so a pad unplugged and plugged back into the same slot keeps working.
|
|
273
|
+
|
|
140
274
|
## Virtual controls
|
|
141
275
|
|
|
142
276
|
On-screen buttons synthesise key events, again reaching the same actions:
|
|
@@ -159,6 +293,12 @@ input.triggerKeyEvent(input.KEY.LEFT, false); // release
|
|
|
159
293
|
| jump fires every frame while held | `bindKey` without its third `lock` argument |
|
|
160
294
|
| `invalid event type` thrown at registration | non-pointer name (`"click"`, `"mousedown"`, …) passed to `registerPointerEvent` |
|
|
161
295
|
| `no action defined for keycode N` | `bindGamepad` called before `bindKey` for that keycode |
|
|
296
|
+
| stick has to be pushed well past its `threshold` before it registers | `threshold` is ADDED to the deadzone, not used instead of it |
|
|
297
|
+
| one half of a stick does nothing | each half is a separate `bindGamepad`, chosen by the sign of `threshold` |
|
|
298
|
+
| a widget under an overlapping panel still reacts | the panel consumes nothing — return `false` from its `onClick` and `onOver` |
|
|
299
|
+
| a widget stays highlighted after the pointer moves onto a panel over it | the panel consumes no `pointermove`, so nothing takes the pointer off the widget |
|
|
300
|
+
| a child's big `z` does not put it in front of another container | `pos.z` is container-local — use `ancestor.moveToTop()` on the container |
|
|
301
|
+
| every click in the game stops working | a handler on `app.viewport` returning `false`, which is asked first |
|
|
162
302
|
|
|
163
303
|
## Related skills
|
|
164
304
|
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: melonjs-math
|
|
3
|
+
description: "Use this skill for vector and matrix maths in melonJS — Vector2d, Vector3d, their observable variants, Matrix2d, Matrix3d, and the math utility functions. Covers which methods mutate and which allocate, the vector pool and when clone() is the wrong tool, interpolation with lerp, slerp, damp and moveTowards, and the argument defaults that silently drop a component. Triggers on: Vector2d, Vector3d, ObservableVector2d, ObservableVector3d, Matrix2d, Matrix3d, vector, vector maths, dot, cross, normalize, length, distance, angle, lerp, slerp, damp, moveTowards, project, clamp, degToRad, radToDeg, clone, vector pool, vector3dPool, setMuted, setCallback, my vector is wrong, z is zero, scale ignores z., moveTowards ignores z, projectN, currentTransform, setTransform, matrix, transform matrix, column-major, val, Float32Array, basis matrix, orientation matrix."
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Vectors, matrices and maths
|
|
8
|
+
|
|
9
|
+
## The one rule that explains most surprises
|
|
10
|
+
|
|
11
|
+
**Methods mutate `this` and return it. They do not return a new vector.**
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
const a = new Vector3d(1, 0, 0);
|
|
15
|
+
const b = new Vector3d(0, 1, 0);
|
|
16
|
+
|
|
17
|
+
a.cross(b); // a IS NOW the cross product; the original a is gone
|
|
18
|
+
a.add(b).normalize().scale(3, 3, 3); // chains, all in place
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
That is what makes the API allocation-free, and it is the opposite of what a
|
|
22
|
+
functional style expects. If you need to keep the original, copy into
|
|
23
|
+
something you own first:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
out.copy(a).cross(b); // a untouched, nothing allocated
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**The exceptions are named.** A handful of methods return a NEW vector, and
|
|
30
|
+
each has a `*Self` sibling that does not:
|
|
31
|
+
|
|
32
|
+
| allocates a new vector | mutates in place |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `negate()` | `negateSelf()` |
|
|
35
|
+
| `floor()` | `floorSelf()` |
|
|
36
|
+
| `ceil()` | `ceilSelf()` |
|
|
37
|
+
| `clamp(low, high)` | `clampSelf(low, high)` |
|
|
38
|
+
| `clone()` | `copy(v)` |
|
|
39
|
+
|
|
40
|
+
So `v.negate()` in a per-frame loop allocates every frame and `v.negateSelf()`
|
|
41
|
+
does not. The names are the only clue; nothing in the call site shows it.
|
|
42
|
+
|
|
43
|
+
## `clone()` comes from a pool, and only pays off if you give it back
|
|
44
|
+
|
|
45
|
+
`clone()` is `vector3dPool.get(...)`. A pool is fast when instances come back:
|
|
46
|
+
`get()` takes a free one and resets it. Nothing comes back on its own, so a
|
|
47
|
+
clone that is simply dropped makes `get()` miss, construct, and write two
|
|
48
|
+
registry entries.
|
|
49
|
+
|
|
50
|
+
Measured, 3M operations:
|
|
51
|
+
|
|
52
|
+
| | |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `out.copy(a).cross(b)` | 39ms |
|
|
55
|
+
| `new Vector3d(ax, ay, az).cross(b)` | 37ms |
|
|
56
|
+
| `a.clone().cross(b)` | **2919ms** |
|
|
57
|
+
|
|
58
|
+
So:
|
|
59
|
+
|
|
60
|
+
- **Transient value inside a function?** Use a module-level scratch vector, or
|
|
61
|
+
`new Vector3d()`. Not `clone()`.
|
|
62
|
+
- **Keeping it, then done with it?** `clone()` and `vector3dPool.release(v)`
|
|
63
|
+
when finished. Releasing is what makes the pool a pool.
|
|
64
|
+
- **Writing a helper that returns a vector?** Take an optional `out`:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
const cross = (a, b, out = new Vector3d()) => out.copy(a).cross(b);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
That is the engine's own convention, and it lets a hot caller supply scratch
|
|
71
|
+
while a casual one ignores it.
|
|
72
|
+
|
|
73
|
+
**A returned value can never be shared scratch.** The next call overwrites
|
|
74
|
+
something the caller is still holding, and nothing fails loudly:
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
const _t = new Vector3d();
|
|
78
|
+
const bad = (v) => _t.copy(v).normalize(); // WRONG: two calls alias
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Argument defaults that drop a component
|
|
82
|
+
|
|
83
|
+
Three signatures quietly discard what you did not pass. All three are
|
|
84
|
+
reachable by writing the obvious thing.
|
|
85
|
+
|
|
86
|
+
**`scale(x, y = x, z = 1)`** — `z` defaults to **1**, not to `x`. A uniform
|
|
87
|
+
scale has to say so three times:
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
v.scale(2); // (1,2,3) -> (2,4,3) z UNTOUCHED
|
|
91
|
+
v.scale(2, 2, 2); // (1,2,3) -> (2,4,6) what you meant
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**`set(x, y, z = 0)`** — setting two components **zeroes the third**:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
v.set(10, 20); // z is now 0, whatever it was
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**`Vector3d.pos` on a renderable is typed `Vector2d`.** `Renderable.pos` is an
|
|
101
|
+
`ObservableVector3d` at run time but is declared through `Polygon` as a
|
|
102
|
+
`Vector2d`, so `.z`, `.setMuted` and `.setCallback` need a cast from
|
|
103
|
+
TypeScript. See issue #1510.
|
|
104
|
+
|
|
105
|
+
## `cross` is two different functions
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
v3.cross(other); // Vector3d: MUTATES v3, returns this
|
|
109
|
+
v2.cross(other); // Vector2d: returns a NUMBER, mutates nothing
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The 2D one is the z component of the 3D cross, which is the useful scalar for
|
|
113
|
+
"which side is this on". Same name, different shape, different return.
|
|
114
|
+
|
|
115
|
+
## Interpolation: four of them, and they are not interchangeable
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
a.lerp(b, t); // straight line, t in 0..1
|
|
119
|
+
a.slerp(b, t); // along the ARC, constant angular rate
|
|
120
|
+
a.damp(b, lambda, dt); // frame-rate independent ease toward b
|
|
121
|
+
a.moveTowards(b, step); // fixed distance per call, never overshoots
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**`moveTowards` is X/Y ONLY, on `Vector3d` as well as `Vector2d`.** It is the
|
|
125
|
+
one of the four that is not 3D: it measures the distance from `dx` and `dy`,
|
|
126
|
+
steps along `atan2(dy, dx)`, and leaves `z` exactly where it was. The source
|
|
127
|
+
says so in a comment and the JSDoc says "on the x and y axis", but the name
|
|
128
|
+
gives no hint, and in a list like the one above it reads as the sibling of the
|
|
129
|
+
other three. Anything moving in three dimensions wants `damp` or an explicit
|
|
130
|
+
step; reach for `moveTowards` only when the motion really is planar.
|
|
131
|
+
|
|
132
|
+
**`lerp` between two directions is uneven**: it slows at the ends, runs fast
|
|
133
|
+
through the middle, and shortens the vector as it passes halfway. Anything
|
|
134
|
+
whose direction matters more than its components wants `slerp` — a camera
|
|
135
|
+
swinging to look somewhere, a turret tracking, a body moving over a sphere.
|
|
136
|
+
`slerp` carries length linearly, so two unit vectors give a unit vector and
|
|
137
|
+
nothing needs normalising afterwards.
|
|
138
|
+
|
|
139
|
+
**`damp` is the one to use for "ease toward a target every frame"**, because
|
|
140
|
+
`lerp(current, target, 0.1)` per frame is frame-rate dependent: it converges
|
|
141
|
+
twice as fast at 120fps as at 60.
|
|
142
|
+
|
|
143
|
+
## `project` scales THIS, and `projectN` is the one without the divide
|
|
144
|
+
|
|
145
|
+
`a.project(b)` does not return the component of `a` along `b`. It scales **a**
|
|
146
|
+
by `a.b / |b|^2` and returns `a`, so the result points along `a`, not along
|
|
147
|
+
`b`. Worth knowing before you reach for it expecting the textbook projection.
|
|
148
|
+
|
|
149
|
+
`projectN(v)` is the same thing for a `v` that is already unit, so it skips
|
|
150
|
+
the `/ v.length2()`:
|
|
151
|
+
|
|
152
|
+
```js
|
|
153
|
+
a.project(b); // a scaled by (a.b / |b|^2)
|
|
154
|
+
a.projectN(b); // a scaled by (a.b) -- only correct when |b| = 1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Handing `projectN` a target that is NOT unit does not normalise anything, it
|
|
158
|
+
just scales by the raw dot product. That is the price of it being cheaper, and
|
|
159
|
+
it is the caller's job to meet the contract.
|
|
160
|
+
|
|
161
|
+
Until 20.9 both 3D classes got this wrong: `Vector3d.projectN` and
|
|
162
|
+
`ObservableVector3d.projectN` were copies of `project`, division and all,
|
|
163
|
+
under `projectN`'s name and its "slightly more efficient" doc comment. Nothing
|
|
164
|
+
in the engine called either one and nothing tested them, which is how it
|
|
165
|
+
survived. Both are fixed and all four classes are now pinned by tests.
|
|
166
|
+
|
|
167
|
+
## `length()` is `sqrt(x*x + y*y + z*z)`
|
|
168
|
+
|
|
169
|
+
Fast and correct to 1 ULP for anything a game holds. It is NOT robust at
|
|
170
|
+
extremes: components above ~1e154 overflow to `Infinity` and below ~1e-162
|
|
171
|
+
underflow to `0`, because the squares are formed before the root. `Math.hypot`
|
|
172
|
+
avoids that and costs 35 to 65% more. The engine takes the speed, which is the
|
|
173
|
+
right trade for coordinates between 1e-3 and 1e6; nothing in a game is 148
|
|
174
|
+
orders of magnitude from unit scale.
|
|
175
|
+
|
|
176
|
+
`length2()` skips the square root. Use it for comparisons:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
if (a.distance(b) < r) { } // a square root you did not need
|
|
180
|
+
if (a.sub(b).length2() < r * r) { } // same answer, cheaper
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Observable vectors
|
|
184
|
+
|
|
185
|
+
`ObservableVector2d` / `ObservableVector3d` call a callback on every write,
|
|
186
|
+
which is how a renderable knows its bounds went stale.
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
v.setCallback(() => { ... });
|
|
190
|
+
v.setMuted(true); // write without firing it
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**`setMuted` is what you want when writing several components**, so a
|
|
194
|
+
half-updated vector does not fire a callback that reads the other half.
|
|
195
|
+
`set()` already does this internally: it disables the callback, writes all
|
|
196
|
+
three, fires once, and re-enables.
|
|
197
|
+
|
|
198
|
+
Note the observable `set(x = 0, y = 0, z = 0)` defaults EVERY argument, so
|
|
199
|
+
`set(10, 20)` zeroes z exactly as the plain vector does.
|
|
200
|
+
|
|
201
|
+
## Matrices
|
|
202
|
+
|
|
203
|
+
`Matrix2d` is 3x3 for 2D affine transforms; `Matrix3d` is 4x4. Both mutate and
|
|
204
|
+
chain, same as vectors, and both come from pools.
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
m.identity().translate(x, y).rotate(angle).scale(sx, sy);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Order is the reverse of how it reads.** These post-multiply, so the call
|
|
211
|
+
made LAST reaches the vertex FIRST. To rotate a thing about its own centre,
|
|
212
|
+
translate to the centre last.
|
|
213
|
+
|
|
214
|
+
### Every renderable already HAS one
|
|
215
|
+
|
|
216
|
+
`Renderable.currentTransform` is a `Matrix3d`. If you are orienting something
|
|
217
|
+
on screen, the matrix exists: write into it rather than building a parallel
|
|
218
|
+
structure and copying.
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
// the whole transform of a renderable, written in place
|
|
222
|
+
mesh.currentTransform.identity().translate(x, y, z).rotate(angle, axis);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### The sixteen numbers are `val`, column-major
|
|
226
|
+
|
|
227
|
+
Composing with `translate`/`rotate`/`scale` is one way to fill a matrix. The
|
|
228
|
+
other is to write the numbers, which is what you want when the orientation
|
|
229
|
+
comes from a basis you have already computed — three orthonormal vectors, a
|
|
230
|
+
surface frame, a camera basis.
|
|
231
|
+
|
|
232
|
+
`val` is a `Float32Array(16)` in **column-major** order, the OpenGL
|
|
233
|
+
convention: each basis vector occupies a stride-4 run, and the translation is
|
|
234
|
+
the last column.
|
|
235
|
+
|
|
236
|
+
| | X column | Y column | Z column | translation |
|
|
237
|
+
|---|---|---|---|---|
|
|
238
|
+
| indices | `0,1,2` | `4,5,6` | `8,9,10` | `12,13,14` |
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// an orientation from three axes, straight into the renderable's own matrix
|
|
242
|
+
const m = mesh.currentTransform.val;
|
|
243
|
+
m[0] = right.x; m[1] = right.y; m[2] = right.z; m[3] = 0;
|
|
244
|
+
m[4] = up.x; m[5] = up.y; m[6] = up.z; m[7] = 0;
|
|
245
|
+
m[8] = fwd.x; m[9] = fwd.y; m[10] = fwd.z; m[11] = 0;
|
|
246
|
+
m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
A helper that builds one should take the destination, the same way the engine
|
|
250
|
+
takes an `out`, so it writes once into the matrix that will be used:
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
const orient = (frame, out) => { /* writes out.val */ return out; };
|
|
254
|
+
orient(frame, mesh.currentTransform);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Getting numbers IN from somewhere else
|
|
258
|
+
|
|
259
|
+
`setTransform(...)` takes the sixteen as arguments, and `copy(m)` takes
|
|
260
|
+
another matrix:
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
m.setTransform(a, b, c, d, e, f, g, h, i, j, k, l, p, q, r, s);
|
|
264
|
+
m.copy(other); // Float32Array.set under the hood
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Both are fine occasionally. In a per-frame loop, prefer writing `val` or
|
|
268
|
+
`copy()` over spreading sixteen arguments, and note that **one matrix built
|
|
269
|
+
once and applied to many renderables** is a `copy()` per renderable, not a
|
|
270
|
+
rebuild per renderable.
|
|
271
|
+
|
|
272
|
+
**`val` is `Float32Array`, so it holds float32.** Numbers you put in are
|
|
273
|
+
rounded to single precision. That is where they were always heading, since
|
|
274
|
+
this is what reaches the GPU, but it means a value read back out is not
|
|
275
|
+
bit-identical to the double you wrote.
|
|
276
|
+
|
|
277
|
+
## Utilities
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
import { math } from "melonjs";
|
|
281
|
+
|
|
282
|
+
math.clamp(v, lo, hi);
|
|
283
|
+
math.lerp(a, b, t); // scalars
|
|
284
|
+
math.damp(a, b, lambda, dt); // frame-rate independent
|
|
285
|
+
math.degToRad(deg); math.radToDeg(rad);
|
|
286
|
+
math.random(lo, hi); // integer
|
|
287
|
+
math.randomFloat(lo, hi);
|
|
288
|
+
math.weightedRandom(lo, hi); // integer, biased toward LO
|
|
289
|
+
math.round(n, decimals);
|
|
290
|
+
math.pow(n); // n squared
|
|
291
|
+
math.DEG_TO_RAD math.RAD_TO_DEG math.TAU math.ETA math.EPSILON
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Symptoms
|
|
295
|
+
|
|
296
|
+
| symptom | cause |
|
|
297
|
+
|---|---|
|
|
298
|
+
| z unchanged after scaling | `scale(s)` leaves z alone; pass `scale(s, s, s)` |
|
|
299
|
+
| z became 0 for no reason | `set(x, y)` defaults z to 0 |
|
|
300
|
+
| the original vector changed | the method mutates; `copy()` into something first |
|
|
301
|
+
| memory climbs in a loop | `clone()` or `negate()`/`floor()`/`ceil()` per frame |
|
|
302
|
+
| two helper results are the same object | a shared scratch vector was returned |
|
|
303
|
+
| `.z` is a type error | `Renderable.pos` is declared `Vector2d` (#1510) |
|
|
304
|
+
| rotation eases oddly between directions | `lerp` on directions; use `slerp` |
|
|
305
|
+
| you built your own 16-number array | `Renderable.currentTransform` is already a `Matrix3d`; write its `val` |
|
|
306
|
+
| a value read back from a matrix differs | `val` is `Float32Array`; it holds float32 |
|
|
307
|
+
| easing differs at 120fps | per-frame `lerp`; use `damp` |
|
|
308
|
+
|
|
309
|
+
## Related skills
|
|
310
|
+
|
|
311
|
+
- `melonjs-3d` — `Camera3d`, meshes, and where these vectors are used in 3D
|
|
312
|
+
- `melonjs-physics` — bodies, velocities and collision response
|
|
313
|
+
- `melonjs-performance` — pooling in general, and what release() is for
|