Coder Social home page Coder Social logo

kaboom's Introduction

Notice

Replit no longer maintains Kaboom. You may be interested in the community fork KaPlay.

Kaboom

kaboom

Kaboom is a JavaScript library that helps you make games fast and fun!

Start playing around with it in the Kaboom Playground

Examples

// initialize context
kaboom()

// define gravity
setGravity(2400)

// load a sprite called "bean"
loadSprite("bean", "sprites/bean.png")

// compose the player game object from multiple components and add it to the game
const bean = add([
    sprite("bean"),
    pos(80, 40),
    area(),
    body(),
])

// press space to jump
onKeyPress("space", () => {
    // this method is provided by the "body" component above
    bean.jump()
})

Kaboom uses a powerful component system to compose game objects and behaviors.

// add a game obj to the scene from a list of component
const player = add([
    // it renders as a sprite
    sprite("bean"),
    // it has a position
    pos(100, 200),
    // it has a collider
    area(),
    // it is a physical body which will respond to physics
    body(),
    // it has 8 of health
    health(8),
    // or give it tags for easier group behaviors
    "player",
    "friendly",
    // plain objects fields are directly assigned to the game obj
    {
        dir: vec2(-1, 0),
        dead: false,
        speed: 240,
    },
])

Blocky imperative syntax for describing behaviors

// .onCollide() comes from "area" component
player.onCollide("enemy", () => {
    // .hurt() comes from "health" component
    player.hurt(1)
})

// check fall death
player.onUpdate(() => {
    if (player.pos.y >= height()) {
        destroy(player)
        gameOver()
    }
})

// if 'player' onCollide with any object with tag "enemy", run the callback
player.onCollide("enemy", () => {
    player.hp -= 1
})

// all objects with tag "enemy" will move towards 'player' every frame
onUpdate("enemy", (e) => {
    e.move(player.pos.sub(e.pos).unit().scale(e.speed))
})

// move up 100 pixels per second every frame when "w" key is held down
onKeyDown("w", () => {
    player.move(0, 100)
})

Usage

Start a Project With create-kaboom

The fastest way to start a Kaboom game is with create-kaboom

$ npm init kaboom mygame

This will create a directory called mygame for you, containing all the files we need

$ cd mygame
$ npm run dev

Then open http://localhost:5173 and edit src/game.js

Install as NPM Package

$ npm install kaboom
import kaboom from "kaboom"

kaboom()

add([
    text("oh hi"),
    pos(80, 40),
])

also works with CommonJS

const kaboom = require("kaboom")

Note that you'll need to use a bundler like esbuild or webpack to use Kaboom with NPM

Browser CDN

This exports a global kaboom function

<script src="https://unpkg.com/kaboom@3000/dist/kaboom.js"></script>
<script>
kaboom()
</script>

or use with es modules

<script type="module">
import kaboom from "https://unpkg.com/kaboom@3000/dist/kaboom.mjs"
kaboom()
</script>

works all CDNs that supports NPM packages, e.g. jsdelivr, skypack

Documentation

Dev

  1. npm install to install dev packages
  2. npm run dev to start dev server
  3. go to http://localhost:8000/ and pick an example
  4. edit examples in examples/ to test

Check out CONTRIBUTION.md for full info.

Community

Games

Collection of games made with Kaboom, selected by Kaboom, here.

Misc

kaboom's People

Contributors

dependabot[bot] avatar epicgamer007 avatar hacknug avatar juneaucross avatar kgish avatar kusstar avatar lajbel avatar lirantal avatar luizbills avatar luluxia avatar malted avatar mamamia5x avatar mannysz avatar masad-frost avatar mflerackers avatar namiwang avatar neerajkumarc avatar neverusedgithub avatar oaklandgit avatar rildev avatar rish avatar sg-swe073 avatar sixhobbits avatar slmjkdbtl avatar stutz avatar triptych avatar tristanperrow avatar wbourne0 avatar worktheclock avatar ykdojo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kaboom's Issues

Multiple tile maps in same scene?

Is it possible to add multiple tile maps to the same scene?

I expected to be able to create multiple "addLevel" objects and assign each to a different layer, but it doesn't seem to work.

UI examples

Hi, Kaboom looks great, very simple API.

I'm new to game develop, it seems to be quite different from web develop, especially UI stuff.

Are there more examples about UI? Like Modal, Input, Dropdown etc.

Backwards compatibility issue with aespriteSheet support

The issue is that earlier versions of aesprite export invalid spritesheet JSON that Kaboom does not recognise.

At the very least v1.1.6 exports unrecognised JSON. (The difference in this version is simply that "frames" is an object rather than an array of objects. An easy manual fix)

