From d2c2f20b65b1043df35f9f4dd467bfd8c8252c52 Mon Sep 17 00:00:00 2001 From: william Date: Sun, 30 Aug 2026 19:18:07 +0200 Subject: [PATCH] =?UTF-8?q?Phase=207=20:=20personnage=20anim=C3=A9=20par?= =?UTF-8?q?=20sprites=20(poses/images=20successives)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- publish/build_package.py | 2 +- routes/screens/screen_edit.py | 4 + screens/__init__.py | 2 + screens/labels/action_type_labels.py | 1 + screens/labels/element_action_properties.py | 13 +++ screens/labels/sprite_library.py | 28 +++++ static/characters/LICENSE-kenney.txt | 23 ++++ static/characters/male-adventurer/idle.png | Bin 0 -> 4057 bytes static/characters/male-adventurer/jump.png | Bin 0 -> 3943 bytes static/characters/male-adventurer/walk0.png | Bin 0 -> 4106 bytes static/characters/male-adventurer/walk1.png | Bin 0 -> 3852 bytes static/characters/male-adventurer/walk2.png | Bin 0 -> 3760 bytes static/characters/male-adventurer/walk3.png | Bin 0 -> 3908 bytes static/characters/male-adventurer/walk4.png | Bin 0 -> 4017 bytes static/characters/male-adventurer/walk5.png | Bin 0 -> 3914 bytes static/characters/male-adventurer/walk6.png | Bin 0 -> 3696 bytes static/characters/male-adventurer/walk7.png | Bin 0 -> 3899 bytes static/characters/zombie/idle.png | Bin 0 -> 4112 bytes static/characters/zombie/jump.png | Bin 0 -> 4082 bytes static/characters/zombie/walk0.png | Bin 0 -> 4103 bytes static/characters/zombie/walk1.png | Bin 0 -> 3854 bytes static/characters/zombie/walk2.png | Bin 0 -> 3764 bytes static/characters/zombie/walk3.png | Bin 0 -> 3975 bytes static/characters/zombie/walk4.png | Bin 0 -> 4085 bytes static/characters/zombie/walk5.png | Bin 0 -> 3909 bytes static/characters/zombie/walk6.png | Bin 0 -> 3781 bytes static/characters/zombie/walk7.png | Bin 0 -> 3977 bytes static/js/play/actions.js | 68 ++++++++++++ static/js/play/screens.js | 14 +++ static/js/screen_edit/animation-timeline.js | 67 ++++++++++++ static/js/screen_edit/flow-editor.js | 59 +++++++++- static/js/screen_edit/panel-init.js | 49 +++++++++ templates/play.html | 3 + templates/screen_edit.html | 74 +++++++++++++ tests/test_sprite_animation.py | 115 ++++++++++++++++++++ 35 files changed, 519 insertions(+), 3 deletions(-) create mode 100644 screens/labels/sprite_library.py create mode 100644 static/characters/LICENSE-kenney.txt create mode 100644 static/characters/male-adventurer/idle.png create mode 100644 static/characters/male-adventurer/jump.png create mode 100644 static/characters/male-adventurer/walk0.png create mode 100644 static/characters/male-adventurer/walk1.png create mode 100644 static/characters/male-adventurer/walk2.png create mode 100644 static/characters/male-adventurer/walk3.png create mode 100644 static/characters/male-adventurer/walk4.png create mode 100644 static/characters/male-adventurer/walk5.png create mode 100644 static/characters/male-adventurer/walk6.png create mode 100644 static/characters/male-adventurer/walk7.png create mode 100644 static/characters/zombie/idle.png create mode 100644 static/characters/zombie/jump.png create mode 100644 static/characters/zombie/walk0.png create mode 100644 static/characters/zombie/walk1.png create mode 100644 static/characters/zombie/walk2.png create mode 100644 static/characters/zombie/walk3.png create mode 100644 static/characters/zombie/walk4.png create mode 100644 static/characters/zombie/walk5.png create mode 100644 static/characters/zombie/walk6.png create mode 100644 static/characters/zombie/walk7.png create mode 100644 tests/test_sprite_animation.py diff --git a/publish/build_package.py b/publish/build_package.py index a0c2e164..8a98ac70 100644 --- a/publish/build_package.py +++ b/publish/build_package.py @@ -23,7 +23,7 @@ _BASE_DIR = os.path.dirname(_PUBLISH_DIR) # Sous-ensemble de static/ réellement nécessaire au mode jouable (voir # templates/play.html) — jamais les assets propres à l'éditeur seul # (icônes de l'interface de l'éditeur mises à part, déjà dans icons/). -_STATIC_ITEMS = ["style.css", "csrf_fetch.js", "icons", "branding", "vendor/fonts", "vendor/animate.min.css", "js/play"] +_STATIC_ITEMS = ["style.css", "csrf_fetch.js", "icons", "branding", "vendor/fonts", "vendor/animate.min.css", "js/play", "characters"] _SLUG_PLACEHOLDER = "_SLUG_PLACEHOLDER" diff --git a/routes/screens/screen_edit.py b/routes/screens/screen_edit.py index 2123c7e3..3511a215 100644 --- a/routes/screens/screen_edit.py +++ b/routes/screens/screen_edit.py @@ -73,6 +73,9 @@ def screen_edit(slug, screen_id): element_visibility_labels=screens.ELEMENT_VISIBILITY_LABELS, element_surbrillance_values=screens.ELEMENT_SURBRILLANCE_VALUES, element_desactive_values=screens.ELEMENT_DESACTIVE_VALUES, + element_orientation_values=screens.ELEMENT_ORIENTATION_VALUES, + sprite_library=screens.SPRITE_LIBRARY, + sprite_library_json=json.dumps(screens.SPRITE_LIBRARY), data_operations=screens.DATA_OPERATIONS, data_operation_labels=screens.DATA_OPERATION_LABELS, definitions=definitions, definitions_json=json.dumps(definitions_data), @@ -86,6 +89,7 @@ def screen_edit(slug, screen_id): element_visibility_labels_json=json.dumps(screens.ELEMENT_VISIBILITY_LABELS), element_surbrillance_labels_json=json.dumps(screens.ELEMENT_SURBRILLANCE_LABELS), element_desactive_labels_json=json.dumps(screens.ELEMENT_DESACTIVE_LABELS), + element_orientation_labels_json=json.dumps(screens.ELEMENT_ORIENTATION_LABELS), data_operation_labels_json=json.dumps(screens.DATA_OPERATION_LABELS), condition_operator_labels_json=json.dumps(screens.CONDITION_OPERATOR_LABELS), trigger_labels_json=json.dumps(screens.TRIGGER_LABELS), diff --git a/screens/__init__.py b/screens/__init__.py index c66966d6..2e40a289 100644 --- a/screens/__init__.py +++ b/screens/__init__.py @@ -51,9 +51,11 @@ from .labels.element_action_properties import ( ELEMENT_ACTION_PROPERTIES, ELEMENT_ACTION_PROPERTY_LABELS, ELEMENT_SURBRILLANCE_VALUES, ELEMENT_SURBRILLANCE_LABELS, ELEMENT_DESACTIVE_VALUES, ELEMENT_DESACTIVE_LABELS, + ELEMENT_ORIENTATION_VALUES, ELEMENT_ORIENTATION_LABELS, ) from .labels.element_visibility import ELEMENT_VISIBILITY_VALUES, ELEMENT_VISIBILITY_LABELS from .labels.data_operations import DATA_OPERATIONS, DATA_OPERATION_LABELS +from .labels.sprite_library import SPRITE_LIBRARY from .flow.constants import ( TRIGGER_EVENTS, CONDITION_OPERATORS, CONDITION_OPERATOR_LABELS, CLICKED_ROW_ID, LAST_INSERTED_ROW_ID, diff --git a/screens/labels/action_type_labels.py b/screens/labels/action_type_labels.py index 7200e82e..5d78197c 100644 --- a/screens/labels/action_type_labels.py +++ b/screens/labels/action_type_labels.py @@ -11,5 +11,6 @@ ACTION_TYPE_LABELS = { "declencher_evenement": "Déclencher un événement", "ajouter_ligne": "Ajouter une ligne à un objet", "jouer_son": "Jouer un son", + "jouer_animation_sprite": "Jouer une animation de sprites", "rien": "Ne rien faire", } diff --git a/screens/labels/element_action_properties.py b/screens/labels/element_action_properties.py index 36633dbe..666236e0 100644 --- a/screens/labels/element_action_properties.py +++ b/screens/labels/element_action_properties.py @@ -39,6 +39,12 @@ ELEMENT_ACTION_PROPERTIES = [ ("pos_y", "Position verticale en % (absolue)"), ("pos_x_relatif", "Déplacer horizontalement de... % (relatif)"), ("pos_y_relatif", "Déplacer verticalement de... % (relatif)"), + # Phase 7 (moteur) — personnage animé par sprites : quel sens regarde + # l'élément (utile pour un personnage qui se déplace au clavier, voir + # applyElementProperty() dans static/js/play/actions.js — retourne + # l'élément en miroir plutôt que de nécessiter une 2e feuille de + # sprites "vue de dos"). + ("orientation", "Orientation — sens du personnage"), ] ELEMENT_ACTION_PROPERTY_LABELS = dict(ELEMENT_ACTION_PROPERTIES) @@ -55,3 +61,10 @@ ELEMENT_DESACTIVE_VALUES = [ ("toggle", "Basculer désactivé / réactivé"), ] ELEMENT_DESACTIVE_LABELS = dict(ELEMENT_DESACTIVE_VALUES) + +ELEMENT_ORIENTATION_VALUES = [ + ("droite", "Faire face à droite"), + ("gauche", "Faire face à gauche"), + ("toggle", "Retourner (miroir)"), +] +ELEMENT_ORIENTATION_LABELS = dict(ELEMENT_ORIENTATION_VALUES) diff --git a/screens/labels/sprite_library.py b/screens/labels/sprite_library.py new file mode 100644 index 00000000..a8452e04 --- /dev/null +++ b/screens/labels/sprite_library.py @@ -0,0 +1,28 @@ +# ---------- Bibliothèque de sprites bundlée avec Forge (Phase 7) ---------- +# +# Sous-ensemble curé (idle/marche/saut, pas les packs complets HD/Parts/ +# Tilesheet/Vector — inutiles pour un jeu 2D web) des personnages "Toon +# Characters" de Kenney (CC0, voir static/characters/LICENSE-kenney.txt), +# copiés dans static/characters//*.png. Un créateur qui veut ses +# propres sprites n'utilise pas ce catalogue : il uploade ses images (voir +# routes/uploads/upload_file.py) et colle leurs URLs directement dans la +# même zone de frames — voir #nf-action-sprite-fields dans +# screen_edit.html. +SPRITE_LIBRARY = { + "male-adventurer": { + "label": "Aventurier", + "animations": { + "idle": ["/static/characters/male-adventurer/idle.png"], + "marche": [f"/static/characters/male-adventurer/walk{i}.png" for i in range(8)], + "saut": ["/static/characters/male-adventurer/jump.png"], + }, + }, + "zombie": { + "label": "Zombie", + "animations": { + "idle": ["/static/characters/zombie/idle.png"], + "marche": [f"/static/characters/zombie/walk{i}.png" for i in range(8)], + "saut": ["/static/characters/zombie/jump.png"], + }, + }, +} diff --git a/static/characters/LICENSE-kenney.txt b/static/characters/LICENSE-kenney.txt new file mode 100644 index 00000000..918d58da --- /dev/null +++ b/static/characters/LICENSE-kenney.txt @@ -0,0 +1,23 @@ + + + Toon Characters + + Created/distributed by Kenney (www.kenney.nl) + Creation date: 26-09-2019 + + ------------------------------ + + License: (Creative Commons Zero, CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + This content is free to use in personal, educational and commercial projects. + Support us by crediting Kenney or www.kenney.nl (this is not mandatory) + + ------------------------------ + + Donate: http://support.kenney.nl + Request: http://request.kenney.nl + Patreon: http://patreon.com/kenney/ + + Follow on Twitter for updates: + http://twitter.com/KenneyNL \ No newline at end of file diff --git a/static/characters/male-adventurer/idle.png b/static/characters/male-adventurer/idle.png new file mode 100644 index 0000000000000000000000000000000000000000..5f596a3b372e473853dc2400137715c0921a522f GIT binary patch literal 4057 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 Bz&-!~ literal 0 HcmV?d00001 diff --git a/static/characters/male-adventurer/walk0.png b/static/characters/male-adventurer/walk0.png new file mode 100644 index 0000000000000000000000000000000000000000..bbceaf0b290cb4d6f19799ef769b558e57136dab GIT binary patch literal 4106 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 a2mB9GAtBS6#z?^c0000dL99a#^c* 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 JPDHLkV1gd{tyKU3 literal 0 HcmV?d00001 diff --git a/static/characters/zombie/idle.png b/static/characters/zombie/idle.png new file mode 100644 index 0000000000000000000000000000000000000000..7b9ca55c11288b59f2f70e748ae62ff0717bde9d GIT binary patch literal 4112 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 O0000RDj%@WkN$mLq$hK zMo31qm`b>uLZ^*MzM@30lSi?bQC3_?u$D$hN=i;pSy`%5SYJ#}Qb$NjMXZxgk((`{ zgG)?NPEl1$O;JouQAw?oMMYCuvXB4(0I8CAHh6ZBiGWpqvTkBf*2EcWv0PBDjkca> zEnjywsC|leq@lYyLaU)$d%8kVRYGlNTWGXKke^g^t~{NXF^r2*t!zYCS~OFDl(|Dg zs&#y|QBa7iU2(aZp>aB0jEbOiH%5X$Uzp34W%0=fVQaoim#H{yV#L8Dm3ft6sf0jl zm#c+|DQ$Ezn0`B6SYEGWM5CfGig!L`UmtvCeQlmTih3uRd^^3IJA9KlMMOQfnckXU zKfawfQ%^>@n@GW;L#dByY`r{nY94}VM!lbca->4Qpgfg;JbiCxYP>_Rl-rhEHlBn= zvzS4)m_E9jJU&2WXv0-ks7+6vOiiWYont++l_ijMKdzELyqzqmiW_`m)stG=m02^P zg+HT;*Op*WRa`Kxjx@8ANlTVxXS*n&f;*pvQB$TwMwvoIN+_j;JgbjcTdX`jh&i;C zTV1eMTB$Xph}e=?U0<^&oquF!!Z^5?NK8{QG&e;?Nj9&L-j-TTQdmAfjYdeFJ*JE{ zs*O3bluA!lI<}WKI66Z_ltDw1Hm8a=t&cxJL|$RHJwHN7N}=JHT4ZOzK|@6}HaIx2 zl0!&OV`jfRy`2Bd0AgjmU}L&Gyqx5kTs*#=Iy^o*x|%pTJv%)>MM_aAriMMgo;*H5 zlEkW<00016bW%=JS6^Q%Z*T9<&p)p}f3L5fug|ZK@8GzpVb4~&X$$`}W_@RvRf#3H$ z;~gh&?(o0Ox?=_~1DFBK0A>I)fEmCHV7$Da{WI@&0(klP`F~k_8v#D~EiL(LJ#HUh zZA)ioXG^~KmN8eiZ2a5WXMYyJ#+FX=zyKiD`tWS#&%B(U-;$rd@n-<=*0wY#tyXmd z1hLlJ*Vos>`vEY=sDR0H9pKZ_S!OkvOiD8tLNOTgh6b~_p`m5H%YeoCoee6J$!fK# z%nhB4z}yUJ8!&gi>?(lw00cn%L1l2yD0D}EP=l|FfM=k>R>mKKC^NGf7$}3lRBCV6 z0P7(^N}E4H4AB1O0hPgEu&Ot?1lXA0(l9XEpH38=A(dgoU{Xt60T6%dc&V5O3;-}F zrCX*CfGMKEth@z)A%K4w07eWdsqb_F8=q}~W-qf&2!ISJrwj1#LBUi2!)Zc)tCB=u znl8W{##0M3SO=^V1HfNxAb_dYfM=Gf)#?FyG+8GD4A21}V5(i@Ayuoa@S!f7%%1?P zCX4{ubpBKU-f9*8t;uAvS|LIvQ>=oK;EP zr@kgb4ID;rILiXk4;7mXDn}Wb6fj?X)Pl z(^*y7rfKYpUWJu#B0%ubpb(2?GyulKbO2aogCRaBVNbZt`|#1AV#_!oKxzYcy1Dsr zo=qV~hIpM$ueUf707j)~QDkJ~6Dzp^d>}`L7z8A24T{g5*gn@nip&C5Mn;|jz2N4_ z0RThIY6#a2=`HmBg(nM!Na)Us@3v7bX;@riPq3ld_2K6tD>=?D!#lt_=`m zyLmg401n5+MXp}Z9v2rjq|+IVA#xxrbPDi6Knz4+X$lOC*>m)Lv%Q7r+c$3wk`$9+ ztqY5bYpM(j8yW)tdU<6=Mq-MmGk`Aw!T}(nKHa-_?>0(w!Ujk%o8ONKq(lWq0tnC6 zfjRU82|zCI&}gy}S2_c%Lx8DLUqF3%1NC1@WCKWoE>YXQ_~LbnLV)RTdA1(K20#Ft zod6a_9Jazhj@M^XUl70ziZa>=1=L==w2h+nSWUs1<>dvmKL!B)3W>xSz%AuW0t{tS zLVdX%P+$X4pVHU9q(rjfx^e=b{V{+hg+dbL7_cVgOh!B|w+WTy)V5my1=JDx+7Sp# zUrqqb{gVLN+a*zc4go7tGBkDJ21Bq60AGGj*8l-0>g$bT0rmQ91knC;f)wo%Nfh4^ zz%wN=!>jIiV7x>(R9;Sf`kxy&_EO+w6v1aGb^-PF_e_dt0A;lMH$eb0$qI+#z%MZ? zqpq%wG8%P5qH>B+wnapL0|4rEAbfv>VgU6z+F#y564Wk>TIUe3834!Y>cj{zvi?*( z1IV_JYe$Z}jbHT8XEuMj0KGEV0>^WaUrGi>AT9uazMk=iVPMS0uQ1?5HmZnjA6)_K zuW0Y>l|{Ye7{G@n@&bSe0eVXT`qC|Agc=u!EGM$rw4Klo3B!b`3USjYf7t?Ov+3O_ zXPU%fakh>C#wa`ULM(I>fkHI;p)g_CqQ|_%;wIL=*It210V^ZUglH%+H6CCT$6mN_ zAyaN44O?%7{0N19{)^Ma5U+;ym%ZkE!C4Uzk(yc{8V3-8d+c$!ea(mIO(^tVd}lgT z?6{cqU%+8S<1acD0gJ~tfbl|Xw$U=iUzd9KtUJ@w>yCrGX#dTe)@1%K7M+6SPd7A% zARk=~W_Gx%uP?o?udS{0o6MSV`El};>F4IQdV(sCxqqYaWLq2Bx0M1QvqmOc<;fYa zVb(qAx^W?l_s=*`3PStRZU7vY$zJ06oIHDONl8iVyOR?1AAfxEBHLH##;#O3NNqB%pbnJ+}heIsHiCE?k4u#J%O2-fzNT;IzB&p zF50K34-RiP8rd>5HKFkZ)UjiqUq=6)p0w%;@CN^$p6;G+0w3eBH=XsXifY=vuTQJ} z%4iILRP5Z@+WJ;(Z0xaP$I$+*%a;kDu%x=W0<6&=J{K0woxQ<%1WzAe>;W)5e6_YV ztquRawe|83gm4V9LjXO3v}zD~GxoDKIFEq;TusdPU5Lz#P{yCc+;tmop_D?;}<@sRE3#U3@ zV%&-DFnH1t@WF>bs7h-ih{D2FR5v8Qx&r@K6ry`!;XR&Q9zeifm|9K;(1scY!UviU zuM$LQcTaa(8YZL!j9GP;g8fr-I6dL;p8)?jAb(xoVcz87>0Dyk}~ z7}Zu6777FpZQ%3>#a|R5OogSD0MK60R}KE!k191E4bzA!_*YRoTGfKN4|#HYMq2?( z00Knfx|1gXA`m?Fry?W-$OE((%2lM0e~fC2ik|2G^8P|t#n2x@faT+)Ku|Kr)4!-_ z7)M+ESA$v*Kt8y7b=an&qSM^Z57vQyNIm+8h!9XR2NU~nQIS?VxZSw>Tz~)IpmtY4 z7J{^Z8-yQ=PCv{Ykdl%imlJ?oF0S)BKp&>OavA~s0U_s5?}Zq*4-WSC_n*6R?n*xZ zqF><*z?}*Z3`@zw;8<0SmJv3PlqlG_Zlv z^d>V85dVy30RjKgG6KXq(FE{2?ts@2plAX_6FvdS4m~#-fTG92uoeb}cHhnKux(Et ze33gqB7uFqf)+di9ZDVtpzVpk|K`nug9uo{=M0d^dVAY#8V{gvpUe-#!~3q?Bm`~I z!SnOD0#?gpHLx*bB{_5-19<00R{vwPulX7w?ECS@gQ3nsuy+vxY6t^ANe(?tU;oGX z^JsSM+O_7KpJ?R(fDqtnXy}U^0qb&eYc5@?VI*6{_yd5kvibj%lhZs3Fpuk8vfr^THoQ->lJwq4s9<=@HZ<2DFn|Ek5`@jA!@6oB8i1Ynu zvHp*;8EVeCn0K%J#j1br*s)_j%qj{=)_#|c+<$pKl<6U;rmf?7^HsrnaOQ$ZE9=)T z0hWY@(%q7ilxOcpZ+Pv$D>wlV5=qu-R{)O^|2Mz>4gr6#znW(q>AHTsD?AY9ti*M$ z0Oo~4w|ost5Ek=6TY{7Z@JEFwOIEq^wg>*>Z|vXy2ED{3{?V2oscNLFkpQ|zVm7-1 z*tj(w7dcc`B0Kba8_HA=L1Sa%^~UR6s`ah_+?9slJ%_MaG+B?^kH?>cGd4m1fOVM* zfGt?euCCyiWW|_f;rZb42qLa`nU=Z$fNsQQ0fi^X){H?fSHckw7QvwOojzbG>Bj4{ z&$yE^-%Wt%f-0-Lrw#B>LjY{IsFvSy$}=BMc}7f1_h|!`VTKx+ZZWBEJ?!&Yis!*n z-ZTL`sru{)O=xWFGTa&h{ED|)Eq!vj0FNi7SV^b?9m3LyjJ7Om@R)v)J(e$3o`rtw zB2`fOO#H4IR|c9t@6}~$6=6V*mQMX0WL(}?0SqO)J;vnl(AX6K!%!+69U8j`z+$d< kmoE3ejR0g!s|5c42RTq$FR@L1umAu607*qoM6N<$g4ox2asU7T literal 0 HcmV?d00001 diff --git a/static/characters/zombie/walk0.png b/static/characters/zombie/walk0.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbaaf3720970e0fafc6dab478f1e656e2b6d33a GIT binary patch literal 4103 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 FV1njwY#{&u literal 0 HcmV?d00001 diff --git a/static/characters/zombie/walk1.png b/static/characters/zombie/walk1.png new file mode 100644 index 0000000000000000000000000000000000000000..cb80d3009f434f0a6ac00acae9ea15278238a8f6 GIT binary patch literal 3854 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 literal 0 HcmV?d00001 diff --git a/static/characters/zombie/walk2.png b/static/characters/zombie/walk2.png new file mode 100644 index 0000000000000000000000000000000000000000..026ec77ca9d0aefdb9d06e9467c14a54135494a8 GIT binary patch literal 3764 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 jhYw!C- 0 ? spriteData.fps : 8; + var loop = !!spriteData.loop; + if (activeSpriteAnimations.has(targetEl)) { + clearInterval(activeSpriteAnimations.get(targetEl)); + activeSpriteAnimations.delete(targetEl); + } + if (!frames.length) return; + var frameIndex = 0; + targetEl.src = frames[0]; + if (frames.length === 1) return; + var intervalId = setInterval(function() { + frameIndex++; + if (frameIndex >= frames.length) { + if (!loop) { clearInterval(intervalId); activeSpriteAnimations.delete(targetEl); return; } + frameIndex = 0; + } + targetEl.src = frames[frameIndex]; + }, 1000 / fps); + activeSpriteAnimations.set(targetEl, intervalId); +} + +// Appelée depuis showScreen() (screens.js) à chaque changement d'écran — +// encapsule activeSpriteAnimations ici plutôt que de le manipuler +// directement depuis screens.js, même patron que runScreenTimerTriggers() +// dans triggers.js (l'appelant ne connaît jamais la structure interne). +function stopAllSpriteAnimations() { + activeSpriteAnimations.forEach(function(intervalId) { clearInterval(intervalId); }); + activeSpriteAnimations.clear(); +} diff --git a/static/js/play/screens.js b/static/js/play/screens.js index 66cb69c7..1d8aa7e8 100644 --- a/static/js/play/screens.js +++ b/static/js/play/screens.js @@ -38,6 +38,11 @@ function showScreen(id) { window.currentScreenId = id; applyScreenAspect(el.dataset.aspect || '9/16'); } + // Phase 7 — nettoie les animations de sprites de l'écran quitté (sinon + // une boucle setInterval reste active sur un élément désormais caché, + // mirroring le nettoyage déjà fait pour activeTimerTriggerIntervals + // dans triggers.js). + stopAllSpriteAnimations(); runScreenShowTriggers(id); runScreenTimerTriggers(id); runAnimationTimeline(id); @@ -141,6 +146,15 @@ function applyAnimationClip(clip) { target.removeEventListener('animationend', handler); }); } + } else if (clip.kind === 'sprite') { + // Phase 7 — même moteur que l'action de flow "jouer_animation_sprite" + // (voir runSpriteAnimation() dans actions.js) : custom_keyframes + // stocke ici {frames, fps} en JSON plutôt que des images-clés CSS + // (réutilise la colonne générique existante, pas de nouveau champ). + var spriteData = {}; + try { spriteData = JSON.parse(clip.custom_keyframes || '{}'); } catch (e) { /* invalide : rien à jouer */ } + spriteData.loop = infinite; + setTimeout(function() { runSpriteAnimation(target, spriteData); }, delay * 1000); } else { var animClass = 'animate__' + clip.animate_name; target.style.setProperty('--animate-duration', duration + 's'); diff --git a/static/js/screen_edit/animation-timeline.js b/static/js/screen_edit/animation-timeline.js index 0d383370..ad69c17e 100644 --- a/static/js/screen_edit/animation-timeline.js +++ b/static/js/screen_edit/animation-timeline.js @@ -9,6 +9,11 @@ var ANIM_SCREEN_ID = SCREEN_ID; var ANIM_PX_PER_SEC = 60; var animCurrentClipId = null; +// Phase 7 — aperçu d'un clip "sprite" dans l'éditeur (voir previewAnimClip +// ci-dessous) : un intervalle à la fois suffit ici (contrairement au +// moteur de jeu, static/js/play/actions.js, PAS chargé sur cette page — +// runSpriteAnimation()/activeSpriteAnimations n'existent que côté jeu). +var animPreviewSpriteInterval = null; function animUrl(path) { return "/game/" + GAME_SLUG + path; } @@ -165,6 +170,32 @@ function toggleAnimClipKind() { var kind = document.getElementById('anim-clip-kind').value; document.getElementById('anim-clip-animate-css-fields').style.display = kind === 'animate_css' ? 'block' : 'none'; document.getElementById('anim-clip-custom-fields').style.display = kind === 'custom' ? 'block' : 'none'; + document.getElementById('anim-clip-sprite-fields').style.display = kind === 'sprite' ? 'block' : 'none'; +} + +// Phase 7 — même mécanisme que onSpriteLibraryCharacterChange()/ +// applySpriteLibraryAnimation() dans flow-editor.js, pour le formulaire de +// clip de Timeline (DOM distinct, pas d'état partagé entre les deux formulaires). +function onAnimClipSpriteLibraryCharacterChange() { + var charSel = document.getElementById('anim-clip-sprite-library-character'); + var animSel = document.getElementById('anim-clip-sprite-library-animation'); + var slug = charSel.value; + animSel.innerHTML = ''; + if (!slug || !SPRITE_LIBRARY[slug]) { animSel.style.display = 'none'; return; } + Object.keys(SPRITE_LIBRARY[slug].animations).forEach(function(name) { + var opt = document.createElement('option'); + opt.value = name; opt.textContent = name; + animSel.appendChild(opt); + }); + animSel.style.display = 'block'; + applyAnimClipSpriteLibraryAnimation(); +} + +function applyAnimClipSpriteLibraryAnimation() { + var slug = document.getElementById('anim-clip-sprite-library-character').value; + var name = document.getElementById('anim-clip-sprite-library-animation').value; + if (!slug || !name || !SPRITE_LIBRARY[slug]) return; + document.getElementById('anim-clip-sprite-frames').value = SPRITE_LIBRARY[slug].animations[name].join('\n'); } function addAnimKeyframeRow(percent, cssText) { @@ -229,6 +260,14 @@ function openAnimClipForm(clip) { var cssText = Object.keys(k.props || {}).map(function(p) { return p + ': ' + k.props[p] + ';'; }).join(' '); addAnimKeyframeRow(k.percent, cssText); }); + // Phase 7 — clip.custom_keyframes stocke {frames, fps} en JSON pour un + // clip kind="sprite" (pas une liste d'images-clés CSS, voir ci-dessus). + var spriteData = {}; + if (clip.kind === 'sprite' && clip.custom_keyframes) { + try { spriteData = JSON.parse(clip.custom_keyframes); } catch (e) { /* ignore */ } + } + document.getElementById('anim-clip-sprite-frames').value = (spriteData.frames || []).join('\n'); + document.getElementById('anim-clip-sprite-fps').value = spriteData.fps || 8; toggleAnimClipKind(); document.querySelectorAll('.animClip').forEach(function(b) { b.classList.toggle('selected', parseInt(b.dataset.clipId, 10) === clip.id); @@ -254,6 +293,18 @@ function saveAnimClipForm() { iteration_count: document.getElementById('anim-clip-iteration').value, }; if (kind === 'custom') fields.custom_keyframes = collectAnimKeyframes(); + if (kind === 'sprite') { + // Phase 7 — {frames, fps} en JSON dans custom_keyframes (colonne + // générique déjà réutilisée par le kind "custom" ci-dessus pour ses + // images-clés) ; la boucle est déjà portée par iteration_count + // (1/2/3/infinite, ci-dessus) — aucun champ dédié nécessaire. + var frames = document.getElementById('anim-clip-sprite-frames').value + .split('\n').map(function(s) { return s.trim(); }).filter(Boolean); + fields.custom_keyframes = { + frames: frames, + fps: parseInt(document.getElementById('anim-clip-sprite-fps').value, 10) || 8, + }; + } return updateAnimClip(animCurrentClipId, fields).then(function() { renderAnimTimeline(); }); } @@ -296,6 +347,22 @@ function previewAnimClip() { target.style.animation = ''; target.removeEventListener('animationend', handler); }); + } else if (clip.kind === 'sprite') { + var spriteData = {}; + try { spriteData = JSON.parse(clip.custom_keyframes || '{}'); } catch (e) { /* ignore */ } + var frames = spriteData.frames || []; + var fps = spriteData.fps > 0 ? spriteData.fps : 8; + if (animPreviewSpriteInterval) { clearInterval(animPreviewSpriteInterval); animPreviewSpriteInterval = null; } + if (frames.length) { + var frameIndex = 0; + target.src = frames[0]; + if (frames.length > 1) { + animPreviewSpriteInterval = setInterval(function() { + frameIndex = (frameIndex + 1) % frames.length; + target.src = frames[frameIndex]; + }, 1000 / fps); + } + } } else { var animClass = 'animate__' + clip.animate_name; target.style.setProperty('--animate-duration', duration + 's'); diff --git a/static/js/screen_edit/flow-editor.js b/static/js/screen_edit/flow-editor.js index b59349b2..0f88348f 100644 --- a/static/js/screen_edit/flow-editor.js +++ b/static/js/screen_edit/flow-editor.js @@ -91,6 +91,8 @@ function nodeLabel(node) { base += ' = ' + (ELEMENT_SURBRILLANCE_LABELS_MAP[node.element_value] || node.element_value); } else if (node.element_property === 'desactive') { base += ' = ' + (ELEMENT_DESACTIVE_LABELS_MAP[node.element_value] || node.element_value); + } else if (node.element_property === 'orientation') { + base += ' = ' + (ELEMENT_ORIENTATION_LABELS_MAP[node.element_value] || node.element_value); } else if (node.element_value && node.element_value.indexOf('||') !== -1) { var vparts = node.element_value.split('||'); base += ' = ' + vparts[0] + ' ↔ ' + vparts[1] + ' (va-et-vient)'; @@ -115,6 +117,12 @@ function nodeLabel(node) { base += ' → ' + (DEFINITIONS_NAMES[node.target_definition_id] || '?'); } else if (node.action_type === 'jouer_son') { base += ' « ' + (node.data_value || '?') + ' »'; + } else if (node.action_type === 'jouer_animation_sprite') { + base += ' → ' + (ELEMENTS_LABELS[node.target_element_id] || '?'); + try { + var spriteData = JSON.parse(node.data_value || '{}'); + base += ' (' + (spriteData.frames ? spriteData.frames.length : 0) + ' images, ' + (spriteData.fps || '?') + ' i/s' + (spriteData.loop ? ', boucle' : '') + ')'; + } catch (e) { /* data_value invalide : pas de détail affiché */ } } return base; } @@ -500,8 +508,10 @@ function toggleFlowActionFields() { var eventFields = document.getElementById('nf-action-event-fields'); var addRowFields = document.getElementById('nf-action-add-row-fields'); var soundFields = document.getElementById('nf-action-sound-fields'); + var spriteFields = document.getElementById('nf-action-sprite-fields'); var isOnglet = typeSel.value === 'activer_onglet'; soundFields.style.display = typeSel.value === 'jouer_son' ? 'block' : 'none'; + spriteFields.style.display = typeSel.value === 'jouer_animation_sprite' ? 'block' : 'none'; screenSel.style.display = (typeSel.value === 'aller_a' || typeSel.value === 'ouvrir_ligne') ? 'block' : 'none'; elementFields.style.display = (typeSel.value === 'modifier_element' || isOnglet) ? 'block' : 'none'; dataFields.style.display = typeSel.value === 'modifier_donnee' ? 'block' : 'none'; @@ -528,16 +538,44 @@ function updateDataValuePlaceholder(operationSelectId, valueInputId) { valueInp.placeholder = opSel.value === 'alea' ? 'min,max (ex. 1,6)' : 'Valeur / montant'; } +// Phase 7 — bibliothèque de sprites Forge (SPRITE_LIBRARY, injecté par +// screen_edit.html) : choisir un personnage puis une de ses animations +// pré-remplit la zone de frames — un créateur qui préfère ses propres +// sprites laisse simplement ce sélecteur sur "— Choisir —" et remplit/ +// uploade directement dans la zone de frames. +function onSpriteLibraryCharacterChange() { + var charSel = document.getElementById('nf-action-sprite-library-character'); + var animSel = document.getElementById('nf-action-sprite-library-animation'); + var slug = charSel.value; + animSel.innerHTML = ''; + if (!slug || !SPRITE_LIBRARY[slug]) { animSel.style.display = 'none'; return; } + Object.keys(SPRITE_LIBRARY[slug].animations).forEach(function(name) { + var opt = document.createElement('option'); + opt.value = name; opt.textContent = name; + animSel.appendChild(opt); + }); + animSel.style.display = 'block'; + applySpriteLibraryAnimation(); +} + +function applySpriteLibraryAnimation() { + var slug = document.getElementById('nf-action-sprite-library-character').value; + var name = document.getElementById('nf-action-sprite-library-animation').value; + if (!slug || !name || !SPRITE_LIBRARY[slug]) return; + document.getElementById('nf-action-sprite-frames').value = SPRITE_LIBRARY[slug].animations[name].join('\n'); +} + function toggleFlowElementPropertyValue() { var propSel = document.getElementById('nf-action-element-property'); var visSel = document.getElementById('nf-action-element-value-visibility'); var surbrillanceSel = document.getElementById('nf-action-element-value-surbrillance'); var desactiveSel = document.getElementById('nf-action-element-value-desactive'); + var orientationSel = document.getElementById('nf-action-element-value-orientation'); var colorInp = document.getElementById('nf-action-element-value-color'); var numInp = document.getElementById('nf-action-element-value-number'); var textInp = document.getElementById('nf-action-element-value-text'); var toggleRow = document.getElementById('nf-action-element-toggle-row'); - [visSel, surbrillanceSel, desactiveSel, colorInp, numInp, textInp].forEach(function(el){ el.style.display = 'none'; }); + [visSel, surbrillanceSel, desactiveSel, orientationSel, colorInp, numInp, textInp].forEach(function(el){ el.style.display = 'none'; }); if (propSel.value === 'visibilite') { visSel.style.display = 'block'; toggleRow.style.display = 'none'; @@ -550,6 +588,10 @@ function toggleFlowElementPropertyValue() { desactiveSel.style.display = 'block'; toggleRow.style.display = 'none'; document.getElementById('nf-action-element-toggle').checked = false; + } else if (propSel.value === 'orientation') { + orientationSel.style.display = 'block'; + toggleRow.style.display = 'none'; + document.getElementById('nf-action-element-toggle').checked = false; } else if (propSel.value === 'contenu') { textInp.style.display = 'block'; toggleRow.style.display = 'none'; @@ -646,13 +688,15 @@ function submitNodeForm() { var prop = document.getElementById('nf-action-element-property').value; payload.element_property = prop; var isColorProp = prop === 'bg_color' || prop === 'border_color'; - var toggleOn = prop !== 'visibilite' && prop !== 'surbrillance' && prop !== 'desactive' && document.getElementById('nf-action-element-toggle').checked; + var toggleOn = prop !== 'visibilite' && prop !== 'surbrillance' && prop !== 'desactive' && prop !== 'orientation' && document.getElementById('nf-action-element-toggle').checked; if (prop === 'visibilite') { payload.element_value = document.getElementById('nf-action-element-value-visibility').value; } else if (prop === 'surbrillance') { payload.element_value = document.getElementById('nf-action-element-value-surbrillance').value; } else if (prop === 'desactive') { payload.element_value = document.getElementById('nf-action-element-value-desactive').value; + } else if (prop === 'orientation') { + payload.element_value = document.getElementById('nf-action-element-value-orientation').value; } else if (prop === 'contenu') { payload.element_value = document.getElementById('nf-action-element-value-text').value; } else { @@ -695,6 +739,17 @@ function submitNodeForm() { // sur le nœud action, comme pour "attendre") plutôt qu'une nouvelle // colonne dédiée. payload.data_value = document.getElementById('nf-action-sound-url').value; + } else if (actionType === 'jouer_animation_sprite') { + // Phase 7 — réutilise target_element_id (déjà whitelisté) + + // data_value en JSON {frames, fps, loop}, même patron que jouer_son. + payload.target_element_id = parseInt(document.getElementById('nf-action-sprite-target-element').value, 10); + var frames = document.getElementById('nf-action-sprite-frames').value + .split('\n').map(function(s) { return s.trim(); }).filter(Boolean); + payload.data_value = JSON.stringify({ + frames: frames, + fps: parseInt(document.getElementById('nf-action-sprite-fps').value, 10) || 8, + loop: document.getElementById('nf-action-sprite-loop').checked, + }); } } diff --git a/static/js/screen_edit/panel-init.js b/static/js/screen_edit/panel-init.js index d560661f..0912b962 100644 --- a/static/js/screen_edit/panel-init.js +++ b/static/js/screen_edit/panel-init.js @@ -70,6 +70,55 @@ function initBuilderPanel() { }); }); + // Phase 7 — sprites propres au créateur : contrairement aux autres + // champs d'upload (qui REMPLACENT la valeur d'un champ texte unique), + // chaque fichier envoyé ici AJOUTE une ligne à la zone de frames — un + // personnage animé a besoin de plusieurs images, pas d'une seule. + var spriteUploadInput = document.getElementById('nf-action-sprite-upload'); + if (spriteUploadInput) { + spriteUploadInput.addEventListener('change', function () { + if (!spriteUploadInput.files.length) return; + var status = document.getElementById('nf-action-sprite-upload-status'); + var framesField = document.getElementById('nf-action-sprite-frames'); + status.textContent = 'Envoi en cours...'; + var data = new FormData(); + data.append('file', spriteUploadInput.files[0]); + fetch("/game/" + GAME_SLUG + "/upload", { method: 'POST', body: data }) + .then(function (r) { return r.json(); }) + .then(function (json) { + if (json.url) { + framesField.value = framesField.value ? (framesField.value + '\n' + json.url) : json.url; + status.textContent = 'Fichier envoyé ✓'; + } else { status.textContent = "Échec de l'envoi."; } + }) + .catch(function () { status.textContent = "Échec de l'envoi."; }); + }); + } + + // Phase 7 — même mécanisme d'upload que nf-action-sprite-upload + // ci-dessus (ajoute une ligne plutôt que de remplacer), pour le + // formulaire de clip de la Timeline d'animation. + var animClipSpriteUploadInput = document.getElementById('anim-clip-sprite-upload'); + if (animClipSpriteUploadInput) { + animClipSpriteUploadInput.addEventListener('change', function () { + if (!animClipSpriteUploadInput.files.length) return; + var status = document.getElementById('anim-clip-sprite-upload-status'); + var framesField = document.getElementById('anim-clip-sprite-frames'); + status.textContent = 'Envoi en cours...'; + var data = new FormData(); + data.append('file', animClipSpriteUploadInput.files[0]); + fetch("/game/" + GAME_SLUG + "/upload", { method: 'POST', body: data }) + .then(function (r) { return r.json(); }) + .then(function (json) { + if (json.url) { + framesField.value = framesField.value ? (framesField.value + '\n' + json.url) : json.url; + status.textContent = 'Fichier envoyé ✓'; + } else { status.textContent = "Échec de l'envoi."; } + }) + .catch(function () { status.textContent = "Échec de l'envoi."; }); + }); + } + bindPropsAutosave(); bindJaugeDefinitionSelect(); bindDefinitionFieldSelects('field-definition_id', ['field-filtre_champ', 'field-filtre2_champ']); diff --git a/templates/play.html b/templates/play.html index c5715d78..b068393c 100644 --- a/templates/play.html +++ b/templates/play.html @@ -52,6 +52,9 @@ /* 3.5 (Confort) — verrouillage d'un élément après décision : grisé + inerte, posé/enlevé par une action "Modifier un élément → Désactivé". */ .forgeDisabled{ opacity:0.45; filter:grayscale(60%); pointer-events:none; } + /* Phase 7 — personnage animé par sprites : retourne l'élément en miroir + plutôt que de nécessiter une 2e feuille de sprites "vue de dos". */ + .forgeFlipped{ transform: scaleX(-1); } diff --git a/templates/screen_edit.html b/templates/screen_edit.html index aa9fa8c7..ff67e28c 100644 --- a/templates/screen_edit.html +++ b/templates/screen_edit.html @@ -431,6 +431,11 @@ {% endfor %} + @@ -500,6 +505,46 @@ + +

+ + + +