From 3a73baba33c0ec168cb31989809f1251e7afe55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?amyspark-ng=20=E2=9C=A8?= <92493175+amyspark-ng@users.noreply.github.com> Date: Mon, 14 Oct 2024 11:44:17 -0500 Subject: [PATCH 1/5] docs: animate example --- examples/add.js | 2 +- examples/ai.js | 6 +++-- examples/animation.js | 51 +++++++++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/examples/add.js b/examples/add.js index e124edb6..7ebceeee 100644 --- a/examples/add.js +++ b/examples/add.js @@ -21,7 +21,7 @@ const player = add([ anchor("center"), // anchor() component defines the pivot point (defaults to "topleft") ]); -// .onUpdate() is a method on all game objects, it registers an event that runs every frame +// .onUpdate() is a method that's found in all game objects, it registers an event that runs every frame player.onUpdate(() => { // .angle is a property provided by rotate() component, here we're incrementing the angle by 120 degrees per second, dt() is the time elapsed since last frame in seconds player.angle += 120 * dt(); diff --git a/examples/ai.js b/examples/ai.js index efdf2a61..5c18fd1e 100644 --- a/examples/ai.js +++ b/examples/ai.js @@ -54,17 +54,19 @@ enemy.onStateEnter("attack", async () => { ]); } + // Waits 1 second to make the enemy enter in "move" state await wait(1); enemy.enterState("move"); }); +// When we enter "move" state, we stay there for 2 sec and then go back to "idle" enemy.onStateEnter("move", async () => { await wait(2); enemy.enterState("idle"); }); -// Like .onUpdate() which runs every frame, but only runs when the current state is "move" -// Here we move towards the player every frame if the current state is "move" +// .onStateUpdate() will run every frame, but only when the current state is "move" +// We move the enemy in the direction of the player enemy.onStateUpdate("move", () => { if (!player.exists()) return; const dir = player.pos.sub(enemy.pos).unit(); diff --git a/examples/animation.js b/examples/animation.js index cb041e03..2b63a0d5 100644 --- a/examples/animation.js +++ b/examples/animation.js @@ -3,10 +3,10 @@ // Start kaboom kaplay(); -loadSprite("bean", "sprites/bean.png"); -loadSprite("bag", "sprites/bag.png"); +// We use the default function to load the bean sprite +loadBean(); -// Rotating +// We add a bean that rotates with the animate component const rotatingBean = add([ sprite("bean"), pos(50, 50), @@ -15,15 +15,15 @@ const rotatingBean = add([ animate(), ]); -// Trying sprite change -rotatingBean.sprite = "bag"; - +// We use the 'animate()' function provided by the animate component +// This will rotate the bean from 0 to 360 degrees in 2 seconds +// The direction "forwards" means it will go back to 0 when it ends, which makes this a loop rotatingBean.animate("angle", [0, 360], { duration: 2, direction: "forward", }); -// Moving right to left using ping-pong +// Now we'll move this bean from left to right const movingBean = add([ sprite("bean"), pos(50, 150), @@ -31,6 +31,8 @@ const movingBean = add([ animate(), ]); +// This will animate the bean from left to right in 2 seconds +// The direction "ping-pong" means that when it goes to the right, it will move back to the left movingBean.animate("pos", [vec2(50, 150), vec2(150, 150)], { duration: 2, direction: "ping-pong", @@ -44,12 +46,14 @@ const secondMovingBean = add([ animate({ relative: true }), ]); +// The fact that is relative, means that instead of setting the bean to these positions (vec2(50, 150), vec2(150, 150)) +// It will ADD those positions to the position the bean was spawned in secondMovingBean.animate("pos", [vec2(50, 150), vec2(150, 150)], { duration: 2, direction: "ping-pong", }); -// Changing color using a color list +// We'll change the color of the bean using a list of colors const coloringBean = add([ sprite("bean"), pos(50, 300), @@ -58,11 +62,14 @@ const coloringBean = add([ animate(), ]); +// It will animate the color the bean color from white to red to green to blue to white +// In 8 seconds, and when it's over i'll start over again coloringBean.animate("color", [WHITE, RED, GREEN, BLUE, WHITE], { duration: 8, + direction: "forward", }); -// Changing opacity using an opacity list +// We'll change the opacity of the bean using a list of opacities const opacitingBean = add([ sprite("bean"), pos(150, 300), @@ -71,12 +78,14 @@ const opacitingBean = add([ animate(), ]); +// We'll animate the opacity from 1, to 0, to 1 during 8 seconds +// This time, we'll be using an easing! opacitingBean.animate("opacity", [1, 0, 1], { duration: 8, easing: easings.easeInOutCubic, }); -// Moving in a square like motion +// We'll move this bean in a square shape const squaringBean = add([ sprite("bean"), pos(50, 400), @@ -84,6 +93,7 @@ const squaringBean = add([ animate(), ]); +// Passing an array of keyframes (the positions) it'll move in a square shape squaringBean.animate( "pos", [ @@ -96,7 +106,7 @@ squaringBean.animate( { duration: 8 }, ); -// Moving in a square like motion, but with custom spaced keyframes +// We'll move the bean in a square shape again, but this time we'll be using timing const timedSquaringBean = add([ sprite("bean"), pos(50, 400), @@ -104,6 +114,8 @@ const timedSquaringBean = add([ animate(), ]); +// This will move the bean in the same positions as before in the same time +// But the timings will make the movement from one keyframe to another quicker or slower timedSquaringBean.animate( "pos", [ @@ -125,6 +137,7 @@ timedSquaringBean.animate( }, ); +// We'll move this bean in a curve // Using spline interpolation to move according to a smoothened path const curvingBean = add([ sprite("bean"), @@ -134,6 +147,7 @@ const curvingBean = add([ rotate(0), ]); +// This will move bean in these positions, but using a different interpolation curvingBean.animate( "pos", [ @@ -146,17 +160,20 @@ curvingBean.animate( { duration: 8, direction: "ping-pong", interpolation: "spline" }, ); +// We'll animate a little bean to rotate around the curvingBean! +// Here we're creating a pivot const littleBeanPivot = curvingBean.add([ animate(), rotate(0), - named("littlebeanpivot"), ]); +// And animating the pivot, you know this! littleBeanPivot.animate("angle", [0, 360], { duration: 2, direction: "reverse", }); +// We'll animate a little bean to rotate around the pivot const littleBean = littleBeanPivot.add([ sprite("bean"), pos(50, 50), @@ -164,19 +181,21 @@ const littleBean = littleBeanPivot.add([ scale(0.25), animate(), rotate(0), - named("littlebean"), ]); +// And here we animate the little bean littleBean.animate("angle", [0, 360], { duration: 2, direction: "forward", }); -console.log(JSON.stringify(serializeAnimation(curvingBean, "root"), "", 2)); +// We'll the serialize an animation and log it to the console so we can see all the current animation channels +console.log(JSON.stringify(serializeAnimation(curvingBean, "root"), null, 2)); +// Debug piece of code that draws a line in the curve that the curving bean goes through, don't mind it /*onDraw(() => { drawCurve(t => evaluateCatmullRom( - vec2(200, 400),\ + vec2(200, 400), vec2(250, 500), vec2(300, 400), vec2(350, 500), t), { color: RED }) @@ -185,4 +204,4 @@ console.log(JSON.stringify(serializeAnimation(curvingBean, "root"), "", 2)); vec2(250, 500), vec2(300, 400), vec2(350, 500)), { color: GREEN }) -})*/ +})*/ \ No newline at end of file From c70f4795e395c990e8da6683811bf752e860f352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?amyspark-ng=20=E2=9C=A8?= <92493175+amyspark-ng@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:08:28 -0500 Subject: [PATCH 2/5] docs: more example comments --- examples/animation.js | 2 +- examples/audio.js | 4 +- examples/bench.js | 5 +- examples/binding.js | 75 +++++++++------- examples/burp.js | 2 +- examples/button.js | 6 +- examples/camera.js | 15 ++-- examples/children.js | 2 + examples/collision.js | 2 +- examples/collisionshapes.js | 13 +++ examples/component.js | 166 +++++++++++++++++++----------------- examples/concert.js | 4 +- examples/confetti.js | 2 + 13 files changed, 174 insertions(+), 124 deletions(-) diff --git a/examples/animation.js b/examples/animation.js index 2b63a0d5..6e43c1f1 100644 --- a/examples/animation.js +++ b/examples/animation.js @@ -204,4 +204,4 @@ console.log(JSON.stringify(serializeAnimation(curvingBean, "root"), null, 2)); vec2(250, 500), vec2(300, 400), vec2(350, 500)), { color: GREEN }) -})*/ \ No newline at end of file +})*/ diff --git a/examples/audio.js b/examples/audio.js index 3ed2ec00..d41d79a1 100644 --- a/examples/audio.js +++ b/examples/audio.js @@ -3,11 +3,12 @@ // audio playback & control kaplay({ - // Don't pause audio when tab is not active + // This makes it so the audio doesn't pause when the tab is changed backgroundAudio: true, background: [0, 0, 0], }); +// Loads the bell sound, and OtherworldlyFoe sound loadSound("bell", "/examples/sounds/bell.mp3"); loadSound("OtherworldlyFoe", "/examples/sounds/OtherworldlyFoe.mp3"); @@ -51,6 +52,7 @@ onKeyPressRepeat("left", () => music.speed -= 0.1); onKeyPressRepeat("right", () => music.speed += 0.1); onKeyPress("m", () => music.seek(4.24)); +// We store some keys in a string const keyboard = "awsedftgyhujk"; // Simple piano with "bell" sound and the second row of a QWERTY keyboard diff --git a/examples/bench.js b/examples/bench.js index 34e54ad5..18e15b85 100644 --- a/examples/bench.js +++ b/examples/bench.js @@ -1,12 +1,14 @@ // @ts-config -// bench marking sprite rendering performance +// Bench marking sprite rendering performance +// We use this example to test and bench the performance of kaplay rendering kaplay(); loadSprite("bean", "sprites/bean.png"); loadSprite("bag", "sprites/bag.png"); +// Adds 5 thousand objects which can be a bean or a bag in random positions for (let i = 0; i < 5000; i++) { add([ sprite(i % 2 === 0 ? "bean" : "bag"), @@ -17,6 +19,7 @@ for (let i = 0; i < 5000; i++) { onDraw(() => { drawText({ + // You can get the current fps with debug.fps() text: debug.fps(), pos: vec2(width() / 2, height() / 2), anchor: "center", diff --git a/examples/binding.js b/examples/binding.js index 23a57cea..6a49d9b4 100644 --- a/examples/binding.js +++ b/examples/binding.js @@ -1,58 +1,69 @@ // @ts-check +// You can set the input bindings for your game! kaplay({ - buttons: { - "jump": { - gamepad: ["south"], - keyboard: ["up", "w"], - mouse: "left", - }, - "inspect": { - gamepad: "east", - keyboard: "f", - mouse: "right", - }, - }, + buttons: { + // Buttons for jumping + "jump": { + // When using a gamepad the button for jumping will be south + gamepad: ["south"], + // When using a keyboard the button will be "up" or "w" + keyboard: ["up", "w"], + // When using a mouse the button will be "left" + mouse: "left", + }, + // Buttons for inspecting + "inspect": { + gamepad: "east", + keyboard: "f", + mouse: "right", + }, + }, }); -loadSprite("bean", "/sprites/bean.png"); +loadBean() // Set the gravity acceleration (pixels per second) setGravity(1600); // Add player game object const player = add([ - sprite("bean"), - pos(center()), - area(), - // body() component gives the ability to respond to gravity - body(), + sprite("bean"), + pos(center()), + area(), + // body() component gives the ability to respond to gravity + body(), ]); // Add a platform to hold the player add([ - rect(width(), 48), - outline(4), - area(), - pos(0, height() - 48), - // Give objects a body() component if you don't want other solid objects pass through - body({ isStatic: true }), + rect(width(), 48), + outline(4), + area(), + pos(0, height() - 48), + // Give objects a body() component if you don't want other solid objects pass through + body({ isStatic: true }), ]); +// Adds an object with a text add([ - text("Press jump button", { width: width() / 2 }), - pos(12, 12), + text("Press jump button", { width: width() / 2 }), + pos(12, 12), ]); +// This runs when the button for "jump" is pressed (will be on any input device) onButtonPress("jump", () => { - debug.log(getLastInputDeviceType()); + // You can get the type of device that the last input was inputted in! + debug.log(getLastInputDeviceType()); - if (player.isGrounded()) { - // .jump() is provided by body() - player.jump(); - } + // Now we'll check if the player is on the ground to make it jump + if (player.isGrounded()) { + // .jump() is provided by body() + player.jump(); + } }); +// When the button for inspecting is pressed we will log in the debug console for our game the text "inspecting" onButtonDown("inspect", () => { - debug.log("inspecting"); + debug.log("inspecting"); }); diff --git a/examples/burp.js b/examples/burp.js index d1865f20..7badf9b6 100644 --- a/examples/burp.js +++ b/examples/burp.js @@ -11,4 +11,4 @@ add([ ]); // burp() on click / tap for our friends on mobile -onClick(burp); +onClick(() => burp()); diff --git a/examples/button.js b/examples/button.js index ef441b91..c06a0cec 100644 --- a/examples/button.js +++ b/examples/button.js @@ -1,6 +1,6 @@ // @ts-check -// Simple Button UI +// Simple UI and setup for buttons kaplay({ background: [135, 62, 132], @@ -9,7 +9,8 @@ kaplay({ // reset cursor to default on frame start for easier cursor management onUpdate(() => setCursor("default")); -function addButton(txt, p, f) { +// Function that adds a button to the game with a given text, position and function +function addButton(txt = "start game", p = vec2(200, 100), f = () => debug.log("hello")) { // add a parent background object const btn = add([ rect(240, 80, { radius: 8 }), @@ -51,5 +52,6 @@ function addButton(txt, p, f) { return btn; } +// Adds the buttons with the function we added addButton("Start", vec2(200, 100), () => debug.log("oh hi")); addButton("Quit", vec2(200, 200), () => debug.log("bye")); diff --git a/examples/camera.js b/examples/camera.js index c1bf9974..63e43efd 100644 --- a/examples/camera.js +++ b/examples/camera.js @@ -12,10 +12,12 @@ loadSprite("grass", "/sprites/grass.png"); loadSound("score", "/examples/sounds/score.mp3"); const SPEED = 480; +let score = 0; +// Set the gravity acceleration (pixels per second) setGravity(2400); -// Setup a basic level +// Setup a basic level, check the 'level' example for more info const level = addLevel([ "@ = $", "=======", @@ -49,17 +51,20 @@ const level = addLevel([ // Get the player object from tag const player = level.get("player")[0]; +// Will run every frame player.onUpdate(() => { // Set the viewport center to player.pos camPos(player.worldPos()); }); +// Set the viewport center to player.pos whenever their physics are resolved player.onPhysicsResolve(() => { - // Set the viewport center to player.pos camPos(player.worldPos()); }); +// When the player collides with a coin object player.onCollide("coin", (coin) => { + // It does these things destroy(coin); play("score"); score++; @@ -77,8 +82,6 @@ onKeyPress("space", () => { onKeyDown("left", () => player.move(-SPEED, 0)); onKeyDown("right", () => player.move(SPEED, 0)); -let score = 0; - // Add a ui layer with fixed() component to make the object // not affected by camera const ui = add([ @@ -91,7 +94,7 @@ ui.add([ pos(12), { update() { - this.text = score; + this.text = score.toString(); }, }, ]); @@ -100,4 +103,4 @@ onClick(() => { // Use toWorld() to transform a screen-space coordinate (like mousePos()) to // the world-space coordinate, which has the camera transform applied addKaboom(toWorld(mousePos())); -}); +}); \ No newline at end of file diff --git a/examples/children.js b/examples/children.js index 0b9bfc44..235c5a58 100644 --- a/examples/children.js +++ b/examples/children.js @@ -5,6 +5,7 @@ kaplay(); loadSprite("bean", "/sprites/bean.png"); loadSprite("ghosty", "/sprites/ghosty.png"); +// Adds the nucleus for the other children to get added to, it just means this is their parent const nucleus = add([ sprite("ghosty"), pos(center()), @@ -23,6 +24,7 @@ for (let i = 12; i < 24; i++) { ]); } +// Runs every frame nucleus.onUpdate(() => { nucleus.pos = mousePos(); diff --git a/examples/collision.js b/examples/collision.js index 3d1acb52..c685ba88 100644 --- a/examples/collision.js +++ b/examples/collision.js @@ -121,4 +121,4 @@ player.onUpdate(() => { // Can also be toggled by pressing F1 debug.inspect = true; -// Check out https://kaboomjs.com#AreaComp for everything area() provides +// Check out https://kaplayjs.com/doc/AreaComp/ for everything area() provides \ No newline at end of file diff --git a/examples/collisionshapes.js b/examples/collisionshapes.js index 907506c2..c58c3b4f 100644 --- a/examples/collisionshapes.js +++ b/examples/collisionshapes.js @@ -1,9 +1,12 @@ // @ts-check +// # How kaplay handles collisions with different shapes kaplay(); +// Set the gravity acceleration (pixels per second) setGravity(300); +// Adds a ground add([ pos(0, 400), rect(width(), 40), @@ -13,6 +16,7 @@ add([ // Continuous shapes loop(1, () => { + // Adds an object with a random shape add([ pos(width() / 2 + rand(-50, 50), 100), choose([ @@ -26,7 +30,16 @@ loop(1, () => { body(), offscreen({ destroy: true, distance: 10 }), ]); + + // getTreeRoot() gets the root of the game, the object that holds every other object + // This line basically means that if there are more than 20 objects, we destroy the last one if (getTreeRoot().children.length > 20) { destroy(getTreeRoot().children[1]); } + + /* The previous code can also be written as + if (get("*").length > 20) { + destroy(get("*")[1]); + } + */ }); diff --git a/examples/component.js b/examples/component.js index be542f52..f6caf6e3 100644 --- a/examples/component.js +++ b/examples/component.js @@ -1,100 +1,110 @@ // @ts-check -// Custom component +// How to make custom components kaplay kaplay(); -loadSprite("bean", "/sprites/bean.png"); +loadBean(); -// Components are just functions that returns an object that follows a certain format +// Components are just function that returns a js object that follows a certain format +// This object contains certain properties which then become available in your object to use function funky() { - // Can use local closed variables to store component state - let isFunky = false; - - return { - // ------------------ - // Special properties that controls the behavior of the component (all optional) - - // The name of the component - id: "funky", - // If this component depend on any other components - require: ["scale", "color"], - - // Runs when the host object is added to the game - add() { - // E.g. Register some events from other components, do some bookkeeping, etc. - }, - - // Runs every frame as long as the host object exists - update() { - if (!isFunky) return; - - // "this" in all component methods refers to the host game object - // Here we're updating some properties provided by other components - this.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)); - this.scale = vec2(rand(1, 2)); - }, - - // Runs every frame (after update) as long as the host object exists - draw() { - // E.g. Custom drawXXX() operations. - }, - - // Runs when the host object is destroyed - destroy() { - // E.g. Clean up event handlers, etc. - }, - - // Get the info to present in inspect mode - inspect() { - return isFunky ? "on" : "off"; - }, - - // ------------------ - // All other properties and methods are directly assigned to the host object - - getFunky() { - isFunky = true; - }, - }; + // Can use local closed variables to store component state + let isFunky = false; + + return { + // ------------------ + // Special properties that controls the behavior of the component (all optional) + + // These properties (id and require specially id) are handled by kaplay, id is the name of the component + // If you want to get all objects with this component you can do get("funky") + // Be careful to tag objects with what might be the id of a component + + id: "funky", // The name of the component + require: ["scale", "color"], // If this component depend on any other components + // If the you put components in require and attach this component to an object that doesn't have these components + // The game will throw an error + + // Runs when the host object is added to the game + add() { + // E.g. Register some events from other components, do some bookkeeping, etc. + }, + + // Runs every frame as long as the host object exists + update() { + if (!isFunky) return; + + // "this" in all component methods refers to the the game object this component is attached to + // Here we're updating some properties provided by other components + this.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)); + this.scale = vec2(rand(1, 2)); + }, + + // Runs every frame (after update) as long as the host object exists + draw() { + // E.g. Custom drawXXX() operations. + }, + + // Runs when the host object is destroyed + destroy() { + // E.g. Clean up event handlers, etc. + }, + + // When you press F1 you can get a list of inspect properties a component might provide for an object + // Here you can provide custom ones + inspect() { + return "funky: " + isFunky; + }, + + // ------------------ + // All other properties and methods are directly assigned to the host object + + // This means that the object is getting funky, not that you're getting the property funky lol! + getFunky() { + isFunky = true; + }, + }; } +// Adds an object with the funky component const bean = add([ - sprite("bean"), - pos(center()), - anchor("center"), - scale(1), - color(), - area(), - // Use our component here - funky(), - // Tags are empty components, it's equivalent to a { id: "friend" } - "friend", - // Plain objects here are components too and work the same way, except unnamed - { - coolness: 100, - friends: [], - }, + sprite("bean"), + pos(center()), + anchor("center"), + scale(1), + color(), + area(), + // Use our component here + funky(), + // Tags are empty components, it's equivalent to a { id: "friend" } + "friend", + // Plain objects here are components too and work the same way, except unnamed + { + coolness: 100, + friends: [], + }, ]); onKeyPress("space", () => { - // .coolness is from our unnamed component above - if (bean.coolness >= 100) { - // We can use .getFunky() provided by the funky() component now - bean.getFunky(); - } + // .coolness is from our plain object 'unnamed component' + if (bean.coolness >= 100) { + // We can use .getFunky() provided by the funky() component now + bean.getFunky(); + } }); onKeyPress("r", () => { - // .use() is on every game object, it adds a component at runtime - bean.use(rotate(rand(0, 360))); + // .use() is on every game object, it adds a component at runtime + bean.use(rotate(rand(0, 360))); }); onKeyPress("escape", () => { - // .unuse() removes a component from the game object - bean.unuse("funky"); + // .unuse() removes a component from the game object + // The tag is the one that appears on the id + bean.unuse("funky"); }); +// Adds a text object add([ - text("Press space to get funky", { width: width() }), - pos(12, 12), + text("Press space to get funky", { width: width() }), + pos(12, 12), ]); diff --git a/examples/concert.js b/examples/concert.js index ae0d674a..233d00be 100644 --- a/examples/concert.js +++ b/examples/concert.js @@ -8,13 +8,14 @@ kaplay({ font: "happy", }); +// Adds bean and all of this friends +loadBean(); loadSprite("bag", `/sprites/bag.png`); loadSprite("ghosty", "/sprites/ghosty.png"); loadSprite("bobo", `/sprites/bobo.png`); loadSprite("gigagantrum", "/sprites/gigagantrum.png"); loadSprite("tga", "/sprites/dino.png"); loadSprite("ghostiny", "/sprites/ghostiny.png"); -loadSprite("bean", "/sprites/bean.png"); loadSprite("note", "/sprites/note.png"); loadSprite("grass", "/sprites/grass.png"); loadSprite("cloud", "/sprites/cloud.png"); @@ -23,6 +24,7 @@ loadSound("bell", "/examples/sounds/bell.mp3"); loadSound("kaboom2000", "/examples/sounds/kaboom2000.mp3"); loadBitmapFont("happy", "/examples/fonts/happy_28x36.png", 28, 36); +// An array of friends const friends = [ "bag", "bobo", diff --git a/examples/confetti.js b/examples/confetti.js index 16d35b19..42a72a63 100644 --- a/examples/confetti.js +++ b/examples/confetti.js @@ -1,5 +1,7 @@ // @ts-check +// Confetti effect done manually (not using particle component) + kaplay(); const DEF_COUNT = 80; From 31f5f07698ddd4e59d26464bfe6f000c210486cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?amyspark-ng=20=E2=9C=A8?= <92493175+amyspark-ng@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:16:15 -0500 Subject: [PATCH 3/5] fix: some more formatting an examples --- examples/ai.js | 2 +- examples/animation.js | 2 +- examples/collision.js | 2 +- examples/dialog.js | 2 + examples/doublejump.js | 368 +++++++++++++++++++++------------------- examples/drag.js | 3 +- examples/draw.js | 4 +- examples/easing.js | 1 + examples/eatlove.js | 242 +++++++++++++------------- examples/egg.js | 2 +- examples/fadeIn.js | 1 + examples/flamebar.js | 2 +- examples/gravity.js | 2 +- examples/movement.js | 2 +- examples/raycaster3d.js | 2 +- examples/textInput.js | 2 +- 16 files changed, 330 insertions(+), 309 deletions(-) diff --git a/examples/ai.js b/examples/ai.js index 5c18fd1e..6273aaff 100644 --- a/examples/ai.js +++ b/examples/ai.js @@ -2,7 +2,7 @@ // Use state() component to handle basic AI -// Start kaboom +// Start kaplay kaplay(); // Load assets diff --git a/examples/animation.js b/examples/animation.js index 6e43c1f1..7abdfe61 100644 --- a/examples/animation.js +++ b/examples/animation.js @@ -1,6 +1,6 @@ // @ts-check -// Start kaboom +// Start kaplay kaplay(); // We use the default function to load the bean sprite diff --git a/examples/collision.js b/examples/collision.js index c685ba88..cd83c473 100644 --- a/examples/collision.js +++ b/examples/collision.js @@ -2,7 +2,7 @@ // Collision handling -// Start kaboom +// Start kaplay kaplay({ scale: 2, }); diff --git a/examples/dialog.js b/examples/dialog.js index 7653ec8c..9063de91 100644 --- a/examples/dialog.js +++ b/examples/dialog.js @@ -15,6 +15,7 @@ kaplay({ font: "happy", }); +// Loads all sprites loadSprite("bean", "/sprites/bean.png"); loadSprite("mark", "/sprites/mark.png"); loadSound("bean_voice", "examples/sounds/bean_voice.wav"); @@ -199,6 +200,7 @@ function startWriting(dialog, char) { }); } +// When the game finishes loading, the dialog will start updating onLoad(() => { updateDialog(); }); diff --git a/examples/doublejump.js b/examples/doublejump.js index b68a4f9d..dd34b8d9 100644 --- a/examples/doublejump.js +++ b/examples/doublejump.js @@ -1,207 +1,221 @@ // @ts-check +// How to use the doubleJump component in this little game kaplay({ - background: [141, 183, 255], + background: [141, 183, 255], }); +// Loads sprites loadSprite("bean", "/sprites/bean.png"); loadSprite("coin", "/sprites/coin.png"); loadSprite("grass", "/sprites/grass.png"); loadSprite("spike", "/sprites/spike.png"); loadSound("coin", "/examples/sounds/score.mp3"); +// Set the gravity acceleration (pixels per second) setGravity(4000); const PLAYER_SPEED = 640; const JUMP_FORCE = 1200; const NUM_PLATFORMS = 5; -// a spinning component for fun +// a spinning component for fun, for more info check the 'component' example function spin(speed = 1200) { - let spinning = false; - return { - require: ["rotate"], - update() { - if (!spinning) { - return; - } - this.angle -= speed * dt(); - if (this.angle <= -360) { - spinning = false; - this.angle = 0; - } - }, - spin() { - spinning = true; - }, - }; + let spinning = false; + return { + require: ["rotate"], + update() { + if (!spinning) { + return; + } + this.angle -= speed * dt(); + if (this.angle <= -360) { + spinning = false; + this.angle = 0; + } + }, + spin() { + spinning = true; + }, + }; } +// Setsup the game scene scene("game", () => { - const score = add([ - text("0", { size: 24 }), - pos(24, 24), - { value: 0 }, - ]); - - const bean = add([ - sprite("bean"), - area(), - anchor("center"), - pos(0, 0), - body({ jumpForce: JUMP_FORCE }), - doubleJump(), - rotate(0), - spin(), - ]); - - for (let i = 1; i < NUM_PLATFORMS; i++) { - add([ - sprite("grass"), - area(), - pos(rand(0, width()), i * height() / NUM_PLATFORMS), - body({ isStatic: true }), - anchor("center"), - "platform", - { - speed: rand(120, 320), - dir: choose([-1, 1]), - }, - ]); - } - - // go to the first platform - bean.pos = get("platform")[0].pos.sub(0, 64); - - function genCoin(avoid) { - const plats = get("platform"); - let idx = randi(0, plats.length); - // avoid the spawning on the same platforms - if (avoid != null) { - idx = choose([...plats.keys()].filter((i) => i !== avoid)); - } - const plat = plats[idx]; - add([ - pos(), - anchor("center"), - sprite("coin"), - area(), - follow(plat, vec2(0, -60)), - "coin", - { idx: idx }, - ]); - } - - genCoin(0); - - for (let i = 0; i < width() / 64; i++) { - add([ - pos(i * 64, height()), - sprite("spike"), - area(), - anchor("bot"), - scale(), - "danger", - ]); - } - - bean.onCollide("danger", () => { - go("lose"); - }); - - bean.onCollide("coin", (c) => { - destroy(c); - play("coin"); - score.value += 1; - score.text = score.value.toString(); - genCoin(c.idx); - }); - - // spin on double jump - bean.onDoubleJump(() => { - bean.spin(); - }); - - onUpdate("platform", (p) => { - p.move(p.dir * p.speed, 0); - if (p.pos.x < 0 || p.pos.x > width()) { - p.dir = -p.dir; - } - }); - - onKeyPress("space", () => { - bean.doubleJump(); - }); - - function move(x) { - bean.move(x, 0); - if (bean.pos.x < 0) { - bean.pos.x = width(); - } - else if (bean.pos.x > width()) { - bean.pos.x = 0; - } - } - - // both keys will trigger - onKeyDown("left", () => { - move(-PLAYER_SPEED); - }); - - onKeyDown("right", () => { - move(PLAYER_SPEED); - }); - - onGamepadButtonPress("south", () => bean.doubleJump()); - - onGamepadStick("left", (v) => { - move(v.x * PLAYER_SPEED); - }); - - let timeLeft = 30; - - const timer = add([ - anchor("topright"), - pos(width() - 24, 24), - text(timeLeft.toString()), - ]); - - onUpdate(() => { - timeLeft -= dt(); - if (timeLeft <= 0) { - go("win", score.value); - } - timer.text = timeLeft.toFixed(2); - }); + // This score textObject holds a value property in a plain object + const score = add([ + text("0", { size: 24 }), + pos(24, 24), + { value: 0 }, + ]); + + const bean = add([ + sprite("bean"), + area(), + anchor("center"), + pos(0, 0), + body({ jumpForce: JUMP_FORCE }), + // Adds the double jump component + doubleJump(), + rotate(0), + spin(), + ]); + + // Adds a num of platforms that go from left to right + for (let i = 1; i < NUM_PLATFORMS; i++) { + add([ + sprite("grass"), + area(), + pos(rand(0, width()), i * height() / NUM_PLATFORMS), + body({ isStatic: true }), + anchor("center"), + "platform", + { + speed: rand(120, 320), + dir: choose([-1, 1]), + }, + ]); + } + + // go to the first platform + bean.pos = get("platform")[0].pos.sub(0, 64); + + // Generates coins on those platforms + function genCoin(avoid) { + const plats = get("platform"); + let idx = randi(0, plats.length); + // avoid the spawning on the same platforms + if (avoid != null) { + idx = choose([...plats.keys()].filter((i) => i !== avoid)); + } + const plat = plats[idx]; + add([ + pos(), + anchor("center"), + sprite("coin"), + area(), + follow(plat, vec2(0, -60)), + "coin", + { idx: idx }, + ]); + } + + genCoin(0); + + for (let i = 0; i < width() / 64; i++) { + add([ + pos(i * 64, height()), + sprite("spike"), + area(), + anchor("bot"), + scale(), + "danger", + ]); + } + + bean.onCollide("danger", () => { + go("lose"); + }); + + bean.onCollide("coin", (c) => { + destroy(c); + play("coin"); + score.value += 1; + score.text = score.value.toString(); + genCoin(c.idx); + }); + + // The double jupm component provides us this function that runs when we double jump + bean.onDoubleJump(() => { + // So we can call the spin() method provided by the spin() component to spin + bean.spin(); + }); + + onUpdate("platform", (p) => { + p.move(p.dir * p.speed, 0); + if (p.pos.x < 0 || p.pos.x > width()) { + p.dir = -p.dir; + } + }); + + onKeyPress("space", () => { + bean.doubleJump(); + }); + + // Will move the bean left and right + function move(x) { + bean.move(x, 0); + if (bean.pos.x < 0) { + bean.pos.x = width(); + } + else if (bean.pos.x > width()) { + bean.pos.x = 0; + } + } + + // both keys will trigger + onKeyDown("left", () => { + move(-PLAYER_SPEED); + }); + + onKeyDown("right", () => { + move(PLAYER_SPEED); + }); + + // The south button will call the doubleJump, for more info on gamepads check the 'gamepad' example + onGamepadButtonPress("south", () => bean.doubleJump()); + + onGamepadStick("left", (v) => { + move(v.x * PLAYER_SPEED); + }); + + let timeLeft = 30; + + const timer = add([ + anchor("topright"), + pos(width() - 24, 24), + text(timeLeft.toString()), + ]); + + onUpdate(() => { + timeLeft -= dt(); + if (timeLeft <= 0) { + go("win", score.value); + } + timer.text = timeLeft.toFixed(2); + }); }); +// Sets up the scene where we win scene("win", (score) => { - add([ - sprite("bean"), - pos(width() / 2, height() / 2 - 80), - scale(2), - anchor("center"), - ]); - - // display score - add([ - text(score), - pos(width() / 2, height() / 2 + 80), - scale(2), - anchor("center"), - ]); - - // go back to game with space is pressed - onKeyPress("space", () => go("game")); - onGamepadButtonPress("south", () => go("game")); + add([ + sprite("bean"), + pos(width() / 2, height() / 2 - 80), + scale(2), + anchor("center"), + ]); + + // display score + add([ + text(score), + pos(width() / 2, height() / 2 + 80), + scale(2), + anchor("center"), + ]); + + // go back to game with space is pressed + onKeyPress("space", () => go("game")); + onGamepadButtonPress("south", () => go("game")); }); +// Sets up the scene where we lose :( scene("lose", () => { - add([ - text("You Lose"), - ]); - onKeyPress("space", () => go("game")); - onGamepadButtonPress("south", () => go("game")); + add([ + text("You Lose"), + ]); + onKeyPress("space", () => go("game")); + onGamepadButtonPress("south", () => go("game")); }); +// Starts the game by entering the game scene go("game"); diff --git a/examples/drag.js b/examples/drag.js index 74a27d1a..ebe70729 100644 --- a/examples/drag.js +++ b/examples/drag.js @@ -49,7 +49,8 @@ onMousePress(() => { if (curDraggin) { return; } - // Loop all "bean"s in reverse, so we pick the topmost one + + // Loop all "bean"s in reverse, so we pick the one that is on top for (const obj of get("drag").reverse()) { // If mouse is pressed and mouse position is inside, we pick if (obj.isHovering()) { diff --git a/examples/draw.js b/examples/draw.js index 3af2bcbe..2cc6435c 100644 --- a/examples/draw.js +++ b/examples/draw.js @@ -1,10 +1,10 @@ // @ts-check -// Kaboom as pure rendering lib (no component / game obj etc.) - +// Kaplay as pure rendering lib (no component / game obj etc.) kaplay(); loadSprite("bean", "/sprites/bean.png"); +// Loads a spiral shader loadShader( "spiral", null, diff --git a/examples/easing.js b/examples/easing.js index 4f5434f1..953949c9 100644 --- a/examples/easing.js +++ b/examples/easing.js @@ -1,5 +1,6 @@ // @ts-check +// Moves objects with custom easings kaplay(); add([ diff --git a/examples/eatlove.js b/examples/eatlove.js index 6574a446..424fb0f0 100644 --- a/examples/eatlove.js +++ b/examples/eatlove.js @@ -2,15 +2,16 @@ kaplay(); +// A lttle game about eating fruit! const fruits = [ - "apple", - "pineapple", - "grape", - "watermelon", + "apple", + "pineapple", + "grape", + "watermelon", ]; for (const fruit of fruits) { - loadSprite(fruit, `/sprites/${fruit}.png`); + loadSprite(fruit, `/sprites/${fruit}.png`); } loadSprite("bean", "/sprites/bean.png"); @@ -19,129 +20,130 @@ loadSound("hit", "/examples/sounds/hit.mp3"); loadSound("wooosh", "/examples/sounds/wooosh.mp3"); scene("start", () => { - play("wooosh"); - - add([ - text("Eat All"), - pos(center().sub(0, 100)), - scale(2), - anchor("center"), - ]); - - add([ - sprite("heart"), - pos(center().add(0, 100)), - scale(2), - anchor("center"), - ]); - - wait(1.5, () => go("game")); + // Plays the wooosh sound + play("wooosh"); + + add([ + text("Eat All"), + pos(center().sub(0, 100)), + scale(2), + anchor("center"), + ]); + + add([ + sprite("heart"), + pos(center().add(0, 100)), + scale(2), + anchor("center"), + ]); + + wait(1.5, () => go("game")); }); // main game scene content scene("game", () => { - const SPEED_MIN = 120; - const SPEED_MAX = 640; - - // add the player game object - const player = add([ - sprite("bean"), - pos(40, 20), - area({ scale: 0.5 }), - anchor("center"), - ]); - - // make the layer move by mouse - player.onUpdate(() => { - player.pos = mousePos(); - }); - - // game over if player eats a fruit - player.onCollide("fruit", () => { - go("lose", score); - play("hit"); - }); - - // move the food every frame, destroy it if far outside of screen - onUpdate("food", (food) => { - food.move(-food.speed, 0); - if (food.pos.x < -120) { - destroy(food); - } - }); - - onUpdate("heart", (heart) => { - if (heart.pos.x <= 0) { - go("lose", score); - play("hit"); - addKaboom(heart.pos); - } - }); - - // score counter - let score = 0; - - const scoreLabel = add([ - text(score.toString(), { - size: 32, - }), - pos(12, 12), - ]); - - // increment score if player eats a heart - player.onCollide("heart", (heart) => { - addKaboom(player.pos); - score += 1; - destroy(heart); - scoreLabel.text = score.toString(); - burp(); - shake(12); - }); - - // do this every 0.3 seconds - loop(0.3, () => { - // spawn from right side of the screen - const x = width() + 24; - // spawn from a random y position - const y = rand(0, height()); - // get a random speed - const speed = rand(SPEED_MIN, SPEED_MAX); - // 50% percent chance is heart - const isHeart = chance(0.5); - const spriteName = isHeart ? "heart" : choose(fruits); - - add([ - sprite(spriteName), - pos(x, y), - area({ scale: 0.5 }), - anchor("center"), - "food", - isHeart ? "heart" : "fruit", - { speed: speed }, - ]); - }); + const SPEED_MIN = 120; + const SPEED_MAX = 640; + + // add the player game object + const player = add([ + sprite("bean"), + pos(40, 20), + area({ scale: 0.5 }), + anchor("center"), + ]); + + // make the layer move by mouse + player.onUpdate(() => { + player.pos = mousePos(); + }); + + // game over if player eats a fruit + player.onCollide("fruit", () => { + go("lose", score); + play("hit"); + }); + + // move the food every frame, destroy it if far outside of screen + onUpdate("food", (food) => { + food.move(-food.speed, 0); + if (food.pos.x < -120) { + destroy(food); + } + }); + + onUpdate("heart", (heart) => { + if (heart.pos.x <= 0) { + go("lose", score); + play("hit"); + addKaboom(heart.pos); + } + }); + + // score counter + let score = 0; + + const scoreLabel = add([ + text(score.toString(), { + size: 32, + }), + pos(12, 12), + ]); + + // increment score if player eats a heart + player.onCollide("heart", (heart) => { + addKaboom(player.pos); + score += 1; + destroy(heart); + scoreLabel.text = score.toString(); + burp(); + shake(12); + }); + + // do this every 0.3 seconds + loop(0.3, () => { + // spawn from right side of the screen + const x = width() + 24; + // spawn from a random y position + const y = rand(0, height()); + // get a random speed + const speed = rand(SPEED_MIN, SPEED_MAX); + // 50% percent chance is heart + const isHeart = chance(0.5); + const spriteName = isHeart ? "heart" : choose(fruits); + + add([ + sprite(spriteName), + pos(x, y), + area({ scale: 0.5 }), + anchor("center"), + "food", + isHeart ? "heart" : "fruit", + { speed: speed }, + ]); + }); }); // game over scene scene("lose", (score) => { - add([ - sprite("bean"), - pos(width() / 2, height() / 2 - 108), - scale(3), - anchor("center"), - ]); - - // display score - add([ - text(score), - pos(width() / 2, height() / 2 + 108), - scale(3), - anchor("center"), - ]); - - // go back to game with space is pressed - onKeyPress("space", () => go("start")); - onClick(() => go("start")); + add([ + sprite("bean"), + pos(width() / 2, height() / 2 - 108), + scale(3), + anchor("center"), + ]); + + // display score + add([ + text(score), + pos(width() / 2, height() / 2 + 108), + scale(3), + anchor("center"), + ]); + + // go back to game with space is pressed + onKeyPress("space", () => go("start")); + onClick(() => go("start")); }); // start with the "game" scene diff --git a/examples/egg.js b/examples/egg.js index 225ba585..0a5acac8 100644 --- a/examples/egg.js +++ b/examples/egg.js @@ -1,6 +1,6 @@ // @ts-check -// Egg minigames (yes, like Peppa) +// Egg minigames (yes, like Peppa) kaplay({ background: [135, 62, 132], }); diff --git a/examples/fadeIn.js b/examples/fadeIn.js index a14725a2..e0a6e222 100644 --- a/examples/fadeIn.js +++ b/examples/fadeIn.js @@ -1,5 +1,6 @@ // @ts-check +// How to fade in an object kaplay(); loadBean(); diff --git a/examples/flamebar.js b/examples/flamebar.js index 947f43b0..1ce8b5d3 100644 --- a/examples/flamebar.js +++ b/examples/flamebar.js @@ -2,7 +2,7 @@ // Mario-like flamebar -// Start kaboom +// Start kaplay kaplay(); // Load assets diff --git a/examples/gravity.js b/examples/gravity.js index e5e710ce..35d1dc6e 100644 --- a/examples/gravity.js +++ b/examples/gravity.js @@ -2,7 +2,7 @@ // Responding to gravity & jumping -// Start kaboom +// Start kaplay kaplay(); // Load assets diff --git a/examples/movement.js b/examples/movement.js index 13e2aec1..07c4ae49 100644 --- a/examples/movement.js +++ b/examples/movement.js @@ -2,7 +2,7 @@ // Input handling and basic player movement -// Start kaboom +// Start kaplay kaplay(); // Load assets diff --git a/examples/raycaster3d.js b/examples/raycaster3d.js index 17251aba..d9130dd7 100644 --- a/examples/raycaster3d.js +++ b/examples/raycaster3d.js @@ -1,6 +1,6 @@ // @ts-check -// Start kaboom +// Start kaplay kaplay(); // load assets diff --git a/examples/textInput.js b/examples/textInput.js index 4a3089b8..28a4d98b 100644 --- a/examples/textInput.js +++ b/examples/textInput.js @@ -1,6 +1,6 @@ // @ts-check -// Start kaboom +// Start kaplay kaplay(); setBackground(BLACK); From ce271e4e7123972155ef77d19bb4403155651b08 Mon Sep 17 00:00:00 2001 From: amyspark-ng <92493175+amyspark-ng@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:13:46 -0500 Subject: [PATCH 4/5] removed # --- examples/collisionshapes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/collisionshapes.js b/examples/collisionshapes.js index c58c3b4f..6cf75101 100644 --- a/examples/collisionshapes.js +++ b/examples/collisionshapes.js @@ -1,6 +1,6 @@ // @ts-check -// # How kaplay handles collisions with different shapes +// How kaplay handles collisions with different shapes kaplay(); // Set the gravity acceleration (pixels per second) From 8904cf5d48537a7b08feb1f3c79c0dec8b257708 Mon Sep 17 00:00:00 2001 From: amyspark-ng <92493175+amyspark-ng@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:52:53 -0500 Subject: [PATCH 5/5] that was confusing --- examples/ai.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/ai.js b/examples/ai.js index 6273aaff..00584ba8 100644 --- a/examples/ai.js +++ b/examples/ai.js @@ -65,9 +65,10 @@ enemy.onStateEnter("move", async () => { enemy.enterState("idle"); }); -// .onStateUpdate() will run every frame, but only when the current state is "move" -// We move the enemy in the direction of the player +// .onStateUpdate() is similar to .onUpdate(), it'll run every frame, but in this case +// Only when the current state is "move" enemy.onStateUpdate("move", () => { + // We move the enemy in the direction of the player if (!player.exists()) return; const dir = player.pos.sub(enemy.pos).unit(); enemy.move(dir.scale(ENEMY_SPEED));