Phase 7 : personnage animé par sprites (poses/images successives)
Ajoute une nouvelle action de flow "jouer_animation_sprite" qui joue une
séquence de PNG sur un élément image (cycle en boucle type marche, ou
une fois type saut) — réutilise target_element_id (déjà whitelisté) et
data_value en JSON {frames, fps, loop}, exactement le patron déjà établi
par "jouer_son" (Phase 6) et "alea" (Phase 2) : aucune nouvelle colonne,
aucune migration de schéma.
Ajoute une propriété d'élément "orientation" (Modifier un élément) pour
retourner un personnage en miroir (gauche/droite/bascule) sans nécessiter
une 2e feuille de sprites "vue de dos" — même patron que "surbrillance"/
"désactivé".
Étend aussi la Timeline d'animation existante (kind="sprite", aux côtés
de "animate_css"/"custom") pour qu'un personnage puisse animer tout seul
dès l'affichage de l'écran (ex. idle en boucle perpétuelle), pas
seulement en réaction à un événement — réutilise la colonne générique
custom_keyframes (JSON) et le réglage iteration_count déjà là pour la
boucle, aucune migration non plus. Les deux entrées (action de flow et
clip de timeline) partagent le même moteur côté client
(runSpriteAnimation()/activeSpriteAnimations dans static/js/play/
actions.js, indexé par nœud DOM plutôt que par id d'élément pour
supporter plusieurs instances d'un même écran-modèle animées
indépendamment).
Une bibliothèque de sprites Forge (2 personnages Kenney CC0, sous-
ensemble curé idle/marche/saut copié dans static/characters/) est
proposée dans l'éditeur, mais un créateur peut tout aussi bien utiliser
ses propres sprites uploadés (même route d'upload générique que le son
de la Phase 6).
Périmètre volontairement limité à ce qui a été demandé : pas d'avatar
modulable en couches (assemblage cheveux/haut/bas par le joueur),
écarté du plan initial à la demande de l'utilisateur.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
76331f9285
commit
d2c2f20b65
@@ -431,6 +431,11 @@
|
||||
<option value="{{ key }}">{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select id="nf-action-element-value-orientation" style="display:none; margin-top:6px;">
|
||||
{% for key, label in element_orientation_values %}
|
||||
<option value="{{ key }}">{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="color" id="nf-action-element-value-color" style="display:none; margin-top:6px;" value="#5b8cff">
|
||||
<input type="number" id="nf-action-element-value-number" style="display:none; margin-top:6px;" value="50" placeholder="Nouvelle valeur en %">
|
||||
<input type="text" id="nf-action-element-value-text" style="display:none; margin-top:6px;" placeholder="Nouveau texte affiché">
|
||||
@@ -500,6 +505,46 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 7 — personnage animé par sprites : joue une séquence de
|
||||
PNG (cycle en boucle type marche, ou une fois type saut) sur
|
||||
l'élément visé, depuis la bibliothèque Forge ou des sprites
|
||||
propres au créateur (même bouton d'upload que le son ci-dessus,
|
||||
mais ajoute une ligne plutôt que de remplacer le champ). -->
|
||||
<div id="nf-action-sprite-fields" style="display:none;">
|
||||
<label>Élément à animer
|
||||
<select id="nf-action-sprite-target-element">
|
||||
{% for e2 in elements %}
|
||||
<option value="{{ e2.id }}">{{ e2|elabel }} (elt-{{ e2.id }})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<label style="margin-top:6px; display:block;">Personnage Forge (optionnel)
|
||||
<select id="nf-action-sprite-library-character" onchange="onSpriteLibraryCharacterChange()">
|
||||
<option value="">— Choisir —</option>
|
||||
{% for slug, character in sprite_library.items() %}
|
||||
<option value="{{ slug }}">{{ character.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<select id="nf-action-sprite-library-animation" style="margin-top:6px; display:none;" onchange="applySpriteLibraryAnimation()"></select>
|
||||
<label style="margin-top:10px; display:block;">Images (une URL par ligne)
|
||||
<textarea id="nf-action-sprite-frames" rows="4" style="width:100%;" placeholder="https://.../frame1.png"></textarea>
|
||||
</label>
|
||||
<div style="margin-top:6px;">
|
||||
<label for="nf-action-sprite-upload" style="font-size:12px;">Ajouter un fichier :</label>
|
||||
<input type="file" id="nf-action-sprite-upload" accept="image/*" style="font-size:12px;">
|
||||
<span id="nf-action-sprite-upload-status" class="uploadStatus" style="font-size:12px; color:var(--text-dim);"></span>
|
||||
</div>
|
||||
<div class="fieldRow" style="margin-top:6px;">
|
||||
<label style="flex:1;">Images/seconde
|
||||
<input type="number" id="nf-action-sprite-fps" min="1" step="1" value="8">
|
||||
</label>
|
||||
<label style="flex:1; display:flex; align-items:center; gap:6px;">
|
||||
<input type="checkbox" id="nf-action-sprite-loop" checked style="width:auto;"> En boucle
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="nf-action-variable-fields" style="display:none;">
|
||||
{% if not global_variables %}
|
||||
<p class="hint">Aucune variable globale pour l'instant — crées-en une depuis "Condition de visibilité" dans les propriétés d'un élément.</p>
|
||||
@@ -570,6 +615,7 @@
|
||||
<select id="anim-clip-kind" onchange="toggleAnimClipKind()">
|
||||
<option value="animate_css">Animation Animate.css</option>
|
||||
<option value="custom">Animation personnalisée — images-clés</option>
|
||||
<option value="sprite">Animation de sprites</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@@ -592,6 +638,32 @@
|
||||
<button type="button" class="smallBtn button is-small" onclick="addAnimKeyframeRow()">+ Ajouter une image-clé</button>
|
||||
</div>
|
||||
|
||||
<!-- Phase 7 — même champs que le nœud de flow "Jouer une animation
|
||||
de sprites" (voir plus haut #nf-action-sprite-fields), formulaire
|
||||
indépendant : bibliothèque Forge ou sprites propres au créateur. -->
|
||||
<div id="anim-clip-sprite-fields" style="display:none;">
|
||||
<label>Personnage Forge (optionnel)
|
||||
<select id="anim-clip-sprite-library-character" onchange="onAnimClipSpriteLibraryCharacterChange()">
|
||||
<option value="">— Choisir —</option>
|
||||
{% for slug, character in sprite_library.items() %}
|
||||
<option value="{{ slug }}">{{ character.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<select id="anim-clip-sprite-library-animation" style="margin-top:6px; display:none;" onchange="applyAnimClipSpriteLibraryAnimation()"></select>
|
||||
<label style="margin-top:10px; display:block;">Images (une URL par ligne)
|
||||
<textarea id="anim-clip-sprite-frames" rows="4" style="width:100%;" placeholder="https://.../frame1.png"></textarea>
|
||||
</label>
|
||||
<div style="margin-top:6px;">
|
||||
<label for="anim-clip-sprite-upload" style="font-size:12px;">Ajouter un fichier :</label>
|
||||
<input type="file" id="anim-clip-sprite-upload" accept="image/*" style="font-size:12px;">
|
||||
<span id="anim-clip-sprite-upload-status" class="uploadStatus" style="font-size:12px; color:var(--text-dim);"></span>
|
||||
</div>
|
||||
<label style="margin-top:6px; display:block;">Images/seconde
|
||||
<input type="number" id="anim-clip-sprite-fps" min="1" step="1" value="8">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="fieldRow">
|
||||
<label style="flex:1;">Départ en secondes
|
||||
<input type="number" id="anim-clip-start" min="0" step="0.1" value="0">
|
||||
@@ -1144,6 +1216,8 @@
|
||||
var ELEMENT_VISIBILITY_LABELS_MAP = {{ element_visibility_labels_json|safe }};
|
||||
var ELEMENT_SURBRILLANCE_LABELS_MAP = {{ element_surbrillance_labels_json|safe }};
|
||||
var ELEMENT_DESACTIVE_LABELS_MAP = {{ element_desactive_labels_json|safe }};
|
||||
var ELEMENT_ORIENTATION_LABELS_MAP = {{ element_orientation_labels_json|safe }};
|
||||
var SPRITE_LIBRARY = {{ sprite_library_json|safe }};
|
||||
var DATA_OPERATION_LABELS_MAP = {{ data_operation_labels_json|safe }};
|
||||
var CONDITION_OPERATOR_LABELS_MAP = {{ condition_operator_labels_json|safe }};
|
||||
var TRIGGER_LABELS_MAP = {{ trigger_labels_json|safe }};
|
||||
|
||||
Reference in New Issue
Block a user