Animations de FreeMinecraftModels
Cette page documente ce que FreeMinecraftModels fait réellement des données d'animation contenues dans un fichier .bbmodel ou .fmmodel : quels noms sont spéciaux, comment les keyframes sont précalculées, quels modes d'interpolation et de boucle sont respectés, et comment l'IK est pilotée. Elle est volontairement conservatrice — tout ce qui suit est visible dans le pipeline d'importation et d'exécution.
Pour les règles de nommage des os et le reste du contrat d'importation, voir les Notes de création de modèles.
Les cinq animations d'état
FreeMinecraftModels associe exactement cinq noms d'animation en minuscules à des états d'exécution automatiques. Tout le reste dans le modèle est une animation personnalisée.
| Nom de l'animation | Boucle | Quand elle se joue |
|---|---|---|
spawn | non | Une seule fois, à la création du modèle. Enchaîne sur idle quand elle se termine |
idle | oui | Tant que la vélocité de l'entité sous-jacente est inférieure ou égale à 0.08 |
walk | oui | Tant que la vélocité de l'entité sous-jacente est supérieure à 0.08 |
attack | non | Lorsqu'elle est déclenchée ; revient à idle quand elle se termine |
death | non | Lors de removeWithDeathAnimation() |
Règles qui découlent de la façon dont la machine à états est construite :
- L'état de départ est
spawnsi le modèle en possède un, sinonidle. Un modèle qui n'a ni l'un ni l'autre n'a aucun état courant : rien ne s'anime tant que quelque chose n'est pas joué explicitement. - Seules les animations qui existent dans le modèle obtiennent un état. Un modèle avec un
walkmais sansidlene sort jamais dewalkde lui-même. - La bascule idle/walk lit la vélocité de l'entité sous-jacente : c'est donc en réalité une fonctionnalité de
DynamicEntity. Les entités statiques et les déguisements de joueurs n'ont pas d'entité sous-jacente à cet effet et restent simplement enidle; l'armor stand qui sert de support à un prop ne bouge pas, donc les props restent eux aussi enidle. Ces trois cas pilotent leurs véritables animations via des scripts, l'API, ou (pour les déguisements) le contrôleur de déguisement de FMM.
jump n'existe qu'en tant qu'entrée d'énumération iciJUMP existe dans l'énumération AnimationStateType, et l'état walk demande bien une transition de saut lorsque l'entité quitte le sol — mais aucun état de saut n'est jamais enregistré, donc cette demande n'aboutit à rien. Une animation nommée jump n'est pas morte pour autant : elle se comporte comme n'importe quelle autre animation personnalisée et doit être déclenchée manuellement. Les déguisements de joueurs font exception — ils utilisent un contrôleur distinct où jump est bien câblé.
Les déguisements de joueurs utilisent un jeu différent
Un déguisement de joueur n'exécute pas la machine à états ci-dessus. Il possède son propre contrôleur exécuté à chaque tick avec cinq noms réservés — attack, jump, sneak, walk, idle — évalués dans cet ordre de priorité, et il avertit dans la console si le modèle n'a pas d'idle. Voir Déguisements des joueurs pour le tableau complet et la mise en garde sur le timing des animations à coup unique.
Animations personnalisées
Toute animation dont le nom n'est pas l'un des cinq ci-dessus peut quand même être jouée par son nom :
modeledEntity.playAnimation("open", /* blend */ true, /* loop */ false);
modeledEntity.stopCurrentAnimations();
boolean exists = modeledEntity.hasAnimation("open");
context.prop:play_animation("open", true, false)
context.prop:stop_animation()
blendn'effectue pas de fondu enchaîné.truemet l'animation en file d'attente pour qu'elle démarre après la fin du tick de l'état courant ;falseinterrompt et bascule immédiatement.loopne s'applique qu'aux animations personnalisées. Un état intégré utilise son propre réglage de boucle, quelle que soit la valeur passée.- Lorsqu'une animation personnalisée sans boucle se termine, l'entité revient au dernier état intégré validé (ce qu'elle faisait auparavant), ou à
idles'il n'y en avait aucun. playAnimationrenvoiefalselorsque le nom ne correspond ni à un état enregistré ni à une animation du modèle.stopCurrentAnimations()bascule versidlesi le modèle en possède un ; sinon il quitte l'état courant et laisse le modèle sans animation active.- Pendant qu'une animation personnalisée est en cours, une demande de
attack,attack_meleeouattack_rangedest ignorée afin qu'une séquence scriptée ne soit pas interrompue par un combat de routine.
Timing et durée
- Blockbench stocke la longueur d'animation en secondes. FMM la convertit avec
ceil(secondes x 20), donc la durée est toujours un nombre entier de ticks et les animations courtes sont arrondies vers le haut plutôt que vers le bas. - Chaque animation est précalculée à l'importation dans un tableau plat d'images par tick. La lecture est une simple consultation de tableau par tick, pas une interpolation en direct.
- Les animations en boucle s'indexent avec
counter % duration; celles sans boucle se bloquent sur la dernière image puis cessent d'appliquer tout changement. - Les temps des keyframes conservent leur position fractionnaire en ticks (
20 x time, non arrondi), donc une keyframe à 0,37 s tombe entre deux ticks et est interpolée correctement au lieu d'être calée ou perdue. La dernière keyframe d'une animation est préservée plutôt que tronquée par l'arrondi. - Si deux keyframes du même canal tombent exactement au même instant, c'est la dernière dans l'ordre du fichier qui l'emporte.
- Une keyframe dont le temps n'est pas un nombre fini interrompt cette piste et produit un unique avertissement
Malformed animation timeline for model ...par animation, tandis que les autres animations du modèle continuent d'être converties.
Les animations de longueur nulle sont valides
Une animation dont la longueur est 0 (ou négative) est traitée comme une pose statique intentionnelle — un choix de création courant pour le mobilier et les autres props qui ont besoin d'une entrée « aucune animation » nommée. Elle est ignorée silencieusement, sans avertissement, et ne produit aucune image.
Modes de boucle
Le réglage de boucle de Blockbench est lu directement depuis l'animation :
| Mode de boucle Blockbench | Exécution Java | Export Bedrock |
|---|---|---|
loop | se répète indéfiniment | "loop": true |
once | se joue jusqu'au bout puis s'arrête | "loop": false |
hold | se joue jusqu'au bout et maintient la dernière image | "loop": "hold_on_last_frame" |
Types d'interpolation
Chaque keyframe porte son propre type d'interpolation, et le segment qui mène à une keyframe utilise le type de cette keyframe. Quatre types sont pris en charge :
| Type Blockbench | Comportement dans FMM |
|---|---|
linear | Interpolation linéaire simple |
catmullrom | Interpolation lissée (accélération/décélération) |
bezier | Approximée avec des points de contrôle fixes 0.42 / 0.58 — FMM ne lit pas les poignées de Bézier par keyframe |
step | Reste sur la valeur précédente jusqu'à la keyframe suivante |
Tout ce qui sort de cet ensemble échoue à l'analyse et est signalé comme une timeline malformée.
Canaux animés
Trois canaux sont précalculés par os : rotation, position et échelle. Points importants pour la création :
- Les valeurs de position sont divisées par 16 (pixels Blockbench vers blocs).
- Les valeurs de rotation sont converties en radians.
- Les
format_version5 et ultérieures de Blockbench inversent le signe des rotations X et Y ainsi que de la position X. FMM compense automatiquement en fonction de la version de format déclarée, donc ne corrigez pas cela à la main — mais ne mélangez pas non plus une déclaration v5 avec des données au format v4. - Un os sans keyframe sur un canal conserve sa valeur de repos pour ce canal ; un os sans aucune image pour un tick donné est réinitialisé à rotation
0,0,0, translation0,0,0, échelle1,1,1. - Les points de données des keyframes peuvent être écrits sous forme de chaînes dans le
.bbmodel. FMM les analyse comme de simples nombres — une chaîne vide devient1pour l'échelle et0sinon, et tout ce qui est inanalysable journaliseFailed to parse supposed number value ...et devient0. Les expressions Molang ne sont pas évaluées. - Seul le premier point de données d'une keyframe est lu, donc les valeurs pre/post distinctes de Blockbench sur une keyframe
stepsont fusionnées en une seule.
Ce qui n'est pas animé
- L'os
hitbox. Les pistes d'animation qui le ciblent sont purement et simplement ignorées. - Les pistes d'effets de Blockbench (animateurs de son, de particules et d'instructions de timeline). Tout animateur dont le type n'est pas
boneounull_objectest ignoré, donc FMM ne déclenchera ni sons ni particules depuis une timeline d'animation. Pilotez-les plutôt depuis un script Lua ou depuis votre propre plugin. - Les os qui n'ont pas pu être résolus par leur nom. Une piste pointant vers un os manquant journalise
Failed to get bone <name> from model <model>!et est ignorée.
Cinématique inverse (IK)
Les null objects de Blockbench servent de contrôleurs d'IK. FMM résout les chaînes à l'exécution avec FABRIK (Forward And Backward Reaching Inverse Kinematics), plafonné à 10 itérations avec une tolérance de 0.001.
Comment tout cela s'articule :
- Un null object possédant à la fois
ik_source(os racine de la chaîne) etik_target(os terminal ou locator) définit une chaîne. La chaîne est découverte en remontant la hiérarchie depuis la cible jusqu'à la source. - Seules les keyframes de position du null object sont lues. Elles deviennent un décalage d'objectif par image, relatif à la position de repos du contrôleur ; les pistes de rotation et d'échelle d'un null object sont ignorées.
- À chaque tick, le décalage d'objectif de l'image courante est appliqué et la chaîne est résolue. Sur une image sans données d'IK, les rotations d'IK de la chaîne sont réinitialisées à la place.
lock_ik_target_rotationsur le null object est lu depuis le modèle.
Les chaînes qui ne peuvent pas être résolues sont ignorées avec un avertissement console nommé — voir les Notes de création de modèles pour les messages exacts et les contraintes de création.
Export Bedrock
Chaque modèle converti écrit également un fichier d'animation Bedrock dans animations/<model_id>.animation.json à l'intérieur du bundle généré :
- Les identifiants d'animation sont
animation.fmm.<model_id>.<animation_name>, avec des noms nettoyés pour Bedrock. animation_lengthest la durée en secondes, avec un plancher à0.05afin qu'une animation d'un seul tick reste valide.- Le mode de boucle est mappé comme indiqué dans le tableau Modes de boucle.
- Un modèle sans aucune animation reçoit tout de même une entrée
idleinerte afin que la définition d'entité Bedrock reste valide. - Seuls les os visuels sont exportés.
hitbox, les os de nametagfmm_nametag_bone_*générés automatiquement et les os de point de monturem_sont exclus de la géométrie et donc du bloc d'os d'animation. L'ostag_que vous créez n'est pas exclu — il est exporté comme n'importe quel autre os (généralement vide, sans cube) ; seul son équivalent nametag généré est filtré. - Un contrôleur d'animation est généré par animation, commuté par une propriété d'entité : c'est ainsi que FMM joue une animation précise sur un client Bedrock.
Voir Sortie du resource pack pour savoir où le bundle atterrit sur le disque.
Jouer des animations depuis d'autres systèmes
| Appelant | Point d'entrée |
|---|---|
| Plugin (Java) | ModeledEntity#playAnimation(String, boolean blend, boolean loop) / #stopCurrentAnimations() / #hasAnimation(String) |
| Script Lua de prop | context.prop:play_animation(name, blend, loop) / context.prop:stop_animation() |
| Toute table d'entité Lua | entity.model:play_animation(name, blend, loop) / entity.model:stop_animations() (disponible lorsque entity.is_modeled vaut true) |
Voir le Guide API et développeur et Lua : API Prop et Item pour les surfaces environnantes.
Dépannage
Mon animation ne se joue jamais automatiquement.
Seules spawn, idle, walk, attack et death se déclenchent d'elles-mêmes. Tout le reste nécessite un appel explicite à playAnimation / play_animation.
Mon modèle ne fait strictement rien.
Il n'a probablement ni animation spawn ni animation idle, donc aucun état n'est activé à la création. Ajoutez une animation idle.
Mon animation se joue mais rien ne bouge. Vérifiez la longueur de l'animation. Une animation de longueur nulle est traitée comme une pose statique et est ignorée silencieusement, par conception.
Les rotations sont en miroir.
Vérifiez meta.format_version dans le .bbmodel. FMM inverse le signe des rotations X/Y pour la version de format 5 et ultérieures ; un fichier qui déclare une version mais contient les données de l'autre ressortira en miroir.
La console affiche Malformed animation timeline for model ....
Une piste de cette animation n'a pas pu être lue ou interpolée. L'avertissement se déclenche une fois par animation et nomme l'os ou le contrôleur d'IK concerné ; les autres animations du modèle sont tout de même converties.
Les sons et particules de ma timeline Blockbench ne font rien. Les pistes d'effets ne sont pas importées. Déclenchez-les depuis un script Lua ou votre propre plugin.