https://kaboomjs.com/ [boom][ka] guideexamplesdownloadgithubtwittertry on replit Import kaboom.global() Lifecycle init()start() Scene scene()go()layers()gravity()camPos()camScale()camRot()camIgnore() Asset Loading loadSprite()loadSound()loadFont() Objects add()destroy()obj.action()obj.use()obj.exists()obj.is()obj.on() obj.trigger()get()every()destroyAll() Components pos()scale()rotate()color()sprite()text()rect()area()body()solid() origin()layer() Events action()collides()overlaps()on() Input keyDown()keyPress()keyRelease()mouseDown()mouseClick()mouseRelease() Query width()height()time()dt()mousePos() Timer wait()loop() Audio play()volume() Math vec2()rgba()rgb()rand()randSeed()makeRng()choose()chance()lerp()map() Draw render()drawSprite()drawRect()drawLine()drawText() Level addLevel() Debug fps()objCount()pause()unpause()kaboom.debug() kaboom.js (beta) is a JavaScript library that helps you make games fast and fun! also check out the kaboom environment on replit.com! Usage quick start Import All functions are under a global object 'kaboom', but you can also choose to import all functions into global namespace. kaboom.global() import all kaboom functions into global namespace // 1) import everything to global kaboom.global(); init(); // 2) keep them under kaboom namespace to prevent any collision const k = kaboom; k.init(); Lifecycle Application Lifecycle Methods init([conf]) initialize context // quickly create a 640x480 canvas and get going init(); // options init({ width: 480, // width of canvas height: 480, // height of canvas canvas: document.getElementById("game"), // use custom canvas scale: 2, // pixel size (for pixelated games you might want small canvas + scale) clearColor: rgb(0, 0, 1), // background color (default black) fullscreen: true, // if fullscreen crisp: true, // if pixel crisp (for sharp pixelated games) }); start(scene, [...args]) start the game loop with specified scene scene("game", () => {/* .. */}); scene("menu", () => {/* .. */}); scene("lose", () => {/* .. */}); start("game"); Scene Scenes are the different stages of a game, like different levels, menu screen, and start screen etc. Everything belongs to a scene. scene(name) describe a scene scene("level1", () => { // all objs are bound to a scene add(/* ... */) // all events are bound to a scene keyPress(/* ... */) }); scene("level2", () => { add(/* ... */) }); scene("gameover", () => { add(/* ... */) }); start("level1"); go(name, [...args]) switch to a scene // go to "paused" scene when pressed "p" scene("main", () => { let score = 0; keyPress("p", () => { go("gameover", score); }) }); scene("gameover", (score) => { // display score passed by scene "main" add([ text(score), ]); }); layers(names, [default]) define the draw layers of the scene // draw background on the bottom, ui on top, layer "obj" is default layers([ "bg", "obj", "ui", ], "obj"); // this will be added to the "obj" layer since it's defined as default above const player = add([ sprite("froggy"), ]); // this will be added to the "ui" layer cuz it's specified by the layer() component const score = add([ text("0"), layer("ui"), ]); gravity(value) set the gravity value (defaults to 980) // (pixel per sec.) gravity(1600); camPos(pos) set the camera position // camera position follow player player.action(() => { camPos(player.pos); }); camScale(scale) set the camera scale if (win) { camPos(player.pos); // get a close up shot of the player camScale(3); } camRot(angle) set the camera angle camRot(0.1); camIgnore(layers) make camera don't affect certain layers // make camera not affect objects on layer "ui" and "bg" camIgnore(["bg", "ui"]); Asset Loading Load assets into asset manager. These should be at application top. loadSprite(name, src, [conf]) load a sprite loadSprite("froggy", "froggy.png"); loadSprite("froggy", "https://replit.com/public/images/mark.png"); // slice a spritesheet and add anims manually loadSprite("froggy", "froggy.png", { sliceX: 4, sliceY: 1, anims: { run: [0, 2], jump: [3], }, }); // load with aseprite sprite sheet loadSprite("froggy", "froggy.png", { aseSpriteSheet: "froggy.json", // use spritesheet exported from aseprite }); loadSound(name, src, [conf]) load a sound loadSound("shoot", "shoot.ogg"); loadFont(name, src, charWidth, charHeight, [chars]) load a font // default character mappings: (ASCII 32 - 126) // const ASCII_CHARS = " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; // load a bitmap font called "04b03", with bitmap "04b03.png", each character on bitmap has a size of (6, 8), and contains default ASCII_CHARS loadFont("04b03", "04b03.png", 6, 8); // load a font with custom characters loadFont("CP437", "CP437.png", 6, 8, ""); Objects Game Object is the basic unit of Kaboom, each game object uses components to compose their data and behavior. add(comps) add a game object to scene // a game object consists of a list of components const player = add([ // a 'sprite' component gives it the render ability sprite("froggy"), // a 'pos' component gives it a position pos(100, 100), // a 'body' component makes it fall and gives it jump() body(), // raw strings are tags "player", "killable", // custom fields are assigned directly to the returned obj ref { dir: vec2(-1, 0), dead: false, speed: 240, }, ]); player.action(() => { player.move(player.dir.scale(player.speed)); }); player.hidden = false; // if this obj renders player.paused = true // if this obj updates // runs every frame as long as player is not destroy() ed player.action(() => { player.move(100, 0); }); // provided by 'sprite()' player.play("jump"); // play a spritesheet animation console.log(player.frame); // get current frame // provided by 'pos()' player.move(100, 20); console.log(player.pos); // provided by 'body()' player.jump(320); // make player jump destroy(obj) remove a game object from scene collides("bullet", "killable", (b, k) => { // remove both the bullet and the thing bullet hit with tag "killable" from scene destroy(b); destroy(k); score++; }); obj.action(cb) update the object, the callback is run every frame player.action(() => { player.move(SPEED, 0); }); obj.use(comp) add a component to a game object // rarely needed since you usually specify all comps in the 'add()' step obj.use(scale(2, 2)); obj.exists() check if obj exists in scene // sometimes you might keep a reference of an object that's already 'destroy()'ed, use exists() to check if they were if (obj.exists()) { child.pos = obj.pos.clone(); } obj.is(tag) if obj has certain tag(s) if (obj.is("killable")) { destroy(obj); } obj.on(event, cb) listen to an event // when obj is 'destroy()'ed obj.on("destroy", () => { add([ sprite("explosion"), ]); }); // runs every frame when obj exists obj.on("update", () => { // ... }); // custom event from comp 'body()' obj.on("grounded", () => { // ... }); obj.trigger(event) trigger an event (triggers 'on') obj.on("grounded", () => { obj.jump(); }); // mainly for custom components defining custom events obj.trigger("grounded"); get(tag) get a list of obj reference with a certain tag const enemies = get("enemy"); every(tag, cb) run a callback on every obj with a certain tag // equivalent to destroyAll("enemy") every("enemy", (obj) => { destroy(obj); }); destroyAll(tag) destroy every obj with a certain tag Components Built-in components. Each component gives the game object certain data / behaviors. pos(x, y) object's position in the world const obj = add([ pos(0, 50), ]); // get the current position in vec2 console.log(obj.pos); // move an object by a speed (dt will be multiplied) obj.move(100, 100); scale(x, y) scale const obj = add([ scale(2), ]); // get the current scale in vec2 console.log(obj.scale); rotate(angle) scale const obj = add([ rotate(2), ]); obj.action(() => { obj.angle += dt(); }); color(r, g, b, [a]) color const obj = add([ sprite("froggy"), // give it a blue tint color(0, 0, 1), ]); obj.color = rgb(1, 0, 0); // make it red instead sprite(id, [conf]) draw sprite // note: this automatically gives the obj an 'area()' component const obj = add([ // sprite is loaded by loadSprite("froggy", src) sprite("froggy"), ]); const obj = add([ sprite("froggy", { animSpeed: 0.3, // time per frame (defaults to 0.1) frame: 2, // start frame (defaults to 0) }), ]); // get current frame console.log(obj.frame); // play animation obj.play("jump"); // stop the anim obj.stop(); obj.onAnimEnd("jump", () => { obj.play("fall"); }); text(txt, size, [conf]) draw text // note: this automatically gives the obj an 'area()' component const obj = add([ // content, size text("oh hi", 64), ]); const obj = add([ text("oh hi", 64, { width: 120, // wrap when exceeds this width (defaults to 0 no wrap) font: "proggy", // font to use (defaults to "unscii") }), ]); // update the content obj.text = "oh hi mark"; rect(w, h) draw rectangle // note: this automatically gives the obj an 'area()' component const obj = add([ // width, height rect(50, 75), pos(25, 25), color(0, 1, 1), ]); // update size obj.width = 75; obj.height = 75; area(p1, p2) a rectangular area for collision checking // 'area()' is given automatically by 'sprite()' and 'rect()', but you can override it const obj = add([ sprite("froggy"), // override to a smaller region area(vec2(6), vec2(24)), ]); // callback when collides with a certain tag obj.collides("collectable", (c) => { destroy(c); score++; }); // similar to collides(), but doesn't pass if 2 objects are just touching each other (checks for distance < 0 instead of distance <= 0) obj.overlaps("collectable", (c) => { destroy(c); score++; }); // checks if the obj is collided with another if (obj.isCollided(obj2)) { // ... } if (obj.isOverlapped(obj2)) { // ... } // register an onClick callback obj.clicks(() => { // ... }); // if the obj is clicked last frame if (obj.isClicked()) { // ... } // register an onHover callback obj.hovers(() => { // ... }); // if the obj is currently hovered if (obj.isHovered()) { // ... } // check if a point is inside the obj area obj.hasPt(); // resolve all collisions with objects with 'solid' // for now this checks against all solid objs in the scene (this is costly now) obj.resolve(); body([conf]) component for falling / jumping const player = add([ pos(0, 0), // now player will fall in this gravity world body(), ]); const player = add([ pos(0, 0), body({ // force of .jump() jumpForce: 640, // maximum fall velocity maxVel: 2400, }), ]); // body() gives obj jump() and grounded() methods keyPress("up", () => { if (player.grounded()) { player.jump(JUMP_FORCE); } }); // and a "grounded" event player.on("grounded", () => { console.log("horray!"); }); solid() mark the obj so other objects can't move past it if they have an area and resolve() const obj = add([ sprite("wall"), solid(), ]); // need to call resolve() (provided by 'area') to make sure they cannot move past solid objs player.action(() => { player.resolve(); }); origin(orig) the origin to draw the object (default center) const obj = add([ sprite("froggy"), // defaults to "topleft" origin("topleft"), // other options origin("top"), origin("topright"), origin("left"), origin("center"), origin("right"), origin("botleft"), origin("bot"), origin("botright"), origin(vec2(0, 0.25)), // custom ]); layer(name) specify the layer to draw on layers([ "bg", "game", "ui", ], "game"); add([ sprite("sky"), layer("bg"), ]); // we specified "game" to be default layer above, so a manual layer() comp is not needed const player = add([ sprite("froggy"), ]); const score = add([ text("0"), layer("ui"), ]); Events kaboom uses tags to group objects and describe their behaviors, functions below all accepts the tag as first arguments, following a callback action(tag, cb) calls every frame for a certain tag // every frame move objs with tag "bullet" up with speed of 100 action("bullet", (b) => { b.move(vec2(0, 100)); }); action("flashy", (f) => { f.color = rand(rgb(0, 0, 0), rgb(1, 1, 1)); }); collides(tag, cb) calls when objects collides with others collides("enemy", "bullet", (e, b) => { destroy(b); e.life--; if (e.life <= 0) { destroy(e); } }); overlaps(tag, cb) calls when objects collides with others // similar to collides(), but doesn't pass if 2 objects are just touching each other (checks for distance < 0 instead of distance <= 0) overlaps("enemy", "bullet", (e, b) => { destroy(b); e.life--; if (e.life <= 0) { destroy(e); } }); on(event, tag, cb) add lifecycle events to a tag group // called when objs with tag "enemy" is added to scene on("add", "enemy", (e) => { console.log("run!!"); }); // per frame (action() is actually an alias to this) on("update", "bullet", (b) => { b.move(100, 0); }); // per frame but drawing phase if you want custom drawing on("draw", "bullet", (e) => { drawSprite(...); }); // when objs gets destroy() ed on("destroy", "bullet", (e) => { play("explosion"); }); Input input events keyDown(key, cb) runs every frame when specified key is being pressed keyPress(key, cb) runs once when specified key is just pressed keyRelease(key, cb) runs once when specified key is just released mouseDown(cb) runs every frame when left mouse is being pressed mouseClick(cb) runs once when left mouse is just clicked mouseRelease(cb) runs once when left mouse is just released Query information about current window and input states width() canvas width height() canvas height time() current game time dt() delta time since last frame mousePos() current mouse position Timer timed events wait(time, cb) runs the callback after time seconds wait(3, () => { destroy(froggy); }); // or await wait(3); destroy(froggy); loop(time, cb) runs the callback every time seconds loop(0.5, () => { console.log("just like setInterval"); }); Audio yeah play(id, [conf]) plays a sound on("destroy", "enemy", (e) => { play("explode", { volume: 2.0, speed: 0.8, detune: 1200, }); }); volume(volume) set the master volume Math math types & utils vec2(x, y) creates a vector 2 vec2() // => { x: 0, y: 0 } vec2(1) // => { x: 1, y: 1 } vec2(10, 5) // => { x: 10, y: 5 } const p = vec2(5, 10); p.x // 5 p.y // 10 p.clone(); // => vec2(5, 10) p.add(vec2(10, 10)); // => vec2(15, 20) p.sub(vec2(5, 5)); // => vec2(0, 5) p.scale(2); // => vec2(10, 20) p.dist(vec2(15, 10)); // => 10 p.len(); // => 11.58 p.unit(); // => vec2(0.43, 0.86) p.dot(vec2(2, 1)); // => vec2(10, 10) p.angle(); // => 1.1 rgba(r, g, b, a) creates a color from red, green, blue and alpha values (note: values are 0 - 1 not 0 - 255) const c = rgba(0, 0, 1, 1); // blue p.r // 0 p.g // 0 p.b // 1 p.a // 1 c.clone(); // => rgba(0, 0, 1, 1) rgb(r, g, b, a) shorthand for rgba() with a = 1 rand(a, b) generate random value rand() // 0.0 - 1.0 rand(1, 4) // 1.0 - 4.0 rand(vec2(0), vec2(100)) // => vec2(29, 73) rand(rgb(0, 0, 0.5), rgb(1, 1, 1)) // => rgba(0.3, 0.6, 0.9, 1) randSeed(seed) set seed for rand generator randSeed(Date.now()); makeRng(seed) create a seedable random number generator const rng = makeRng(Date.now()); rng.gen(); // works the same as rand() choose(arr) get random element from array chance(p) rand(0, 1) <= p lerp(a, b, t) linear interpolation map(a, b, x, y, t) map number to another range Draw Raw immediate drawing functions (you prob won't need these) render(cb) use a generic draw loop for custom drawing scene("draw", () => { render(() => { drawSprite(...); drawRect(...); drawLine(...); }); }); drawSprite(name, [conf]) draw a sprite drawSprite("car", { pos: vec2(100), scale: 3, rot: time(), frame: 0, }); drawRect(pos, w, h, [conf]) draw a rectangle drawRect(vec2(100), 20, 50); drawLine(p1, p2, [conf]) draw a rectangle drawLine(vec2(0), mousePos(), { width: 2, color: rgba(0, 0, 1, 1), z: 0.5, }); drawText(text, [conf]) draw a rectangle drawText("hi", { size: 64, pos: mousePos(), origin: "topleft", }); Level helpers on building tiled maps addLevel(map, ref) takes a level drawing and turn them into game objects according to the ref map const characters = { "a": { sprite: "ch1", msg: "ohhi how are you", }, }; const map = addLevel([ " a ", " ===", " ? * ", " ==== ^^ ", "===================", ], { width: 11, height: 11, pos: vec2(0, 0), // every "=" on the map above will be turned to a game object with following comps "=": [ sprite("ground"), solid(), "block", ], "*": [ sprite("coin"), solid(), "block", ], // use a callback for dynamic evauations per block "?": () => { return [ sprite("prize"), color(0, 1, rand(0, 1)), "block", ]; }, "^": [ sprite("spike"), solid(), "spike", "block", ], // any catches anything that's not defined by the mappings above, good for more dynamic stuff like this any(ch) { if (characters[ch]) { return [ sprite(char.sprite), solid(), "character", { msg: characters[ch], }, ]; } }, }); // query size map.width(); map.height(); // get screen pos through map index map.getPos(x, y); // destroy all map.destroy(); // there's no spatial hashing yet, if too many blocks causing lag, consider hard disabling collision resolution from blocks far away by turning off 'solid' action("block", (b) => { b.solid = player.pos.dist(b.pos) <= 20; }); Debug debug utilities fps() current frames per second objCount() current number of objects in scene pause() pause the game unpause() unpause the game kaboom.debug() debug flags // scale the time kaboom.debug.timeScale = 0.5; // show the bounding box of objects with area() kaboom.debug.showArea = true; // hover to inspect objects (needs showArea checked) kaboom.debug.hoverInfo = true;