Phase 6 : son (musique de fond par écran + action "Jouer un son")
Build and deploy / test-python (push) Successful in 1m27s
Build and deploy / test-js (push) Successful in 6s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Ajoute deux mécanismes distincts, à la demande de l'utilisateur qui a
précisé qu'un son doit pouvoir être attaché à une SCÈNE (pas seulement
joué ponctuellement par une action de flow, comme prévu initialement) :

- Musique de fond par écran (nouveau champ background_music_url sur
  _screens, ALTER TABLE nullable) : réglée dans le panneau gauche de
  l'éditeur (URL ou envoi de fichier, réutilise la route d'upload
  générique existante), enregistrée en AJAX au même patron que le format
  d'aperçu (screen_set_aspect.py). Démarrée en boucle à l'affichage de
  l'écran et arrêtée au changement d'écran (runScreenBackgroundMusic(),
  appelée depuis showScreen() dans static/js/play/screens.js) — un seul
  Audio actif à la fois, jamais cumulé avec une musique restée d'un écran
  précédent.

- Action de flow "jouer_son" (aux côtés des actions existantes) : effet
  sonore ponctuel, non bouclé, déclenchable sur n'importe quel nœud
  Déclencheur. Réutilise data_value (déjà un champ texte générique sur
  le nœud action, comme pour "attendre") plutôt qu'une nouvelle colonne
  dédiée — fire-and-forget côté client (runActionNode), ne bloque jamais
  la suite du graphe.

Les deux réutilisent le même mécanisme d'upload de fichier déjà en place
ailleurs dans l'éditeur (ex. source d'une vidéo), sans nouvelle route.

Ceci complète les 6 phases du plan d'extension du moteur (état par
joueur, hasard/maths, clavier/minuteur, ajout de ligne, position/
collision, son) : Forge Engine peut désormais couvrir des jeux bien
au-delà du narratif/puzzle/quiz (action, arcade, jeux à contrainte de
temps).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-08-30 17:56:49 +02:00
co-authored by Claude Sonnet 5
parent 9e263435e6
commit 76331f9285
12 changed files with 269 additions and 1 deletions
+1
View File
@@ -71,6 +71,7 @@ from .screens_repo.delete_screen import delete_screen
from .screens_repo.move_screen import move_screen
from .screens_repo.screens_referencing import screens_referencing
from .screens_repo.set_screen_aspect import set_screen_aspect
from .screens_repo.set_screen_background_music import set_screen_background_music
from .elements.list_elements import list_elements
from .elements.get_element import get_element
+1
View File
@@ -10,5 +10,6 @@ ACTION_TYPE_LABELS = {
"attendre": "Attendre quelques secondes avant de continuer",
"declencher_evenement": "Déclencher un événement",
"ajouter_ligne": "Ajouter une ligne à un objet",
"jouer_son": "Jouer un son",
"rien": "Ne rien faire",
}
+7
View File
@@ -107,6 +107,13 @@ def ensure_schema(slug):
# que la fenêtre du joueur n'a pas la même proportion que celle
# utilisée à la conception.
conn.execute("ALTER TABLE _screens ADD COLUMN preview_aspect TEXT NOT NULL DEFAULT '9/16'")
if "background_music_url" not in screen_cols:
# Phase 6 — musique de fond de cet écran (URL) : démarrée en boucle
# à l'affichage de l'écran, arrêtée au changement d'écran (voir
# runScreenBackgroundMusic() dans static/js/play/screens.js).
# Indépendante de l'action "Jouer un son" (effet sonore ponctuel,
# non bouclé, sur n'importe quel déclencheur).
conn.execute("ALTER TABLE _screens ADD COLUMN background_music_url TEXT")
action_cols = {r["name"] for r in conn.execute("PRAGMA table_info(_actions)").fetchall()}
for col_name, col_def in [
("target_element_id", "INTEGER REFERENCES _screen_elements(id)"),
@@ -0,0 +1,17 @@
import db
from .ensure_schema import ensure_schema
def set_screen_background_music(slug, screen_id, url):
"""Mémorise l'URL de musique de fond de cet écran (voir le commentaire
sur la colonne background_music_url dans ensure_schema.py). Chaîne vide
-> NULL (pas de musique), comme un simple champ texte qu'on vide."""
ensure_schema(slug)
conn = db.connect(slug)
conn.execute(
"UPDATE _screens SET background_music_url = ? WHERE id = ?",
(url or None, screen_id),
)
conn.commit()
conn.close()