BeeEngine logo BeeEngine JAVASCRIPT 2D ENGINE

Animazione Spritesheet in JavaScript: play, update e draw

Documentazione – BeeEngine
v2.9.2

BeeAnimatedSprite — Documentazione Tecnica

Clip da spritesheet: play / update / draw, finished per l’animator

📁 Panoramica

BeeAnimatedSprite riproduce un clip. Non è un’BeeEntity, non è BeeAnimator, non è BeeSprite (quella è un’altra classe). Vive in src/graphics/BeeAnimatedSprite.js. Vuole un BeeSpriteSheet: i frame sono indici, il ritaglio lo fa sheet.drawFrame. Factory: gioco.createAnimatedSprite(sheet, config).

Il grafo idle → run → attack sta sull’animator. Qui restano: quale clip, a che fps, se gira in loop, quando finished è true. L’animator in #enter chiama sprite.play(clip, { restart: true, loop: next.loop }).

const sheet = gioco.createSpriteSheet(img, 32, 32, { framesPerRow: 8 }); const sprite = gioco.createAnimatedSprite(sheet, { animations: { idle: { frames: [0, 1], fps: 4, loop: true }, run: { frames: [2, 3, 4, 5], fps: 10, loop: true }, attack: { frames: [6, 7, 8], fps: 12, loop: false } } }); hero.sprite = sprite;

📁 Update

In pausa dt è 0: il clip si ferma. L’entity ticka o l’animator o lo sprite, non entrambi.

  1. 1. chi tickaentity.animator → animator.update (chiama sprite.update). Altrimenti entity.sprite.update(dt).
  2. 2. frametimer += min(dt, 4 / fps). Un frame a tick. fps ≤ 0 diventa 8.
  3. 3. fineLoop: #loopOverride ?? anim.loop. One-shot: ultimo frame, poi finished e timer = 0.

draw(ctx, x, y, { width, height }) è spazio mondo se gli passi worldX/Y (BeePlayer lo fa). flipX specchia sul bordo destro del dest. save / restore in try/finally. Senza ctx, senza frames o frame undefined: return.

📁 Dove è facile sbagliare

Senza loop: true il clip è one-shot. anim.loop assente è falsy. L’animator copre il buco: in #enter passa loop: next.loop e sullo stato il default è true. Da solo, play('idle') senza flag gira una volta e si gela.

play stesso nome senza restart. Early-return: non cambia #loopOverride. Per forzare un one-shot sullo stesso clip: play('attack', { restart: true, loop: false }).

Catch-up morbido. Un hitch non salta 20 frame in un tick: il dt extra è tappato a 4 durate, poi smaltisce un frame per update. Dopo un tab in background può sembrare un filo più veloce per pochi frame.

Serve lo sheet. draw non guarda se this.sheet è null: chiama frameWidth / drawFrame. Nome clip inesistente: play torna false, console.warn, clip invariato.

📁 Esempio: clip + animator sul player

const animator = gioco.createAnimator(sprite); animator .add(‘idle’, { clip: ‘idle’, initial: true }) .add(‘run’, { clip: ‘run’, priority: 1 }) .add(‘attack’, { clip: ‘attack’, loop: false, lock: true, priority: 10, exitTo: ‘idle’ }) .when(‘*’, ‘attack’, (actor) => actor.wantsAttack) .start(); hero.animator = animator;

📁 Riepilogo API

Non estende BeeEntity. Il flip sul player lo scrive BeePlayer.draw da vx.

Membro Ritorna Scopo
new BeeAnimatedSprite(sheet, config?) BeeAnimatedSprite animations, clip iniziale config.animation o prima chiave.
play(name, { restart, loop }?) true / false Cambia clip, azzera frame/timer. true anche se è già quel clip (senza restart). false = nome assente, warn, resta sul precedente. loop boolean override; assente torna a anim.loop.
update(dt) this Avanza un frame. dt 0 in pausa. Cap hitch 4× durata frame.
draw(ctx, x, y, { width, height }?) — Ritaglio via sheet. Dest default = frameWidth/Height. flipX specchia.
finished / clip boolean / string One-shot chiuso. Nome clip corrente (l’animator lo legge).
gioco.createAnimatedSprite(sheet, config) istanza Factory sul motore, stesso costruttore.