I'm not sure which aesprite version changed the export format (or how many variations there are)

This might be an issue for the documentation rather than the library itself, as you may not wish the hassle of supporting every different export format that was in use.

Many Thanks!

Feature Request: full docs beyond the anchors on the home page

Having the docs on the home page is great! But as someone who's using this every day for a week now, having to mouse over some API elements as the only way to know how some things work is a bit challenging.

For instance. I'm on my laptop with a limited screen space, and I'm trying to look at KaboomCtx:
image

It's literally impossible for me to see the whole thing because when I mouse over the KaboomCtx I only see the partial tooltip, and there's no way to anchor it to scroll.

Sure I can go look in the source - but having something more reader friendly ( outside the fun main website ) would be awesome.

import scenes from a different file

Could you show an example of how to write a scene in a different file and then import it in?

Right now I'm using absolute path to import i.e. import { differentScene } from "/pub/examples/different_scene.js";

This is working but is this best practice? Is there a way to support relative path importing?

kaboom examples and replit kaboom project no longer work in Safari 14.1

Seems like the recent updates to the kaboom library have changed something that has impacted Safari support. Previously all of the examples worked and I could learn to code using the kaboom library with my replit projects on Safari on a Mac or on my iPad. Now none of the examples work and my replit project is no longer working. This seems to have changed with the recent 0.5.0 release? The error message in Safari's web inspector is not very helpful to me but perhaps you understand it:

[Error] Error: 

	f (kaboom.js:1:9800)
	(anonymous function) (kaboom.js:1:7877)
	Et (kaboom.js:1:8678)
	(anonymous function) (kaboom.js:54:28043)
	Global Code (about:srcdoc:30)

The examples seem to work in the latest version of Google Chrome but as I can not use Chrome on my school issue iPads it would be better if Safari was supported.

How to name sprites from spritesheet

Hi there,

I can't see information in the doc about creating sprites from a spritesheet (to use as separate tiles in level() for example). All the examples use distinct image files, and the only mention about splitting a spritesheet is related to animation (anim, from, too). What's the right way to do it ?

Many thanks for your help !

Tileset support?

Is there support for tilesets? I would like to create levels using a single tileset image and pass in indices of tile objects (instead of separate sprite images individually).

Great project btw! Very simple and fun to play with

text() with width set wraps, but cuts off words.

the text object is very cool! However when you set a width, it's not all that useful because the words are cut off. Can you add an option or fix the rendering so that if a word does not fit in the width, the whole word is carried over to the next line?
image

'destroy' method broken : Uncaught TypeError: obj.exists is not a function

destroy() method does not work correctly, returning the error referenced below. Conversely, destroyAll() functions as anticipated in the same scenarios. Full error messaging below:

    Uncaught TypeError: obj.exists is not a function
        at destroy (kaboom.js:2191)
        at Object.cb (main.js:59)
        at frame (kaboom.js:2403)

Playing Aseprite animation fix

I've tried using an aseprite animation but can't get it to work. I've finally found the problem, and after changing

