Supprime le type d'écran "document" et recentre le produit sur le jeu 2D
Le document de cadrage produit cible des formateurs non techniques créant des serious games/quiz gamifiés — l'éditeur générique "document" (blocs de logique en nœuds, timeline d'animation, définitions d'objets/relations, templates réutilisables) est une complexité hors cible que l'effort d'ingénierie récent avait déjà abandonnée au profit du jeu_2d. - Onboarding : ne garde que le parcours "RPG" (jeu_2d), retire Quiz/Embranchement/Créer mon jeu de A à Z (tous document-only) - Suppression en bloc des modules exclusifs au document : routes/elements, routes/element_types, routes/objects, routes/legacy_actions, screens/elements, screens/element_types, screens/widgets, screens/legacy_actions, le rendu render_element_html.py et son cluster, templates/screen_edit.html, templates/game_dashboard.html, flow-editor.js/tabs-and-blocks.js/animation-timeline.js - Dashboard toujours simplifié (un seul mode possible désormais) - Tests document-only supprimés, tests de logique partagée (flow, événements personnalisés, animations) retargetés sur des écrans jeu_2d - Aucune régression jeu_2d : 299 tests passent Carte d'onboarding retravaillée : argumentaire RH non technique (liste à coche, badge "Compatible LMS"), taille et interaction de retournement ajustées.
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
import db
|
||||
|
||||
from ..screens_repo.list_screens import list_screens
|
||||
from ..elements.list_elements import list_elements
|
||||
from ..flow.list_flow_nodes import list_flow_nodes
|
||||
from ..flow.list_flow_edges import list_flow_edges
|
||||
from ..animations.list_animation_clips import list_animation_clips
|
||||
from ..element_types.list_element_types import list_element_types
|
||||
from ..element_types.load_template_tree import _load_template_tree
|
||||
from ..rendering.personnage_data import resolve_personnage_animations
|
||||
from ..rendering.personnage_commands import resolve_personnage_commands
|
||||
from ..rendering.personnage_role import resolve_personnage_role
|
||||
@@ -45,59 +42,43 @@ def full_game_payload(slug, player_id=db.PLAYER_SHARED):
|
||||
flows = {}
|
||||
animations = {}
|
||||
for s in screens_:
|
||||
if s["kind"] == "jeu_2d":
|
||||
objects = list_scene_objects(slug, s["id"])
|
||||
for o in objects:
|
||||
o["rendered_html"] = render_scene_object(o)
|
||||
# Déplacement/animation automatiques (voir
|
||||
# static/js/play/personnage-controller.js) : chaque
|
||||
# personnage porte ses touches et son rôle déjà résolus
|
||||
# (défauts comblés) pour que le runtime client n'ait
|
||||
# aucune logique de repli à dupliquer — seul un
|
||||
# personnage "joueur" est déplacé/suivi par la caméra.
|
||||
if o["kind"] == "personnage":
|
||||
o["personnage_commandes"] = resolve_personnage_commands(o)
|
||||
o["personnage_role"] = resolve_personnage_role(o)
|
||||
if o["kind"] in ("dialogue_box", "quiz_box", "score_widget"):
|
||||
# Widgets d'interface (voir "🖥️ Interface",
|
||||
# screens/rendering/dialogue_box_style.py) : ni
|
||||
# collision, ni cible/source de règle — juste leur
|
||||
# style, lu par static/js/play/dialogue-box-controller.js.
|
||||
o["dialogue_box_style"] = resolve_dialogue_box_style(o)
|
||||
continue
|
||||
# Boîte de collision (voir static/js/play/conditions.js::
|
||||
# elementsOverlap) : posée sur TOUT objet de scène, pas
|
||||
# seulement "personnage" — un décor/fond peut aussi servir
|
||||
# d'obstacle.
|
||||
o["collision"] = resolve_collision_settings(o)
|
||||
# Règles "à la collision/dans un périmètre -> action" (voir
|
||||
# "🧩 Collision", templates/scene_edit.html, et
|
||||
# static/js/play/collision-rules-controller.js pour leur
|
||||
# exécution) — jamais sur "fond" (jamais une cible), ni sur
|
||||
# le personnage "joueur" lui-même (ce sont TOUJOURS les
|
||||
# AUTRES objets qui réagissent à SA présence, jamais
|
||||
# l'inverse).
|
||||
if o["kind"] != "fond" and not (o["kind"] == "personnage" and o.get("personnage_role") == "joueur"):
|
||||
o["collision_rules"] = resolve_collision_rules(o)
|
||||
payload_screens.append({**s, "elements": objects})
|
||||
else:
|
||||
elements = list_elements(slug, s["id"], enforce_visibility=True, player_id=player_id)
|
||||
payload_screens.append({**s, "elements": elements})
|
||||
objects = list_scene_objects(slug, s["id"])
|
||||
for o in objects:
|
||||
o["rendered_html"] = render_scene_object(o)
|
||||
# Déplacement/animation automatiques (voir
|
||||
# static/js/play/personnage-controller.js) : chaque
|
||||
# personnage porte ses touches et son rôle déjà résolus
|
||||
# (défauts comblés) pour que le runtime client n'ait
|
||||
# aucune logique de repli à dupliquer — seul un
|
||||
# personnage "joueur" est déplacé/suivi par la caméra.
|
||||
if o["kind"] == "personnage":
|
||||
o["personnage_commandes"] = resolve_personnage_commands(o)
|
||||
o["personnage_role"] = resolve_personnage_role(o)
|
||||
if o["kind"] in ("dialogue_box", "quiz_box", "score_widget"):
|
||||
# Widgets d'interface (voir "🖥️ Interface",
|
||||
# screens/rendering/dialogue_box_style.py) : ni
|
||||
# collision, ni cible/source de règle — juste leur
|
||||
# style, lu par static/js/play/dialogue-box-controller.js.
|
||||
o["dialogue_box_style"] = resolve_dialogue_box_style(o)
|
||||
continue
|
||||
# Boîte de collision (voir static/js/play/conditions.js::
|
||||
# elementsOverlap) : posée sur TOUT objet de scène, pas
|
||||
# seulement "personnage" — un décor/fond peut aussi servir
|
||||
# d'obstacle.
|
||||
o["collision"] = resolve_collision_settings(o)
|
||||
# Règles "à la collision/dans un périmètre -> action" (voir
|
||||
# "🧩 Collision", templates/scene_edit.html, et
|
||||
# static/js/play/collision-rules-controller.js pour leur
|
||||
# exécution) — jamais sur "fond" (jamais une cible), ni sur
|
||||
# le personnage "joueur" lui-même (ce sont TOUJOURS les
|
||||
# AUTRES objets qui réagissent à SA présence, jamais
|
||||
# l'inverse).
|
||||
if o["kind"] != "fond" and not (o["kind"] == "personnage" and o.get("personnage_role") == "joueur"):
|
||||
o["collision_rules"] = resolve_collision_rules(o)
|
||||
payload_screens.append({**s, "elements": objects})
|
||||
|
||||
# Le graphe de logique et les animations sont, eux, lus pour TOUS les
|
||||
# écrans, écrans-modèles compris (include_templates=True) — pas
|
||||
# seulement les "vrais" écrans ci-dessus. Un élément de jeu réutilisable
|
||||
# (ex. "mail content") peut avoir son propre déclencheur/sa propre
|
||||
# animation posée dans l'éditeur de SON écran-modèle (voir
|
||||
# screen_edit.html) : sans ses entrées ici, gameData.flows/
|
||||
# gameData.animations n'auraient jamais contenu cet écran-modèle côté
|
||||
# client, et findTriggerNode()/collectAnimationClips() (templates/
|
||||
# play.html) — pourtant déjà écrits pour les chercher — n'auraient
|
||||
# jamais rien trouvé. On ne les ajoute PAS à payload_screens : un
|
||||
# écran-modèle ne doit jamais être rendu comme un vrai <div
|
||||
# class="playScreen"> (il n'est jamais affiché tel quel, seulement
|
||||
# rechargé en direct à l'intérieur d'un élément qui l'utilise).
|
||||
# Animations d'un personnage (Phase 8) — résolues ici, à CHAQUE
|
||||
# écrans. Animations d'un personnage (Phase 8) — résolues ici, à CHAQUE
|
||||
# affichage de la page de jeu (donc toujours à partir du personnage
|
||||
# Forge ACTUELLEMENT assigné), plutôt que figées dans le nœud de flow/
|
||||
# le clip de Timeline au moment où le créateur les a configurés : sans
|
||||
@@ -107,24 +88,17 @@ def full_game_payload(slug, player_id=db.PLAYER_SHARED):
|
||||
# voir runActionNode()/applyAnimationClip() qui font cette résolution
|
||||
# à l'exécution à partir de gameData.personnage_animations plutôt que
|
||||
# depuis un data_value/custom_keyframes qui contiendrait des frames
|
||||
# déjà résolues). include_templates=True : un personnage peut vivre
|
||||
# dans un écran-modèle d'élément de jeu réutilisable, comme les flows/
|
||||
# animations ci-dessous.
|
||||
# déjà résolues).
|
||||
personnage_animations = {}
|
||||
for s in list_screens(slug, include_templates=True):
|
||||
for s in screens_:
|
||||
flows[str(s["id"])] = {
|
||||
"nodes": list_flow_nodes(slug, s["id"]),
|
||||
"edges": list_flow_edges(slug, s["id"]),
|
||||
}
|
||||
animations[str(s["id"])] = list_animation_clips(slug, s["id"])
|
||||
if s["kind"] == "jeu_2d":
|
||||
for o in list_scene_objects(slug, s["id"]):
|
||||
if o["kind"] == "personnage":
|
||||
personnage_animations[str(o["id"])] = resolve_personnage_animations(o)
|
||||
else:
|
||||
for el in list_elements(slug, s["id"]):
|
||||
if el.get("widget") == "personnage":
|
||||
personnage_animations[str(el["id"])] = resolve_personnage_animations(el)
|
||||
for o in list_scene_objects(slug, s["id"]):
|
||||
if o["kind"] == "personnage":
|
||||
personnage_animations[str(o["id"])] = resolve_personnage_animations(o)
|
||||
|
||||
definitions = db.list_definitions(slug)
|
||||
data = {}
|
||||
@@ -164,30 +138,6 @@ def full_game_payload(slug, player_id=db.PLAYER_SHARED):
|
||||
for f in full["fields"]
|
||||
]
|
||||
|
||||
# element_type_id -> id de son écran-modèle : nécessaire côté client (voir
|
||||
# collectAnimationClips() dans play.html) pour savoir, quand un élément de
|
||||
# jeu réutilisable (ex. "mail content") est posé sur un écran, quels
|
||||
# autres clips d'animation (ceux de SON PROPRE écran-modèle) doivent
|
||||
# aussi être joués à l'affichage de cet écran — sans quoi une animation
|
||||
# posée directement dans l'éditeur du modèle ne se jouait jamais quand le
|
||||
# modèle est utilisé ailleurs.
|
||||
element_types = {str(t["id"]): t["template_screen_id"] for t in list_element_types(slug)}
|
||||
|
||||
# Arbre complet (éléments + descendants) de l'écran-modèle de chaque
|
||||
# élément de jeu réutilisable — voir screens/element_types/
|
||||
# load_template_tree.py, appelée aujourd'hui à CHAQUE rendu (aperçu
|
||||
# créateur ET jeu publié en ligne). Nécessaire ici pour que le port
|
||||
# client-side de l'export Web/SCORM (static/js/play/offline/,
|
||||
# rendu d'un exemplaire d'élément de jeu OU d'un modèle de ligne de
|
||||
# Répéteur) puisse le rejouer sans base de données — inoffensif pour
|
||||
# le runtime en ligne, qui l'ignore.
|
||||
element_type_templates = {}
|
||||
for type_id_str, template_screen_id in element_types.items():
|
||||
if template_screen_id:
|
||||
tree = _load_template_tree(slug, int(type_id_str))
|
||||
if tree:
|
||||
element_type_templates[type_id_str] = tree
|
||||
|
||||
# Instantané des variables globales, pour qu'un nœud Condition puisse en
|
||||
# tester une côté CLIENT (evaluateConditionClause, templates/play.html) —
|
||||
# {{$var}} (Répéteur/Condition de visibilité), lui, reste résolu côté
|
||||
@@ -216,8 +166,8 @@ def full_game_payload(slug, player_id=db.PLAYER_SHARED):
|
||||
|
||||
return {
|
||||
"screens": payload_screens, "flows": flows, "animations": animations,
|
||||
"element_types": element_types, "data": data, "fields_meta": fields_meta,
|
||||
"data": data, "fields_meta": fields_meta,
|
||||
"variables": variables, "personnage_animations": personnage_animations,
|
||||
"definition_names": definition_names, "element_type_templates": element_type_templates,
|
||||
"definition_names": definition_names,
|
||||
"quests": quests,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user