From 127611846478dbb97fe8f99e139e7b64915818cc Mon Sep 17 00:00:00 2001 From: Olivier Biot Date: Thu, 29 Oct 2026 12:45:14 +0800 Subject: [PATCH] Examples: a Sprite showcase, in space The sprite example was two monsters turning over a galaxy, built in the preload callback through the global `game`. It is now a small scene showing what a Sprite can do, built in its own Stage from the app instance: - the monster in the middle breathes and leans (scale, rotate) and wears a different shader effect every few seconds, or on a click: Glow, Shine, Sway, Hologram, Dissolve, then Outline and Glow chained; - eight coins cut from the platformer's TexturePacker atlas orbit it, spinning (scale, flipX) under one shared Shine, and pass in front of it and behind it (depth, with world.sortNow()); - the astronaut drifts across, walking in mid-air (addAnimation, play), facing the way it goes and turning; flies buzz in figures of eight; - small monsters float about, tinted, fading, two of them additive. The backdrop is Earth Defender's nebula drawn once at the size of the screen with the same noise, larger and dimmer so the sprites read: a 32 KB WebP. On Canvas everything but the effects runs, and the caption says so. Also: TextureAtlas#createAnimationFromName had no documentation since #1008 put getAnimationSettings between it and its doc comment, so its docs sat on the wrong method and TypeScript required both its arguments. The comment is back on its method (with a typo fixed). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01SeWCkETjW35ZbXDRswV1hx --- .../src/examples/sprite/ExampleSprite.tsx | 388 ++++++++++++++---- .../src/examples/sprite/assets/nebula.webp | Bin 0 -> 31904 bytes packages/examples/src/main.tsx | 2 +- packages/melonjs/src/video/texture/atlas.js | 60 +-- 4 files changed, 350 insertions(+), 100 deletions(-) create mode 100644 packages/examples/src/examples/sprite/assets/nebula.webp diff --git a/packages/examples/src/examples/sprite/ExampleSprite.tsx b/packages/examples/src/examples/sprite/ExampleSprite.tsx index edea395611..2f4959f706 100644 --- a/packages/examples/src/examples/sprite/ExampleSprite.tsx +++ b/packages/examples/src/examples/sprite/ExampleSprite.tsx @@ -1,92 +1,342 @@ /** - * melonJS — Sprite + animation basics example. + * melonJS — Sprite showcase example. * Copyright (C) 2011 - 2026 AltByte Pte Ltd — MIT License. * See `packages/examples/LICENSE.md` for full license + asset credits. + * + * A small scene in space showing what a Sprite can do. The monster in the + * middle breathes, sways and wears a different shader effect every few + * seconds (click it for the next one), up to two effects chained. Coins cut + * from a TexturePacker atlas orbit it, spinning and passing in front of it + * and behind it; the astronaut drifts by, walking in mid-air; flies buzz + * around; tinted, fading and additive little monsters float in the dark. + * The nebula behind them is Earth Defender's sky, drawn once at the size of + * the screen with the same noise. */ import { Application, - ColorLayer, - event, - game, + DissolveEffect, + GlowEffect, + HologramEffect, + input, loader, + OutlineEffect, + type ShaderEffect, + ShineEffect, Sprite, + Stage, + SwayEffect, state, - Vector2d, + Text, + TextureAtlas, video, } from "melonjs"; import { createExampleComponent } from "../utils"; -import galaxyImg from "./assets/galaxy.png"; import monsterImg from "./assets/monster.png"; +import nebulaImg from "./assets/nebula.webp"; + +const platformer = `${import.meta.env.BASE_URL}assets/platformer/img/`; const resources = [ { name: "monster", type: "image", src: monsterImg }, - { name: "background", type: "image", src: galaxyImg }, + { name: "nebula", type: "image", src: nebulaImg }, + { name: "texture", type: "json", src: `${platformer}texture.json` }, + { name: "texture", type: "image", src: `${platformer}texture.png` }, ]; -const createGame = async () => { - // Initialize the video. - try { - const app = new Application(1218, 562, { - parent: "screen", - scaleMethod: "flex", - renderer: video.AUTO, - }); - await app.init(); - } catch { - alert("Your browser does not support HTML5 canvas."); - return; - } +const WIDTH = 1200; +const HEIGHT = 700; +const CX = WIDTH / 2; +const CY = HEIGHT / 2 - 10; - // load assets and populate the game world - loader.preload(resources, () => { - state.change(state.DEFAULT, true); - - // background sprite (centered, semi-transparent, rotating) - const bgSprite = new Sprite( - game.viewport.width / 2, - game.viewport.height / 2, - { - image: "background", - anchorPoint: new Vector2d(0.5, 0.5), - }, - ); - bgSprite.alpha = 0.5; - - // left sprite (small, rotating clockwise) - const leftSprite = new Sprite( - game.viewport.width / 2 - 125, - game.viewport.height / 2, - { - image: "monster", - anchorPoint: new Vector2d(0.5, 0.5), - }, - ); - leftSprite.scale(0.25); - - // right sprite (larger, rotating counter-clockwise) - const rightSprite = new Sprite( - game.viewport.width / 2 + 125, - game.viewport.height / 2, - { - image: "monster", - anchorPoint: new Vector2d(0.5, 0.5), - }, +const WALK = Array.from({ length: 11 }, (_, i) => { + return `walk${String(i + 1).padStart(4, "0")}.png`; +}); +const FLY = ["fly_normal.png", "fly_fly.png"]; + +/** how long the monster wears each effect, in seconds */ +const EFFECT_TIME = 3.5; + +class Showcase extends Stage { + /** what moves each frame, given the time and the step, in seconds */ + private moves: ((time: number, step: number) => void)[] = []; + private time = 0; + + override onResetEvent(app: Application) { + const world = app.world; + world.backgroundColor.parseCSS("#0b0d1a"); + this.moves = []; + this.time = 0; + const move = (fn: (time: number, step: number) => void) => { + this.moves.push(fn); + }; + // the atlas the platformer's characters and coins are cut from; each + // frame carries a pivot at its feet, which becomes its anchor + const atlas = new TextureAtlas(loader.getJSON("texture"), "texture"); + + // ---- the nebula behind everything -------------------------------- + world.addChild( + new Sprite(0, 0, { image: "nebula", anchorPoint: "top-left" }), + 0, ); - rightSprite.scale(0.75); - - // add all children to the game world - game.world.addChild(new ColorLayer("background", "#202020")); - game.world.addChild(bgSprite); - game.world.addChild(leftSprite); - game.world.addChild(rightSprite); - - // rotate sprites each frame - event.on(event.GAME_UPDATE, () => { - bgSprite.rotate(0.0125); - leftSprite.rotate(0.05); - rightSprite.rotate(-0.05); + + // ---- little monsters, tinted, fading, two of them added on -------- + const minions = [ + { x: 170, y: 150, tint: "#ff7a6e", blend: "normal" }, + { x: 1050, y: 560, tint: "#7ab8ff", blend: "normal" }, + { x: 1040, y: 150, tint: "#c58cff", blend: "lighter" }, + { x: 150, y: 560, tint: "#9cff8a", blend: "lighter" }, + ] as const; + minions.forEach((m, i) => { + const minion = new Sprite(m.x, m.y, { image: "monster" }); + minion.scale(0.13); + minion.tint.parseCSS(m.tint); + minion.blendMode = m.blend; + world.addChild(minion, 1); + move((time, step) => { + minion.setOpacity(0.45 + 0.4 * Math.sin(time * 0.8 + i * 1.7)); + minion.pos.y = m.y + Math.sin(time * 1.1 + i) * 14; + minion.rotate(step * (i % 2 === 0 ? 0.4 : -0.4)); + }); + }); + + // ---- the monster, and the effects it wears ------------------------ + const hero = new Sprite(CX, CY, { image: "monster" }); + hero.scale(0.55); + world.addChild(hero, 3); + let breath = 1; + let lean = 0; + move((time) => { + // breathing: scale, and a slow lean either way: rotate + const next = 1 + 0.04 * Math.sin(time * 2.2); + hero.scale(next / breath); + breath = next; + const angle = 0.06 * Math.sin(time * 0.9); + hero.rotate(angle - lean); + lean = angle; + }); + + const caption = new Text(CX, HEIGHT - 70, { + font: "Arial", + size: 26, + fillStyle: "#ffffff", + textAlign: "center", + textBaseline: "middle", + text: "", }); + world.addChild(caption, 10); + const hint = new Text(CX, HEIGHT - 38, { + font: "Arial", + size: 15, + fillStyle: "#9aa0b4", + textAlign: "center", + textBaseline: "middle", + text: "", + }); + world.addChild(hint, 10); + + const r = app.renderer; + if (r.shaderLanguage === null) { + caption.setText("Sprite"); + hint.setText("shader effects need WebGL or WebGPU"); + } else { + // every effect is added once and switched on and off: taking one + // off a renderable would destroy it + const glow = new GlowEffect(r, { + color: [0.45, 0.9, 1.0], + width: 9, + intensity: 3, + }); + const outline = new OutlineEffect(r, { color: [1, 1, 1], width: 5 }); + const shine = new ShineEffect(r, { + color: [1.0, 0.95, 0.75], + speed: 0.6, + width: 0.08, + intensity: 0.8, + angle: 0.6, + }); + const hologram = new HologramEffect(r, { + color: [0.3, 0.8, 1.0], + intensity: 0.6, + }); + const dissolve = new DissolveEffect(r, { + progress: 0, + edgeColor: [0.4, 0.9, 1.0], + }); + const sway = new SwayEffect(r, { strength: 0.04, speed: 3 }); + const all: ShaderEffect[] = [ + glow, + outline, + shine, + hologram, + dissolve, + sway, + ]; + for (const fx of all) { + fx.enabled = false; + hero.addPostEffect(fx); + } + const looks: { name: string; effects: ShaderEffect[] }[] = [ + { name: "GlowEffect", effects: [glow] }, + { name: "ShineEffect", effects: [shine] }, + { name: "SwayEffect", effects: [sway] }, + { name: "HologramEffect", effects: [hologram] }, + { name: "DissolveEffect", effects: [dissolve] }, + { name: "OutlineEffect + GlowEffect", effects: [outline, glow] }, + ]; + let current = -1; + let since = 0; + const wear = (index: number) => { + current = index % looks.length; + since = this.time; + for (const fx of all) { + fx.enabled = looks[current].effects.includes(fx); + } + caption.setText(looks[current].name); + }; + wear(0); + hint.setText("click the monster for the next effect"); + // pointer events reach a renderable that is not kinematic + hero.isKinematic = false; + input.registerPointerEvent("pointerdown", hero, () => { + wear(current + 1); + return false; + }); + move((time) => { + if (time - since > EFFECT_TIME) { + wear(current + 1); + } + const local = time - since; + shine.setTime(time); + hologram.setTime(time); + sway.setTime(time); + // gone and back within its turn + dissolve.setProgress( + 0.5 - 0.5 * Math.cos((local / EFFECT_TIME) * Math.PI * 2), + ); + }); + } + + // ---- coins orbiting it: in front of it, then behind it ------------ + const coinShine = + r.shaderLanguage === null + ? undefined + : new ShineEffect(r, { + color: [1.0, 0.95, 0.7], + speed: 0.8, + width: 0.25, + intensity: 0.5, + angle: 0.35, + bands: 14.5, + }); + if (coinShine !== undefined) { + // one effect for every coin: shared, so no coin destroys it + coinShine.shared = true; + move((time) => { + coinShine.setTime(time); + }); + } + const COINS = 8; + // a coin crossing to the other side changes its depth, and a world + // sorted on "z" is re-sorted by hand for it: depth alone does not + let resort = false; + for (let i = 0; i < COINS; i++) { + const coin = atlas.createAnimationFromName(["coin.png"]); + // turned about its middle rather than its pivot + coin.anchorPoint.set(0.5, 0.5); + if (coinShine !== undefined) { + coin.addPostEffect(coinShine); + } + world.addChild(coin, 2); + let size = 1; + let squeeze = 1; + move((time) => { + const angle = time * 0.5 + (i / COINS) * Math.PI * 2; + const front = Math.sin(angle); + coin.pos.x = CX + Math.cos(angle) * 330; + coin.pos.y = CY + 30 + front * 95; + // nearer is bigger, and drawn over the monster + const nextSize = 1.4 + 0.5 * front; + coin.scale(nextSize / size); + size = nextSize; + const depth = front > 0 ? 4 : 2; + if (coin.depth !== depth) { + coin.depth = depth; + resort = true; + } + // spinning on itself: squeezed across, flipped past the edge + const across = Math.cos(time * 3 + i); + const nextSqueeze = Math.max(Math.abs(across), 0.06); + coin.scale(nextSqueeze / squeeze, 1); + squeeze = nextSqueeze; + coin.flipX(across < 0); + }); + } + move(() => { + if (resort) { + world.sortNow(); + resort = false; + } + }); + + // ---- the astronaut, drifting across, walking in mid-air ----------- + const astronaut = atlas.createAnimationFromName(WALK); + astronaut.addAnimation("walk", WALK, 70); + astronaut.play("walk"); + astronaut.anchorPoint.set(0.5, 0.5); + astronaut.scale(0.9); + world.addChild(astronaut, 5); + let spin = 0; + move((time) => { + // across the screen and back, facing the way it goes + const along = Math.sin(time * 0.18); + astronaut.pos.x = CX + along * 470; + astronaut.pos.y = 120 + Math.sin(time * 0.7) * 30; + astronaut.flipX(Math.cos(time * 0.18) < 0); + // and turning slowly as it floats + const angle = 0.35 * Math.sin(time * 0.5); + astronaut.rotate(angle - spin); + spin = angle; + }); + + // ---- flies, buzzing in figures of eight --------------------------- + [0, 1].forEach((i) => { + const fly = atlas.createAnimationFromName(FLY); + fly.addAnimation("buzz", FLY, 90); + fly.play("buzz"); + world.addChild(fly, 5); + const ox = i === 0 ? 260 : 940; + move((time) => { + const t = time * 1.3 + i * 2; + fly.pos.x = ox + Math.sin(t) * 110; + fly.pos.y = 360 + Math.sin(t * 2) * 60; + // facing the way it flies + fly.flipX(Math.cos(t) > 0); + }); + }); + } + + override update(dt: number) { + const step = dt / 1000; + this.time += step; + for (const move of this.moves) { + move(this.time, step); + } + super.update(dt); + // something moves every frame + return true; + } +} + +export const ExampleSprite = createExampleComponent(async () => { + const app = new Application(WIDTH, HEIGHT, { + parent: "screen", + scale: "auto", + renderer: video.AUTO, }); -}; + await app.init(); -export const ExampleSprite = createExampleComponent(createGame); + state.set(state.PLAY, new Showcase()); + loader.preload(resources, () => { + state.change(state.PLAY, true); + }); +}); diff --git a/packages/examples/src/examples/sprite/assets/nebula.webp b/packages/examples/src/examples/sprite/assets/nebula.webp new file mode 100644 index 0000000000000000000000000000000000000000..c765eb3d54ca9bdfe817b08fc87dff5cea52f9a9 GIT binary patch literal 31904 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 literal 0 HcmV?d00001 diff --git a/packages/examples/src/main.tsx b/packages/examples/src/main.tsx index 2a99115f98..a40a444c94 100644 --- a/packages/examples/src/main.tsx +++ b/packages/examples/src/main.tsx @@ -630,7 +630,7 @@ const examples: { path: "sprite", sourceDir: "sprite", description: - "Displaying and transforming sprites with scaling, rotation, and alpha blending.", + "Sprites: transforms, tint and blending, atlas animation, and shader effects alone or chained.", }, { component: , diff --git a/packages/melonjs/src/video/texture/atlas.js b/packages/melonjs/src/video/texture/atlas.js index 8749f45e8b..136b5a9259 100644 --- a/packages/melonjs/src/video/texture/atlas.js +++ b/packages/melonjs/src/video/texture/atlas.js @@ -736,36 +736,6 @@ export class TextureAtlas extends Texture2d { ); } - /** - * Create an animation object using the first region found using all specified names - * @param {string[]|number[]} [names] - list of names for each sprite (if not specified all defined names/entries in the atlas will be added) - * (when manually creating a Texture out of a spritesheet, only numeric values are authorized) - * @param {object} [settings] - Additional settings passed to the {@link Sprite} contructor - * @returns {Sprite} - * @example - * // create a new texture object under the `game` namespace - * game.texture = new me.TextureAtlas( - * me.loader.getJSON("texture"), - * me.loader.getImage("texture") - * ); - * - * // create a new Animated Sprite - * let sprite = game.texture.createAnimationFromName([ - * "walk0001.png", "walk0002.png", "walk0003.png", - * "walk0004.png", "walk0005.png", "walk0006.png", - * "walk0007.png", "walk0008.png", "walk0009.png", - * "walk0010.png", "walk0011.png" - * ]); - * - * // define an additional basic walking animation - * sprite.addAnimation ("simple_walk", [0,2,1]); - * // you can also use frame name to define your animation - * sprite.addAnimation ("speed_walk", ["walk0007.png", "walk0008.png", "walk0009.png", "walk0010.png"]); - * // set the default animation - * sprite.setCurrentAnimation("simple_walk"); - * // set the renderable position to bottom center - * sprite.anchorPoint.set(0.5, 1.0); - */ /** * Return the Sprite settings object (framewidth, frameheight, atlas, atlasIndices, etc.) * for the given set of atlas frame names. This is useful when extending {@link Sprite} @@ -857,6 +827,36 @@ export class TextureAtlas extends Texture2d { }; } + /** + * Create an animation object using the first region found using all specified names + * @param {string[]|number[]} [names] - list of names for each sprite (if not specified all defined names/entries in the atlas will be added) + * (when manually creating a Texture out of a spritesheet, only numeric values are authorized) + * @param {object} [settings] - Additional settings passed to the {@link Sprite} constructor + * @returns {Sprite} + * @example + * // create a new texture object under the `game` namespace + * game.texture = new me.TextureAtlas( + * me.loader.getJSON("texture"), + * me.loader.getImage("texture") + * ); + * + * // create a new Animated Sprite + * let sprite = game.texture.createAnimationFromName([ + * "walk0001.png", "walk0002.png", "walk0003.png", + * "walk0004.png", "walk0005.png", "walk0006.png", + * "walk0007.png", "walk0008.png", "walk0009.png", + * "walk0010.png", "walk0011.png" + * ]); + * + * // define an additional basic walking animation + * sprite.addAnimation ("simple_walk", [0,2,1]); + * // you can also use frame name to define your animation + * sprite.addAnimation ("speed_walk", ["walk0007.png", "walk0008.png", "walk0009.png", "walk0010.png"]); + * // set the default animation + * sprite.setCurrentAnimation("simple_walk"); + * // set the renderable position to bottom center + * sprite.anchorPoint.set(0.5, 1.0); + */ createAnimationFromName(names, settings) { const tpAtlas = []; const indices = {};