play(name, loop) {
	const anim = spr[this.spriteID].anims[name];

to

play(name, loop) {
	const anim = assets.sprites[this.spriteID].anims[name];

it worked.

I'm not sure if it's related to aseprite plugin, or related to core. I can make PR if needed

Typescript Support

Congrats. I'm fall in love with your engine. Your engine is easy to read. But I think you should move it to typescript. Just compile it with esbuild with iife format, it's fast and modern enough rather than use webpack.

๐Ÿ‘๐Ÿป good job.

Add example with animation

Hi there,

I'm trying to add an animation (manually created from a spritesheet) to a character, but I can't get it working. If I'm right, the only example using this feature is "drive", which extracts data from a json file. Another straightforward example (manually split, add animation and play) would be really useful !

PS : many thanks for Kaboom.js ! I can't wait to see Kaboom grow and I'm really impatient to use it with my students :)

Dragging object

Hi! Kaboom looks amazing!
Is there any support for dragging an object?
I found event handlers for click and hover, but not for dragging.

Change license to MIT

Hello, I just found this project, seems nice and cool and small, however the GNU license is overkill for game development libraries and makes wonder why I would use this instead of other existing options. So please consider to change to MIT.

Improve animations frame duration (animSpeed) handling

I've been trying to use animation in a game and I've noticed that you can only use one animSpeed for all the frames/animations of a sprite.

For example, here I have made a heart collectible and 3 animations with different frame durations that I would want to use inside Kaboom as-is. "Spawn" frames are 200ms long, "idle" are 800ms long, and "pick" are 100ms long.

image

But I've noticed that you can only set a animSpeed for the whole sprite and only when you're adding a sprite to the scene.

I think it could be nice if you could set animation frame durations at 3 points in time :

  • when loading a sprite, with loadSprite() and loadAseprite()
  • when initialising a sprite, with sprite()
  • when playing an animation, with play(), so you can speed up an animation based on some conditions

As an API, I thought about using something like :

Let say you have a sprite with two animations A and B and 5 frames like A1, A2, A3, B4, B5
You could say {durations: {A: 200, B: 300}} or {durations: {A: 200, B: [125, 175]}} or {durations: [200, 200, 200, 300, 300]} (like an aseprite files contains) so you can handle all level of customisations.

play(animation, loop = true) for sprites would transform into play(animation, options = {})
with options being something {loop: <boolean>, durations: <durationData>, restart: <boolean>}

I'm introducing restart because I find it strange to handle this myself:

action("player", () => {
  if (! keyIsDown("left") && ! keyIsDown("right")) {
    // this might be kaboom's work
    if (player.curAnim() != 'idle') {
      player.play("idle", true)
    }
}

It would be nice that by default it does not switch if animation is already playing, unless you explicitely say to restart the animation.

If these changes interest you, I could make a PR.

Switching from one animation to another (like in documentation) fails

I'm trying to make animations work but switching animations like this fails :

(heart spawns animation once, then idle animation looping)

image

It seems like .play() inside the ballback tries to end current animations and trigger onAnimEnd callbacks, but I'm already in one so it makes an infinite loop.

Improve sound control

๐Ÿ‘‹ I'm making a proof of concept of a rhythm game using Kaboom. It's such a simple and easy-to-understand engine & it's great to work in.

It would be very useful to have additional control of the play() function, mainly:

  1. Being able to ask the underlying player how long it has been playing:
const music = play("song1");
//...
music.currentTime();
  1. Being able to attach event listeners to the audio timeupdate event and other events from the underlying audio player so you don't have to poll for updates, similar to obj.on()
const music = play("song1");
//...
music.on("timeupdate", () => {
    //...
});

Feature Request: Event trigger for when an object leaves the scene

I know there's an exists() and an add() event. But need some kind of event or check to see if an object is still visible in a scene. For instance imagine if you are in a shooter game and enemies are spawing from the top and moving down. It would be great to have something like obj.leftView() = true and object.on("leftView", (o)=>{ destroy(o) } ) when the enemies go down below the view and offscreen, so they can be destroyed ( or whathaveyou )

If there already is something great, but I couldn't find it. And if there's not - this is a request to add this.

It's not when the object is invisible, but just when the object is now outside the viewport.

Destroy event handlers getting called twice

Hi there,

I just noticed that since version 0.3.0 destroy event handlers are getting called twice. To reproduce with 0.4.0:

const k = kaboom()

k.scene('main', () => {
  const foo = k.add(['foo'])
  
  k.on('destroy', 'foo', console.log)
  k.destroy(foo)
})

k.start('main')

Cheers, having a lot of fun with your library! :)

Animations play in fast forward after running in background tab

When a scene is left running in another browser tab, and that tab is reopened, sprites that had active animations running play them in fast-forward until they are fully caught up.

This issue seems to occur in different browsers (tested Firefox and Chrome) and when using either the loadSprite or loadAseprite functions to load the sprite.

I have some code to reproduce if that would be useful.

Many Thanks!

Game objects on different layers do not trigger overlaps callback.

I'm not sure if this intentional or not, but game objects on different layers will not trigger the callback defined in the overlaps function.

Example:

Player rendered on 'sprite' layer and bullet's rendered on 'bullet' layer never overlap. Player has 'player' tag. Bullet has 'bullet' tag.

overlaps('player', 'bullet', (p, b) => { destroy(p); destroy(b); });

Neither are destroyed during overlap.

Sprite and layer transparency

Can you add transparency to sprites and layer?

  • sprite transparency: can be used to show a player or object is invincible or otherwise unaffected by collisions
  • layer transparency: useful to display a high-score screen or instruction screen overlaid on the game. Currently I'm doing this with separate scenes.

This could also be covered with fadeIn()/fadeOut() animations.

Loop not cleared when go()ing from inside the loop

Hey again,

I just discovered a small bug while implementing a countdown to switch scenes: when calling go() from within a loop(), that loop doesn't get cleared but keeps running. To reproduce:

const k = kaboom()

k.scene('start', () => {
  let count = 0

  k.loop(1, () => {
    k.go('main', ++count)
  })
})

k.scene('main', count => {
  k.add([
    k.text(`Entered main scene ${count}`)
  ])
})

k.start('start')

Cheers! :)

Edit: Actually, this can also be induced by just calling loop() right after go() -- inside wait(), curScene() then already returns the next scene to which the loop getting added:

k.scene('start', () => {
  k.go('main')
  k.loop(1, () => console.log('loop'))
})

k.scene('main', () => {
  k.add([
    k.text('Entered main scene')
  ])
})

No collision detection in RPG demo - add an option in the moveleft/right shortcut?

In the RPG demo the player can move through walls. This is because of the player.moveLeft etc does not take into consideration solid objects. Can you add some option in the moveLeft /moveRight etc. shortcut to stop if the movement would have if it overlaps with a solid object? Or in some way account for the solid walls.

References:

https://kaboomjs.com/examples#rpg

moveLeft() {

Support for ascii symbols like "โ™ฅ" in text?

Not sure if this is a bug or a feature request.

I was working on an RPG where I wanted to show the heart symbol in text ( yes I know I could do images, but this was faster for the implementation ) But when I tried to render ascii symbols - nothing showed up... is this a limitation of the engine or of the font?

Example replit : https://replit.com/@triptych/DeafeningDesertedAdmins#scenes/main.js

add([
  text("ascii text? Heart: โ™ฅ"),
  pos(10,10)
])

image

Scene graph?

Exciting framework! Is there a way to accomplish a scene graph: ie creating parent/child relationships between sprites? (For example, a rotating turret that is a child of a parent tank.)

Resolve and solid are incompatible

My 7-year-old has started his first game and a problem emerged:

He wants the tanks to bump into each other and not pass under each other. But adding solid() to each and calling resolve() on each causes both to instantly zoom upward off the screen. How do you make two objects that move around not overlap ever?

Grid Movement resolve always moves left

The grid movement methods, moveLeft, moveRight, ... alway place the object in the center of the next grid, when resolving the position, the minimum overlap is equidistant in all directions, and when entering the switch to adjust the position the first case is always matched for right and the object is moved left.

As a workaround, I can resolve on movement and check for the presence of targets occupying the grid position

keyPress(["left", "a"], () => {
    player.moveLeft()
    const targets = player.resolve()
    if (targets.length
        && targets.find(t => t.obj.gridPos.x === player.gridPos.x && t.obj.gridPos.y === player.gridPos.y)
    ) {
        player.moveRight()
    }
})

If the object is being moved using the grid movement method, perhaps a last position could be stored that resolve could look to when the object has a gridPos property, and in the event of a collision with another gridPos containing object, if they are occupying the same position, the last position could be restored?

I believe the assumption here is that an object is exclusively moved with grid movement or regular movement and not a mix of both.

more examples

I saw this on Hacker News, is great!

I'm having to guess a lot of stuff for now but it's early days. I found out changing direction...

obj.use(scale(-1, 1)) // going from right to left movement

but could use some more explicit examples OR more method but it's early days all good.

thx!

Position check for touch events "lagging"

Hi,

the position check for touch events is "lagging"; meaning if you add a click listener to an object, the first tap on that object will correctly trigger a click event, however an immediately following tap anywhere else will still trigger a click event on the same object.

Best try it yourself by alternatingly turning off and on "fx" and "music" here (on a mobile device, obviously; the chrome device emulator will do as well though):

import kaboom from 'kaboom'

export const k = kaboom({
  fullscreen: true,
  clearColor: 'black'
})

k.scene('main', () => {
  k.add([
    k.text('fx', 32),
    k.color(1, 1, 1),
    k.pos(0, 0),
    'control'
  ])

  k.add([
    k.text('music', 32),
    k.color(1, 1, 1),
    k.pos(0, 64),
    'control'
  ])

  k.every('control', control => {
    let isActive = false

    control.clicks(() => {
      isActive = !isActive
      control.color = k.rgb(...isActive ? [1, 0, 0] : [1, 1, 1])
    })
  })
})

k.start('main')

Cheers!

kaboom.debug.hoverInfo doesn't seem to respect camera position

Can be seen in https://kaboomjs.com/examples#level

Expected behavior:
I should see info on an object after hovering over it regardless of how the camera is positioned.

Observed behavior:
image
image

See cursor position in the above images. Hover calculations appear to be happening irrespective of the current camera transform. As such, you have to position your mouse in unintuitive positions to hover objects.

(By the way - Thank you for the excellent library!)

Action priorities

Firstly, love the library, so simple and elegant.

When updating the camera position inside an object action, objects whose update phase have passed aren't rendered in the correct position that accounts for the updated camera vector.

A work-around is to add a "camera" tagged object as the first or last object so that either it's action runs before all other objects or that the camera is moved at the end of update.

I don't know that adding a priority number as an argument to the add calls would be better, or adding a "lateUpdate" event in addition to the current "update". The work-around isn't all that bad, it just might not be intuitive.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.