{"id":15765175,"url":"https://github.com/thorwebdev/supabase-realtime-kaboom-multiplayer-game","last_synced_at":"2025-03-31T10:34:02.527Z","repository":{"id":77094471,"uuid":"458441202","full_name":"thorwebdev/supabase-realtime-kaboom-multiplayer-game","owner":"thorwebdev","description":"Build a Realtime Multiplayer Browser Game with Kaboomjs, Replit, and Supabase!","archived":false,"fork":false,"pushed_at":"2022-02-23T14:25:24.000Z","size":6874,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-26T02:51:58.790Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://supareplmultiplayer.thorwebdev.repl.co/#","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thorwebdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-12T06:30:32.000Z","updated_at":"2022-05-09T08:22:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"169ea210-2af6-422e-a7d6-7956694f09d9","html_url":"https://github.com/thorwebdev/supabase-realtime-kaboom-multiplayer-game","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thorwebdev","download_url":"https://codeload.github.com/thorwebdev/supabase-realtime-kaboom-multiplayer-game/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246454068,"owners_count":20780065,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-04T12:24:49.883Z","updated_at":"2025-03-31T10:34:02.497Z","avatar_url":"https://github.com/thorwebdev.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![kaboom](learn/kaboom.png)\n\nWelcome! Kaboom is a JavaScript library that helps you make games fast and fun :D\n\nThis is an intro tutorial that will cover the basic concepts and make a very simple [Chrome Dino](https://en.wikipedia.org/wiki/Dinosaur_Game) - ish game.\n\n![game](learn/game.png)\n\n(scroll to bottom to see / copy the full game code)\n\nLet's start by initializing the context with the `kaboom()` function.\n\n```js\nkaboom()\n```\n\nThis should give you a blank canvas with a nice checkerboard pattern like this\n\n![empty](learn/empty.png)\n\nThen let's add some stuff to screen, like an image. Copy this piece of code to your editor and see what happens when you run the game.\n\n```js\n// load a sprite \"bean\" from an image\nloadSprite(\"bean\", \"sprites/bean.png\")\n\n// add something to screen\nadd([\n\tsprite(\"bean\"),\n\tpos(80, 40),\n])\n```\n\nIntroducing Frog the \"Bean\"! A happy frog that enjoys life. You'll see Bean a lot around here.\n\n![bean](learn/bean.png)\n\nBefore explaining what this code does, let's try adding some more stuff to it and see what happens:\n\n```js\n// add something to screen\nadd([\n\tsprite(\"bean\"),\n\tpos(80, 40),\n\tscale(3),\n\trotate(30),\n\tcolor(0, 0, 255),\n])\n```\n\nFeel free to tweak some parameters and see how it affects what happens on screen.\n\nIn Kaboom, each game object is composed from multiple components. Each component will give the game obj certain functionality.\n\n\u003e A game object is basically any character in the game, like the player character, a bullet, a rock, a cloud\n\nFor example, some component might decide what's the shape, some components might decide if it should subject to gravity, some components might decide what color it is, some component might decide how long it can live.\n\n![comps](learn/comps.png)\n\n\nIf you're having trouble understanding, consider this Human Bean:\n\n![humanbean](learn/humanbean.png)\n\nHuman are also composed from a list of components, each component provides different functionalities, which is exactly what component means in Kaboom. `add()` is the function you use to assemble all the components into a game object in kaboom:\n\n![assemble](learn/assemble.png)\n\nIt's actually kinda like playing with lego pieces! Let's keep this in mind and start making the actual player character in our game:\n\n```js\n// putting together our player character\nconst bean = add([\n\tsprite(\"bean\"),\n\tpos(80, 40),\n\tarea(),\n\tbody(),\n])\n\n// .jump() when \"space\" key is pressed\nonKeyPress(\"space\", () =\u003e {\n\tbean.jump()\n})\n```\n\nLet's see what components we're using:\n- `sprite()` makes it render as a sprite, with the `\"bean\"` sprite we just loaded with `loadSprite()`\n- `pos()` gives it a position on screen, at X: 80 Y: 40\n- `area()` gives it a collider area, so we can check for collisions with other characters later on\n- `body()` gives it a physical body, making it fall due to gravity and ability to jump\n\nWe're also testing out our player character with a little interaction here. `onKeyPress()` registers an event that runs every time user presses a certain key. In this case, we're calling the `.jump()` method (which is provided by the `body()` component) when `\"space\"` key is pressed. Go ahead and slap that space key!\n\nWith the `body()` component, our Bean is going to keep falling into oblivion if we don't hit \"space\" key enough. Let's add a solid platform for Bean to land on.\n\n```js\n// add platform\nadd([\n\trect(width(), 48),\n\tpos(0, height() - 48),\n\toutline(4),\n\tarea(),\n\tsolid(),\n\tcolor(127, 200, 255),\n])\n```\n\nWoah! That looks like a lot, but it's actually really simple, let's look at each component\n\n- `rect()` renders a triangle. It accepts 2 arguments, the width and height, which we give it the game width (returned by `width()`) and height of 48 pixels\n- `pos()` position. We give it a x: 0 and y: `height() - 48` so it sits right on the bottom of the screen\n- `outline()` renders an outline of `4` pixels\n- `area()` adds a collider to it\n- `solid()` makes other objects impossible to pass through\n- `color()` makes it render with an RGB color, we give it a R: 127 G: 200 B: 255 which is a blue-ish color\n\nPretty straightforward! Refresh the game and you should see our Bean is now safely landed on a solid blue platform.\n\n![land](learn/land.png)\n\nLet's also make sure our Bean can only jump when grounded.\n\n```js\nonKeyPress(\"space\", () =\u003e {\n\tif (bean.grounded()) {\n\t\tbean.jump();\n\t}\n});\n```\n\n`grounded()` is another function provided by `body()` component which checks if currently landed on a platform. Now our game is slightly more physically correct.\n\nBean loves challanges. Let's start adding in obstacles to jump over! Time to build a game object from components again.\n\n```js\n// add tree\nadd([\n\trect(48, 64),\n\tarea(),\n\toutline(4),\n\tpos(width(), height() - 48),\n\torigin(\"botleft\"),\n\tcolor(255, 180, 255),\n\tmove(LEFT, 240),\n]);\n```\n\nA lot of these we have already seen you should know what they do, but some new ones here:\n- `origin()` defines the origin point of positioning. By default `pos()` defines the top left point of the shape, here we change it to the bottom left point because we want it to be just above the platform, so we give it Y position of `height() - 48`\n- `move()` makes it move towards a direction infinitely. In this case we move towards the `LEFT` by `480` pixels per second\n\n![tree](learn/tree.png)\n\nChallenger appears! Try jumping over it.\n\nOh but it's.. not really fun! Or rather, there's no feedback to whether we managed to jump over the ramp. Let's add some feedback.\n\nTo do this we'll need to check for collision between the two.\n\nFirst we'll need to give the tree a tag. Any game object can have any number of tags, they're kinda like components but much more light weight. We often use tags to quickly describe behaviors for a group of objects.\n\n```js\n// add tree\nadd([\n\trect(48, 64),\n\tarea(),\n\toutline(4),\n\tpos(width(), height() - 48),\n\torigin(\"botleft\"),\n\tcolor(255, 180, 255),\n\tmove(LEFT, 240),\n\t\"tree\", // add a tag here\n]);\n```\n\nTo add a tag we simply put a string in the component array. Then we can check for collision between Bean and any object with tag \"tree\".\n\n```js\nbean.onCollide(\"tree\", () =\u003e {\n\taddKaboom(bean.pos);\n\tshake();\n});\n```\n\n`.onCollide()` is a function provided by the `area()` component. It registers an event that runs every time the object collides with another object with a certain tag, passed by the first argument. In this case, it means every time Bean collides with another game obj with tag `\"tree\"`, run the callback.\n\nInside the callback we're doing 2 things. `addKaboom()` spawns an explosion animation which is basically kaboom's logo, it accepts 1 argument the position to spawn, which we pass in the player's current position with `.pos` (which is provided by the `pos()` component).\n\nThe second thing is `shake()`, which just shakes the screen,\n\n![hit](learn/hit.gif)\n\nHere's a trick. Try pressing `F1` in the game. See all the blue outlines? This is inspect mode and it'll show all the bounding boxes of every game obj with `area()` component. Also try hovering over each game object to inspect its states like position and tags.\n\n![inspect](learn/inspect.png)\n\nNow it's time to add more trees. How can we keep them spawning constantly?\n\nLet's try the `loop()` function, which performs an action every x seconds.\n\n```js\nloop(1, () =\u003e {\n\t// add tree\n\tadd([\n\t\trect(48, 64),\n\t\tarea(),\n\t\toutline(4),\n\t\tpos(width(), height() - 48),\n\t\torigin(\"botleft\"),\n\t\tcolor(255, 180, 255),\n\t\tmove(LEFT, 240),\n\t\t\"tree\", // add a tag here\n\t]);\n});\n```\n\nLet's just put the tree adding code inside a `loop()`. The first argument is the time in seconds here, so it'll spawn a tree every 1 seconds.\n\nSick! Lots of trees coming to you now. Now we already have most of the game mechanics done. Some improvements we can make:\n\n1. It might be better if trees all have different random heights. We can use `rand()` to assign different value to the tree's rect height:\n\n```js\nrect(48, rand(24, 64)),\n```\n\n2. It'll be more fun if the trees spawn at different intervals. We cannot do that from `loop()`, but we can compose that with recursive `wait()`s, which waits for x seconds to execute some code.\n\n```js\nfunction spawnTree() {\n\tadd([\n\t\t// the tree components\n\t]);\n\twait(rand(0.5, 1.5), () =\u003e {\n\t\tspawnTree();\n\t});\n}\n\nspawnTree();\n```\n\nSee? We're calling `spawnTree()` recursively / endlessly, with a random interval between 0.5 - 1.5 seconds each time.\n\nBefore adding a score counter, let's actually complete the game loop first, by sending player to a gameover scene when they hit a tree. We can achieve this with kaboom's `scene()` system\n\n```js\nscene(\"game\", () =\u003e {\n\tadd([\n\t\tsprite(\"bean\"),\n\t])\n})\n\nscene(\"lose\", () =\u003e {\n\tadd([\n\t\ttext(\"Game Over\"),\n\t])\n})\n\ngo(\"game\")\n```\n\nConsider this example above, we're declaring 2 scenes here, \"game\" and \"lose\". The function we pass to `scene()` is the function to run when this scene is activated (by `go()`). In this case, we want to add a \"bean\" sprite on \"game\" scene, and want to add a \"Game Over\" text on the \"lose\" scene.\n\nLet's first move everything game code we have into a scene.\n\n```js\n// don't move these init / loader functions\nkaboom()\nloadSprite(\"bean\", \"sprites/bean.png\");\n\nscene(\"game\", () =\u003e {\n\t// add bean\n\t// add platform\n\t// spawn trees\n});\n\ngo(\"game\")\n```\n\nTry this, this shouldn't change any of your game's content.\n\nThen we can add a \"lose\" scene independent to your core game content here.\n\n```js\nscene(\"lose\", () =\u003e {\n\tadd([\n\t\ttext(\"Game Over\"),\n\t\tpos(center()),\n\t\torigin(\"center\"),\n\t])\n})\n```\n\nSo in the \"lose\" scene, we'll add a piece of text in the center says \"Game Over\" (`text()` is a component that renders text). Go ahead and go to this scene when player collides with a tree:\n\n```js\nplayer.onCollide(\"tree\", () =\u003e {\n\taddKaboom(bean.pos);\n\tshake();\n\tgo(\"lose\"); // go to \"lose\" scene here\n});\n```\n\nOk! Now we've arrived at the final part of our game: score counter.\n\n```js\nlet score = 0;\nconst scoreLabel = add([\n\ttext(score),\n\tpos(24, 24)\n])\n```\n\nHere we've declared a number variable to store the score, and added a game obj with `text()` component to display the text.\n\nLet's keep it simple and just use time as score.\n\n```js\n// increment score every frame\nonUpdate(() =\u003e {\n\tscore++;\n\tscoreLabel.text = score;\n});\n```\n\nWe can use the `onUpdate()` function, which takes a function, and runs it every frame. In this case we're going to increment the score, and update the score label's text every frame.\n\n(todo)\n\nFull game code here:\n\n```js\nimport kaboom from \"kaboom\";\n\nconst FLOOR_HEIGHT = 48;\nconst JUMP_FORCE = 800;\nconst SPEED = 480;\n\n// initialize context\nkaboom();\n\n// load assets\nloadSprite(\"bean\", \"sprites/bean.png\");\n\nscene(\"game\", () =\u003e {\n\n\t// define gravity\n\tgravity(2400);\n\n\t// add a game object to screen\n\tconst player = add([\n\t\t// list of components\n\t\tsprite(\"bean\"),\n\t\tpos(80, 40),\n\t\tarea(),\n\t\tbody(),\n\t]);\n\n\t// floor\n\tadd([\n\t\trect(width(), FLOOR_HEIGHT),\n\t\toutline(4),\n\t\tpos(0, height()),\n\t\torigin(\"botleft\"),\n\t\tarea(),\n\t\tsolid(),\n\t\tcolor(127, 200, 255),\n\t]);\n\n\tfunction jump() {\n\t\tif (player.grounded()) {\n\t\t\tplayer.jump(JUMP_FORCE);\n\t\t}\n\t}\n\n\t// jump when user press space\n\tonKeyPress(\"space\", jump);\n\tonClick(jump);\n\n\tfunction spawnTree() {\n\n\t\t// add tree obj\n\t\tadd([\n\t\t\trect(48, rand(32, 96)),\n\t\t\tarea(),\n\t\t\toutline(4),\n\t\t\tpos(width(), height() - FLOOR_HEIGHT),\n\t\t\torigin(\"botleft\"),\n\t\t\tcolor(255, 180, 255),\n\t\t\tmove(LEFT, SPEED),\n\t\t\t\"tree\",\n\t\t]);\n\n\t\t// wait a random amount of time to spawn next tree\n\t\twait(rand(0.5, 1.5), spawnTree);\n\n\t}\n\n\t// start spawning trees\n\tspawnTree();\n\n\t// lose if player collides with any game obj with tag \"tree\"\n\tplayer.onCollide(\"tree\", () =\u003e {\n\t\t// go to \"lose\" scene and pass the score\n\t\tgo(\"lose\", score);\n\t\tburp();\n\t\taddKaboom(player.pos);\n\t});\n\n\t// keep track of score\n\tlet score = 0;\n\n\tconst scoreLabel = add([\n\t\ttext(score),\n\t\tpos(24, 24),\n\t]);\n\n\t// increment score every frame\n\tonUpdate(() =\u003e {\n\t\tscore++;\n\t\tscoreLabel.text = score;\n\t});\n\n});\n\nscene(\"lose\", (score) =\u003e {\n\n\tadd([\n\t\tsprite(\"bean\"),\n\t\tpos(width() / 2, height() / 2 - 80),\n\t\tscale(2),\n\t\torigin(\"center\"),\n\t]);\n\n\t// display score\n\tadd([\n\t\ttext(score),\n\t\tpos(width() / 2, height() / 2 + 80),\n\t\tscale(2),\n\t\torigin(\"center\"),\n\t]);\n\n\t// go back to game with space is pressed\n\tonKeyPress(\"space\", () =\u003e go(\"game\"));\n\tonClick(() =\u003e go(\"game\"));\n\n});\n\ngo(\"game\");\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthorwebdev%2Fsupabase-realtime-kaboom-multiplayer-game/lists"}