Éditeur : le canevas affiche tout le monde (fond agrandi), pas que la scène
Suite au fix du glisser figé à (0,0) : le canevas de l'éditeur restait malgré tout limité à la scène nominale (960×540 par ex.) — la partie d'un "fond" plus grand qui dépasse restait invisible/injoignable à la souris. Le canevas affiche désormais tout le "monde" (max de la scène et de l'étendue de chaque "fond", voir routes/scenes/scene_edit_view.py), comme la caméra en jeu le fait déjà (personnage-controller.js). Nouveau repère visuel "🎥 Champ de la caméra" : un cadre en pointillés marquant où s'arrête la scène nominale à l'intérieur de ce monde agrandi (le reste est assombri), pour que l'auteur voie clairement ce que le joueur verra réellement à l'écran une fois le monde plus grand que le viewport. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
6b4846a646
commit
14ec76dddd
@@ -21,6 +21,24 @@ def render_scene_edit(slug, screen_id, game):
|
|||||||
objects = screens.list_scene_objects(slug, screen_id)
|
objects = screens.list_scene_objects(slug, screen_id)
|
||||||
for o in objects:
|
for o in objects:
|
||||||
o["rendered_html"] = screens.render_scene_object(o)
|
o["rendered_html"] = screens.render_scene_object(o)
|
||||||
|
|
||||||
|
# "Monde" (voir static/js/play/personnage-controller.js::
|
||||||
|
# forgeUpdateSceneWorldSize, même principe côté serveur) : un "fond"
|
||||||
|
# posé à sa taille RÉELLE (souvent plus grande que la scène, voir
|
||||||
|
# add_scene_object.py) rend visible/joignable, dans CET éditeur, tout
|
||||||
|
# ce qui dépasse la scène nominale plutôt que de le rogner (le
|
||||||
|
# glisser-déposer le permet déjà depuis le fix précédent — sans
|
||||||
|
# agrandir le canevas ici, cette partie restait invisible/injoignable
|
||||||
|
# à la souris). Le rectangle "🎥 Champ de la caméra" (voir
|
||||||
|
# templates/scene_edit.html) marque ensuite où s'arrête la scène
|
||||||
|
# nominale À L'INTÉRIEUR de ce monde plus grand.
|
||||||
|
world_width, world_height = screen["scene_width"], screen["scene_height"]
|
||||||
|
for o in objects:
|
||||||
|
if o["kind"] == "fond":
|
||||||
|
world_width = max(world_width, o["x"] + o["width"])
|
||||||
|
world_height = max(world_height, o["y"] + o["height"])
|
||||||
|
world_width, world_height = int(world_width), int(world_height)
|
||||||
|
|
||||||
selected_id = request.args.get("selected", type=int)
|
selected_id = request.args.get("selected", type=int)
|
||||||
personnage_data = None
|
personnage_data = None
|
||||||
personnage_commands = None
|
personnage_commands = None
|
||||||
@@ -95,6 +113,7 @@ def render_scene_edit(slug, screen_id, game):
|
|||||||
return render_template(
|
return render_template(
|
||||||
"scene_edit.html",
|
"scene_edit.html",
|
||||||
game=game, screen=screen, all_screens=all_screens,
|
game=game, screen=screen, all_screens=all_screens,
|
||||||
|
world_width=world_width, world_height=world_height,
|
||||||
objects=objects, selected_id=selected_id, personnage_data=personnage_data,
|
objects=objects, selected_id=selected_id, personnage_data=personnage_data,
|
||||||
personnage_commands=personnage_commands or screens.DEFAULT_PERSONNAGE_COMMANDS,
|
personnage_commands=personnage_commands or screens.DEFAULT_PERSONNAGE_COMMANDS,
|
||||||
personnage_role=personnage_role or screens.DEFAULT_PERSONNAGE_ROLE,
|
personnage_role=personnage_role or screens.DEFAULT_PERSONNAGE_ROLE,
|
||||||
|
|||||||
@@ -592,6 +592,16 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
|||||||
position:relative; width:100%; height:100%; flex:1 1 auto; margin:0; background:#0b0d12; border-radius:8px;
|
position:relative; width:100%; height:100%; flex:1 1 auto; margin:0; background:#0b0d12; border-radius:8px;
|
||||||
overflow:hidden; border:1px solid var(--border);
|
overflow:hidden; border:1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
/* "🎥 Champ de la caméra" (voir templates/scene_edit.html) : repère
|
||||||
|
visuel marquant, à l'intérieur d'un monde agrandi par un "fond" plus
|
||||||
|
grand que la scène, les limites RÉELLES de ce que la caméra montre en
|
||||||
|
jeu — jamais interactif (pointer-events:none), pour ne jamais gêner la
|
||||||
|
sélection/le glisser d'un objet dessous. */
|
||||||
|
.sceneCameraFrame{
|
||||||
|
position:absolute; left:0; top:0; border:2px dashed var(--accent);
|
||||||
|
box-shadow:0 0 0 2000px rgba(0,0,0,.45);
|
||||||
|
pointer-events:none; z-index:5;
|
||||||
|
}
|
||||||
.canvasElement{
|
.canvasElement{
|
||||||
/* Pas d'overflow:hidden ici : une échelle (transform:scale) ou une
|
/* Pas d'overflow:hidden ici : une échelle (transform:scale) ou une
|
||||||
animation posée sur cet élément (voir la Timeline d'animation) vit sur
|
animation posée sur cet élément (voir la Timeline d'animation) vit sur
|
||||||
|
|||||||
@@ -121,7 +121,20 @@
|
|||||||
|
|
||||||
<div class="builderTabPanel active" data-tab-panel="screen">
|
<div class="builderTabPanel active" data-tab-panel="screen">
|
||||||
<div class="canvasFrame">
|
<div class="canvasFrame">
|
||||||
<div class="canvas" id="canvas" style="width:{{ screen.scene_width }}px; height:{{ screen.scene_height }}px; aspect-ratio:auto; margin:0 auto; position:relative; overflow:hidden; background:#1a1d24;">
|
<div class="canvas" id="canvas" style="width:{{ world_width }}px; height:{{ world_height }}px; aspect-ratio:auto; margin:0 auto; position:relative; overflow:hidden; background:#1a1d24;">
|
||||||
|
{% if world_width > screen.scene_width or world_height > screen.scene_height %}
|
||||||
|
<!-- "🎥 Champ de la caméra" : le monde (ce canevas, voir
|
||||||
|
world_width/world_height ci-dessus, routes/scenes/
|
||||||
|
scene_edit_view.py) peut être plus grand que la scène
|
||||||
|
nominale dès qu'un "fond" plus grand qu'elle est posé — ce
|
||||||
|
cadre en pointillés marque où s'arrête ce que la caméra
|
||||||
|
montre RÉELLEMENT en jeu (voir static/js/play/personnage-
|
||||||
|
controller.js::forgeUpdateSceneCamera), pour que le monde
|
||||||
|
agrandi reste lisible plutôt qu'une simple étendue grise
|
||||||
|
sans repère. Purement visuel (pointer-events:none) : ne
|
||||||
|
gêne jamais la sélection/le glisser d'un objet dessous. -->
|
||||||
|
<div class="sceneCameraFrame" style="width:{{ screen.scene_width }}px; height:{{ screen.scene_height }}px;" title="Champ de la caméra en jeu ({{ screen.scene_width }}×{{ screen.scene_height }} px)"></div>
|
||||||
|
{% endif %}
|
||||||
{% for o in objects %}
|
{% for o in objects %}
|
||||||
<div class="canvasElement {{ 'selected' if o.id == selected_id else '' }}" id="el-{{ o.id }}"
|
<div class="canvasElement {{ 'selected' if o.id == selected_id else '' }}" id="el-{{ o.id }}"
|
||||||
style="position:absolute; left:{{ o.x }}px; top:{{ o.y }}px; width:{{ o.width }}px; height:{{ o.height }}px;"
|
style="position:absolute; left:{{ o.x }}px; top:{{ o.y }}px; width:{{ o.width }}px; height:{{ o.height }}px;"
|
||||||
@@ -532,8 +545,13 @@
|
|||||||
var GAME_SLUG = "{{ game.slug }}";
|
var GAME_SLUG = "{{ game.slug }}";
|
||||||
var SCREEN_ID = {{ screen.id }};
|
var SCREEN_ID = {{ screen.id }};
|
||||||
var SCREEN_EDIT_URL = "{{ url_for('screen_edit', slug=game.slug, screen_id=screen.id) }}";
|
var SCREEN_EDIT_URL = "{{ url_for('screen_edit', slug=game.slug, screen_id=screen.id) }}";
|
||||||
var SCENE_WIDTH = {{ screen.scene_width }};
|
// Borne le glisser-déposer/redimensionnement (static/js/scenes/
|
||||||
var SCENE_HEIGHT = {{ screen.scene_height }};
|
// scene-editor.js) au MONDE affiché (voir world_width/world_height,
|
||||||
|
// routes/scenes/scene_edit_view.py) — pas seulement à la scène
|
||||||
|
// nominale, sinon un "fond" plus grand qu'elle (voir "🎥 Champ de la
|
||||||
|
// caméra" ci-dessus) resterait injoignable par endroits une fois agrandi.
|
||||||
|
var SCENE_WIDTH = {{ world_width }};
|
||||||
|
var SCENE_HEIGHT = {{ world_height }};
|
||||||
var CURRENT_SELECTED_ID = {{ selected_id or 'null' }};
|
var CURRENT_SELECTED_ID = {{ selected_id or 'null' }};
|
||||||
var DEFINITIONS_DATA = {{ definitions_json|safe }};
|
var DEFINITIONS_DATA = {{ definitions_json|safe }};
|
||||||
var DEFINITIONS_NAMES = {{ definitions_names_json|safe }};
|
var DEFINITIONS_NAMES = {{ definitions_names_json|safe }};
|
||||||
|
|||||||
@@ -203,3 +203,39 @@ def test_deleting_element_cleans_up_its_animation_clips(client, game):
|
|||||||
screens.add_animation_clip(game, screen_id, element_id, kind="animate_css", animate_name="fadeIn")
|
screens.add_animation_clip(game, screen_id, element_id, kind="animate_css", animate_name="fadeIn")
|
||||||
screens.delete_element(game, element_id)
|
screens.delete_element(game, element_id)
|
||||||
assert screens.list_animation_clips(game, screen_id) == []
|
assert screens.list_animation_clips(game, screen_id) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_edit_view_world_matches_scene_when_no_oversized_fond(client, tmp_game_slug_cleanup):
|
||||||
|
"""Pas de "fond" plus grand que la scène -> le monde affiché reste
|
||||||
|
exactement la scène nominale, et le repère "🎥 Champ de la caméra"
|
||||||
|
(voir static/style.css .sceneCameraFrame) ne s'affiche pas — inutile
|
||||||
|
tant que rien ne dépasse."""
|
||||||
|
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||||
|
html = client.get(f"/game/{slug}/screens/{screen_id}/edit").get_data(as_text=True)
|
||||||
|
assert 'id="canvas" style="width:960px; height:540px;' in html
|
||||||
|
assert "sceneCameraFrame" not in html
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_edit_view_expands_world_for_an_oversized_fond(client, tmp_game_slug_cleanup):
|
||||||
|
"""Bug corrigé (glisser-déposer figé à (0,0) pour un objet plus grand
|
||||||
|
que la scène, voir static/js/scenes/scene-editor.js) : le canevas de
|
||||||
|
l'éditeur doit maintenant afficher tout le "fond", pas seulement la
|
||||||
|
scène nominale (960×540) qu'il dépasse — sinon la partie qui dépasse
|
||||||
|
resterait invisible/injoignable à la souris malgré le fix du glisser."""
|
||||||
|
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||||
|
fond_id = screens.add_scene_object(slug, screen_id, kind="fond")
|
||||||
|
screens.update_scene_object_geometry(slug, fond_id, x=0, y=0, width=1920, height=1080)
|
||||||
|
html = client.get(f"/game/{slug}/screens/{screen_id}/edit").get_data(as_text=True)
|
||||||
|
assert 'id="canvas" style="width:1920px; height:1080px;' in html
|
||||||
|
# Le repère de la caméra marque toujours les bornes de la scène NOMINALE (960×540),
|
||||||
|
# même si le canevas affiché est désormais bien plus grand.
|
||||||
|
assert 'class="sceneCameraFrame" style="width:960px; height:540px;' in html
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_edit_view_world_bounds_are_used_for_drag_clamping(client, tmp_game_slug_cleanup):
|
||||||
|
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||||
|
fond_id = screens.add_scene_object(slug, screen_id, kind="fond")
|
||||||
|
screens.update_scene_object_geometry(slug, fond_id, x=0, y=0, width=1920, height=1080)
|
||||||
|
html = client.get(f"/game/{slug}/screens/{screen_id}/edit").get_data(as_text=True)
|
||||||
|
assert "var SCENE_WIDTH = 1920;" in html
|
||||||
|
assert "var SCENE_HEIGHT = 1080;" in html
|
||||||
|
|||||||
Reference in New Issue
Block a user