Animations de FreeMinecraftModels
FreeMinecraftModels importe les animations des fichiers .bbmodel et .fmmodel. Cette page présente les noms réservés, le minutage des images, l'interpolation, les modes de boucle et la cinématique inverse (IK).
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 | En l'absence de mouvement horizontal ; passe à walk si la vitesse sur X ou Z devient non nulle |
walk | oui | Pendant un mouvement horizontal ; passe à idle lorsque l'entité est au sol et que les vitesses sur X et Z sont toutes deux nulles |
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 transition idle/walk lit la vitesse horizontale de l'entité sous-jacente : un mouvement uniquement vertical ne déclenche pas la marche. Les entités statiques et les déguisements n'ont pas d'entité sous-jacente utilisable à cette fin ; les props immobiles n'ont aucun mouvement horizontal. Leurs autres animations sont pilotées par les scripts, l'API ou 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 utilisent un autre ensemble d'animations
Un déguisement ajoute un contrôleur par tick qui demande les animations au même moteur de lecture. Ses cinq noms réservés sont attack, jump, sneak, walk, idle, évalués dans cet ordre de priorité lorsque le compte à rebours d'une animation à lecture unique est inactif. Il avertit la console si le modèle n'a pas d'idle. Consultez les déguisements des joueurs pour le tableau complet et la limite de durée de ces animations.
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.- Il n'existe qu'un emplacement en attente : une nouvelle demande différée remplace la précédente. Une animation personnalisée démarre immédiatement sans état courant. Un état intégré mis en attente ne peut pas avancer depuis un état courant nul ; utilisez
blend=falsedans ce cas. 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.- Utilisez les noms exacts pour les animations personnalisées et
hasAnimation: ces deux recherches distinguent les majuscules des minuscules. Les demandes de lecture d'états intégrés acceptent une casse différente, mais leur enregistrement exige toujours le nom en minuscules dans le modèle. - Lorsqu'une animation personnalisée sans boucle se termine, elle demande le dernier état intégré validé enregistré, ou
idlesi aucun n'a été enregistré. Il s'agit du dernier état intégré que le gestionnaire a quitté, qui peut différer de celui actif juste avant l'animation personnalisée. Si l'état de retour demandé n'existe pas, l'état personnalisé reste sélectionné sans nouvelle mise à jour des images. playAnimationrenvoiefalsepour un nom inconnu, sauf pour les demandes d'attaque ignorées décrites ci-dessous. Un retour positif signifie que la demande a été acceptée, pas qu'une image visible a été affichée.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. - La mort est terminale dans la machine à états partagée : les nouvelles demandes renvoient
false, les transitions en attente sont supprimées et arrêter les animations ne change pas cet état. La méthode publique d'arrêt envoie aussi une demande d'arrêt distincte à Bedrock ; ne l'utilisez pas pour gérer une séquence de mort sur les deux clients.
Cadence et durée
- Blockbench stocke la durée d'animation en secondes. FMM la convertit avec
ceil(seconds x 20): la durée est toujours un nombre entier de ticks, et les animations courtes sont arrondies vers le haut. - 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 images clés conservent leur position fractionnaire en ticks (
20 x time, sans arrondi) : une image clé à 0,37 s contribue à l'interpolation entre ticks. Les images sont échantillonnées aux ticks entiers de0àduration - 1; une image clé placée exactement à la fin déclarée influence l'interpolation, mais n'est pas elle-même échantillonnée. Placez la pose finale avant cette limite si une image affichée doit l'atteindre. - 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 détermine l'animation exportée pour Bedrock :
| Mode de boucle Blockbench | Export Bedrock |
|---|---|
loop | "loop": true |
once | "loop": false |
hold | "loop": "hold_on_last_frame" |
La lecture Java utilise la règle de boucle de l'état intégré ou l'argument loop passé à une animation personnalisée. Elle ne détermine pas sa règle à partir de ce champ Blockbench : la lecture peut donc différer entre Java et Bedrock si ces réglages ne concordent pas.
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 images clés de son et d'instructions de timeline des pistes d'effets de Blockbench. FMM n'importe que les images clés de particules d'une piste d'effets ; voir Particules. Jouez plutôt les sons 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 avec
ik_source(os racine) etik_target(os terminal ou locator) définit une chaîne. La détection examine la hiérarchie et prend aussi en charge les recherches entre frères et vers les descendants ; des cibles sœurs au niveau racine produisent une chaîne contenant seulement l'os source. - Seules les images clés de position du null object pilotent l'IK. Elles deviennent un décalage par image ajouté à la position de repos de l'os ou du locator cible. Le solveur n'utilise pas la position de repos stockée du contrôleur comme origine de la cible. La rotation et l'échelle ne pilotent pas l'IK.
- À chaque tick, les chaînes IK associées à l'animation courante reçoivent leurs décalages et sont résolues. Une chaîne associée sans données pour cette image est réinitialisée. Chaque changement d'animation, ainsi que
stopCurrentAnimations(), efface les rotations IK de toutes les chaînes : une pose IK n'est donc pas reportée sur l'animation suivante. lock_ik_target_rotationest lu et stocké, mais le solveur actuel ne l'applique pas.
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>.a_<hex>, où<hex>correspond aux octets UTF-8 du nom de l'animation écrits en hexadécimal. Deux noms qui ne diffèrent que par des caractères interdits par Bedrock reçoivent donc des identifiants distincts. 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. - La géométrie exclut
hitbox, les os de nom générésfmm_nametag_bone_*et les points de monturem_; les ancragestag_créés par l'auteur restent présents. L'exporteur d'animations écrit les pistes précalculées sans appliquer le même filtre d'os visuels : n'animez donc pas un os de monture exclu en espérant voir sa géométrie. - L'export Bedrock utilise les images précalculées de rotation, position et échelle des os. Il n'y incorpore pas les rotations produites à l'exécution par le solveur IK ; vérifiez séparément sur Bedrock les modèles qui dépendent de l'IK.
- 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.
- Les images clés de particules deviennent la timeline
particle_effectsde l'animation, que les clients Bedrock jouent donc nativement. Voir Particules.
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) |
Consultez le guide de l'API pour les développeurs et Lua : API des props pour les interfaces associées.
Les valeurs Lua par défaut diffèrent : context.prop:play_animation(name) utilise blend=true, loop=true, tandis que entity.model:play_animation(name) utilise false, false. Passez explicitement les deux booléens lorsque cette distinction compte.
Dépannage
Mon animation ne se joue jamais automatiquement.
La machine à états partagée reconnaît les noms minuscules spawn, idle, walk, attack et death. Le mouvement pilote les transitions idle/walk ; les attaques et la mort nécessitent toujours leur déclencheur à l'exécution. Les autres noms exigent un appel explicite à playAnimation / play_animation, sauf les noms supplémentaires sélectionnés par le contrôleur de déguisement.
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 de ma timeline Blockbench ne font rien. Les images clés de son ne sont pas importées. Déclenchez les sons depuis un script Lua ou votre propre plugin. Les images clés de particules sont importées ; si elles ne s'affichent pas, voir Particules.