Files
Forge-Engine/screens/scenes/render_scene_object.py
T
williamandClaude Sonnet 5 9199897784
Build and deploy / test-python (push) Successful in 6m26s
Build and deploy / test-js (push) Successful in 57s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Image de fond de scène + caméra qui suit le personnage, fps d'animation cohérent
Trois retours utilisateur :
- fps d'idle/interagir/touches supplémentaires alignés sur celui de la
  marche (8 i/s partout, était 4 pour idle — perçu comme "les autres
  animations sont lentes à côté de la marche").
- Nouveau menu "🏞️ Images de fond" dans "Objets de cette scène" : pose
  un objet kind="fond" à la taille RÉELLE de l'image choisie (pack
  CraftPix intégré en galerie, admin seulement — licence, voir
  core/sprite_gate.py), derrière tout le reste, insensible au clic.
- Si ce fond dépasse la scène, elle devient le "monde" : .playScreen.
  playScene est désormais le viewport (overflow:hidden, taille fixe),
  .sceneWorld le monde à l'intérieur — la caméra centre le premier
  personnage trouvé, bornée pour ne jamais montrer au-delà des bords
  (voir personnage-controller.js::forgeUpdateSceneCamera). Le personnage
  peut désormais se déplacer sur tout le monde, pas seulement le petit
  cadre visible (clampSceneObjectPosition, actions.js). Un jeu sans fond
  XXL garde un comportement strictement identique à avant (monde ==
  scène, transform vide).

Bibliothèque générée une fois par scripts/generate_background_manifest.py
(assets/background/, non versionné, licence CraftPix) vers
static/backgrounds/ (committé), même patron que
generate_animal_sprite_manifest.py.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 12:24:10 +02:00

58 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import html as html_lib
from ..rendering.personnage_data import resolve_personnage_idle_frame
def render_scene_object(obj):
"""HTML d'un objet de scène — positionnement en PIXELS ABSOLUS (pas de
% fluide, voir ensure_scene_schema.py), mirror volontairement plus
simple que render_element_html.py (pas d'arbre de nesting, pas de
palette de widgets à gérer) : juste kind="personnage" (réutilise
resolve_personnage_idle_frame, même _personnage_data que le widget
"personnage" de l'éditeur document) ou kind="decor" (image fixe,
attributes.src). data-object-id/data-personnage jouent le même rôle
que data-element-id/data-personnage côté DOM (voir
static/js/screen_edit/personnage-preview.js, static/js/play/actions.js)."""
style = (
f"position:absolute; left:{obj['x']}px; top:{obj['y']}px; "
f"width:{obj['width']}px; height:{obj['height']}px; z-index:{obj['z_index']};"
)
# data-element-id (en plus de data-object-id) : réutilise TELS QUELS
# tous les sélecteurs [data-element-id=...] déjà écrits pour l'éditeur
# document (collision, animation de sprites, "Modifier un élément") —
# voir static/js/play/actions.js/conditions.js. Sans risque de
# collision d'id : un jeu est ENTIÈREMENT "document" (_screen_elements)
# OU "jeu_2d" (_scene_objects), jamais les deux à la fois.
# data-anim-target (Timeline d'animation, Bug corrigé) : applyAnimationClip()
# (static/js/play/screens.js) et son équivalent d'aperçu éditeur
# (animation-timeline.js) sélectionnent TOUJOURS leur cible via
# [data-anim-target=...] (jamais data-element-id/data-object-id, posé
# sur .canvasElement/.playElement pour le DOM, voir visible_attrs.py) —
# un objet de scène n'ayant pas de wrapper équivalent, cet attribut est
# posé directement sur son <img> : SANS lui, aucun clip de Timeline (ni
# même une action de flow "Jouer une animation") ne trouvait jamais sa
# cible pour un objet de scène, quel que soit son type d'animation.
# class="sceneObjectSprite" (object-fit:contain, voir static/style.css) :
# les frames CraftPix (screens/labels/animal_sprite_library.py) sont de
# GRANDS canevas très paddés (~788×504 px, très différent des sprites
# Kenney déjà bien recadrés, ~96×128 px) — sans object-fit, l'image
# remplirait quand même son cadre (width/height:100%, voir la règle
# `.canvasElementInner > img` dans scene_edit.html) mais DÉFORMÉE,
# rendant le personnage minuscule/écrasé dans sa boîte de sélection.
if obj["kind"] == "personnage":
src = resolve_personnage_idle_frame(obj)
src_attr = f' src="{html_lib.escape(src)}"' if src else ""
return (f'<img class="sceneObjectSprite" data-object-id="{obj["id"]}" data-element-id="{obj["id"]}" '
f'data-anim-target="{obj["id"]}" data-personnage="1" style="{style}"{src_attr}>')
src = (obj.get("attributes") or {}).get("src", "")
src_attr = f' src="{html_lib.escape(src)}"' if src else ""
# "fond" (voir add_scene_object.py) : même image fixe que "decor",
# seule la classe change — .sceneBackground (static/style.css) la
# rend insensible au clic (pointer-events:none), pour qu'elle ne
# bloque jamais un clic destiné à un objet posé par-dessus, même
# étendue sur tout le "monde" (voir personnage-controller.js, la
# caméra qui la suit en défilant).
css_class = "sceneObjectSprite sceneBackground" if obj["kind"] == "fond" else "sceneObjectSprite"
return (f'<img class="{css_class}" data-object-id="{obj["id"]}" data-element-id="{obj["id"]}" '
f'data-anim-target="{obj["id"]}" style="{style}"{src_attr}>')