tga, 01/15/2023
We’re releasing Kaboom v3000 beta! This major version update includes a lot of new features and improvements, and also breaking changes (see migration guide below).
To try the beta version, install kaboom@next
$ npm install kaboom@next
<script src="https://unpkg.com/kaboom@next/dist/kaboom.js">script>
or use this Replit template
Note that this is a beta release, there are bugs and possiblly breaking changes before official release. Please report bugs to github issues, and general questions / discussions to github discussions.
Scene Graph
Objects can now have children with obj.add()
! Children will inherit the transform (position, scale and rotation) of the parent.
const bean = add([
sprite("bean"),
pos(160, 120),
])
const sword = bean.add([
sprite("sword"),
pos(20, 20),
rotate(20),
])
const hat = bean.add([
sprite("hat"),
pos(0, -10),
])
bean.moveBy(100, 200)
bean.destroy()
Check out the rotating pineapples in this live example (in case you didn’t notice, it also demonstrates rotating areas!)
More Font Formats
loadFont()
now loads .ttf
, .otf
, .woff
, .woff2
fonts (any font that browser font-face supports). The function to load bitmap font is renamed to loadBitmapFont()
.
kaboom({
font: "ComicSans",
})
loadFont("ComicSans", "assets/fonts/ComicSans.ttf")
loadFont("apl386", "assets/fonts/apl386.ttf", { outline: 4, filter: "linear" })
loadBitmapFont("4x4", "/examples/fonts/4x4.png", 4, 4)
Tweening
const t = tween(
obj.pos,
mousePos(),
0.5,
(p) => obj.pos = p,
easings.easeOutElastic,
)
t.cancel()
t.onEnd(() => {
})
await tween(...)
await wait(1)
await tween(...)
await tween(...)
await wait(1)
Go to tween example to play around with it! Press left / right arrow key to change the interpolation function, mouse click anywhere to set destination.
Rotated Areas
Previously Kaboom only supports unrotated AABB boxes for collision detection, now Kaboom supports collision detection and resolution between any arbitrary convex polygons (e.g. rotated rectangles).
add([
sprite("bean"),
pos(200, 100),
rotate(30),
area(),
])
add([
sprite("bean"),
pos(200, 100),
area({ shape: new Polygon([vec2(0), vec2(100), vec2(-100, 100)]) }),
])
Check out the new collision example. Press Q / E to rotate bean, and arrow keys to move around and see how bean now reacts with others!
Improved Performance
Graphics performance improved ~3x – 50x, collision detection performance improved ~2x – 4x. Read more about this in this blog post.
Custom Loading Screen
Now you can draw your custom loading screen with onLoading()
(note that this function runs every frame, you can only use the drawXXX()
functions here)
onLoading(() => {
drawRect({
width: width(),
height: height(),
color: rgb(0, 0, 0),
})
drawCircle({
pos: center(),
radius: 32,
end: map(progress, 0, 1, 0, 360),
})
drawText({
text: "loading" + ".".repeat(wave(1, 4, time() * 12)),
font: "monospace",
size: 24,
anchor: "center",
pos: center().add(0, 70),
})
})
Another option is to turn off loading screen completely, default or custom:
kaboom({
loadingScreen: false,
})
Try it ou in the loader example! It also demonstrated some other loading techniques.
Post Effect
Kaboom now provides an easy way to add full screen visual effect with shader:
loadShader("pixelate", null, `
uniform float u_size;
uniform vec2 u_resolution;
vec4 frag(vec2 pos, vec2 uv, vec4 color, sampler2D tex) {
if (u_size <= 0.0) return def_frag();
vec2 nsize = vec2(u_size / u_resolution.x, u_size / u_resolution.y);
float x = floor(uv.x / nsize.x + 0.5);
float y = floor(uv.y / nsize.y + 0.5);
vec4 c = texture2D(tex, vec2(x, y) * nsize);
return c * color;
}
`)
usePostEffect("pixelate", {
"u_resolution": vec2(width(), height()),
"u_size": 4,
})
Try it out in the postEffect example. Use UP/DOWN arrow to cycle through the example effects!
Gamepad
Added gamepad support.
onGamepadButtonPress("south", () => {
player.jump()
})
onGamepadStick("left", (v) => {
player.move(v.scale(SPEED))
})
If you gamepad doesn’t work, add your gamepad mappings to Kaboom’s gamepad mapping json file.
Connect a gamepad and go nuts with this classic minigame!
Path Finding
The level API has been rewored and added path finding support. Use the new tile()
component with option tile({ isObstacle: true })
to define obstacles in a level, and agent()
component to
const map = addLevel([
"##########",
"# #",
"# @ #",
"#..... #",
"# #",
"# ....#",
"# $ #",
"# #",
"##########",
], {
tileWidth: 64,
tileHeight: 64,
tiles: {
"$": () => [
sprite("coin"),
area(),
],
"#": () => [
sprite("wall"),
tile({ isObstacle: true }),
],
"@": () => [
sprite("player"),
tile(),
agent({ speed: 640, allowDiagonals: true }),
"player",
],
},
})
const player = get("player")[0]
onClick(() => {
bean.setTarget(mousePos())
})
Run this maze example to see for yourself. Click anywhere in the maze to travel to it!
Path finding is implemented by @mflerackers
More features
See complete list of changes in CHANGELOG
Migrating to v3000
You can check this doc