FreeMinecraftModels Animationen
Diese Seite dokumentiert, was FreeMinecraftModels tatsächlich mit den Animationsdaten in einer .bbmodel- oder .fmmodel-Datei macht: welche Namen eine Sonderrolle haben, wie Keyframes gebacken werden, welche Interpolations- und Loop-Modi berücksichtigt werden und wie IK angesteuert wird. Sie ist bewusst konservativ gehalten — alles hier ist im Import- und Laufzeit-Pipeline sichtbar.
Für Bone-Namensregeln und den Rest des Import-Vertrags siehe Hinweise zur Modellerstellung.
Die fünf Zustandsanimationen
FreeMinecraftModels bindet genau fünf kleingeschriebene Animationsnamen an automatische Laufzeitzustände. Alles andere im Modell ist eine benutzerdefinierte Animation.
| Animationsname | Loopt | Wann sie abgespielt wird |
|---|---|---|
spawn | nein | Einmal, wenn das Modell erzeugt wird. Geht am Ende in idle über |
idle | ja | Solange die Geschwindigkeit der zugrundeliegenden Entität bei oder unter 0.08 liegt |
walk | ja | Solange die Geschwindigkeit der zugrundeliegenden Entität über 0.08 liegt |
attack | nein | Wenn ausgelöst; kehrt am Ende zu idle zurück |
death | nein | Bei removeWithDeathAnimation() |
Regeln, die sich aus dem Aufbau der Zustandsmaschine ergeben:
- Der Startzustand ist
spawn, sofern das Modell eine solche Animation besitzt, sonstidle. Ein Modell mit keiner von beiden hat keinen aktuellen Zustand, es animiert also nichts, bis etwas explizit abgespielt wird. - Nur Animationen, die im Modell vorhanden sind, erhalten einen Zustand. Ein Modell mit
walk, aber ohneidle, verlässtwalkvon selbst nie wieder. - Der Wechsel zwischen Idle und Walk liest die Geschwindigkeit der zugrundeliegenden Entität, ist also eigentlich ein
DynamicEntity-Feature. Statische Entitäten und Spieler-Verkleidungen haben dafür keine zugrundeliegende Entität und bleiben schlicht inidle; der Armor Stand hinter einem Prop bewegt sich nicht, also bleiben auch Props inidle. Alle drei steuern ihre echten Animationen über Skripte, die API oder (bei Verkleidungen) FMMs eigenen Verkleidungs-Controller an.
jump existiert hier nur als EnumJUMP existiert im Enum AnimationStateType, und der Walk-Zustand fordert tatsächlich einen Jump-Übergang an, wenn die Entität den Boden verlässt — aber es wird nie ein Jump-Zustand registriert, sodass diese Anforderung ins Leere läuft. Eine Animation namens jump ist nicht tot: Sie verhält sich einfach wie jede andere benutzerdefinierte Animation und muss manuell ausgelöst werden. Spieler-Verkleidungen sind die Ausnahme — sie verwenden einen separaten Controller, in dem jump sehr wohl angebunden ist.
Spieler-Verkleidungen verwenden einen anderen Satz
Eine Spieler-Verkleidung führt die obige Zustandsmaschine nicht aus. Sie hat ihren eigenen Controller pro Tick mit fünf reservierten Namen — attack, jump, sneak, walk, idle —, die in genau dieser Prioritätsreihenfolge ausgewertet werden, und sie warnt in der Konsole, wenn das Modell keine idle-Animation hat. Siehe Spieler-Verkleidungen für die vollständige Tabelle und den Timing-Vorbehalt bei Einmal-Animationen.
Benutzerdefinierte Animationen
Jede Animation, deren Name keiner der obigen fünf ist, kann trotzdem namentlich abgespielt werden:
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()
blendblendet nicht über.truereiht die Animation ein, damit sie startet, nachdem der Tick des aktuellen Zustands abgeschlossen ist;falseunterbricht und wechselt sofort.loopgilt nur für benutzerdefinierte Animationen. Ein eingebauter Zustand verwendet unabhängig vom übergebenen Wert seine eigene Loop-Einstellung.- Wenn eine nicht loopende benutzerdefinierte Animation endet, kehrt die Entität zum zuletzt bestätigten eingebauten Zustand zurück (was auch immer sie vorher getan hat), oder zu
idle, falls es keinen gab. playAnimationgibtfalsezurück, wenn der Name weder zu einem registrierten Zustand noch zu einer Animation im Modell passt.stopCurrentAnimations()wechselt zuidle, sofern das Modell eine solche Animation hat; andernfalls verlässt es den aktuellen Zustand und lässt das Modell ohne aktive Animation zurück.- Während eine benutzerdefinierte Animation läuft, wird eine Anfrage für
attack,attack_meleeoderattack_rangedverschluckt, damit eine geskriptete Sequenz nicht durch normalen Kampf unterbrochen wird.
Timing und Dauer
- Blockbench speichert die Animationslänge in Sekunden. FMM rechnet sie mit
ceil(seconds x 20)um, die Dauer ist also immer eine ganze Anzahl Ticks und kurze Animationen werden auf- statt abgerundet. - Jede Animation wird beim Import in ein flaches Frame-Array pro Tick gebacken. Die Wiedergabe ist ein Array-Zugriff pro Tick, keine Live-Interpolation.
- Loopende Animationen indexieren mit
counter % duration; nicht loopende werden auf den letzten Frame begrenzt und stellen danach keine weiteren Änderungen mehr dar. - Keyframe-Zeiten behalten ihre gebrochene Tick-Position (
20 x time, nicht gerundet), sodass ein Keyframe bei 0,37 s zwischen Ticks landet und korrekt interpoliert wird, statt eingerastet oder verworfen zu werden. Der letzte Keyframe einer Animation bleibt erhalten und wird nicht durch Rundung abgeschnitten. - Wenn zwei Keyframes desselben Kanals auf exakt derselben Zeit landen, gewinnt der in der Dateireihenfolge spätere.
- Ein Keyframe mit einer nicht endlichen Zeit bricht diesen Track ab und erzeugt eine einzelne Warnung
Malformed animation timeline for model ...pro Animation, während die übrigen Animationen des Modells weiter konvertiert werden.
Animationen der Länge null sind gültig
Eine Animation mit der Länge 0 (oder negativ) wird als absichtliche statische Pose behandelt — eine gängige Wahl bei Möbeln und anderen Props, die einen benannten Eintrag „keine Animation“ brauchen. Sie wird stillschweigend und ohne Warnung übersprungen und trägt keine Frames bei.
Loop-Modi
Blockbenchs Loop-Einstellung wird direkt aus der Animation gelesen:
| Blockbench-Loop-Modus | Java-Laufzeit | Bedrock-Export |
|---|---|---|
loop | wiederholt sich unbegrenzt | "loop": true |
once | läuft durch und stoppt | "loop": false |
hold | läuft durch und hält den letzten Frame | "loop": "hold_on_last_frame" |
Interpolationstypen
Jeder Keyframe trägt seinen eigenen Interpolationstyp, und das Segment, das in einen Keyframe hineinführt, verwendet den Typ dieses Keyframes. Vier werden unterstützt:
| Blockbench-Typ | Verhalten in FMM |
|---|---|
linear | Geradlinige lineare Interpolation |
catmullrom | Geglättete Interpolation (Ease-in/Ease-out) |
bezier | Angenähert mit festen Kontrollpunkten 0.42 / 0.58 — FMM liest keine Bezier-Anfasser pro Keyframe |
step | Rastet auf den vorherigen Wert ein, bis der nächste Keyframe kommt |
Alles außerhalb dieses Satzes kann nicht geparst werden und wird als fehlerhafte Timeline gemeldet.
Animierte Kanäle
Pro Bone werden drei Kanäle gebacken: Rotation, Position und Skalierung. Wichtige Hinweise für die Erstellung:
- Positionswerte werden durch 16 geteilt (Blockbench-Pixel zu Blöcken).
- Rotationswerte werden in Radiant umgerechnet.
- Blockbench
format_version5 und neuer dreht das Vorzeichen der X- und Y-Rotation sowie der X-Position um. FMM gleicht das anhand der deklarierten Formatversion automatisch aus, korrigiere also nicht von Hand — mische aber auch keine v5-Deklaration mit v4-förmigen Daten. - Ein Bone ohne Keyframes auf einem Kanal behält für diesen Kanal seinen Ruhewert; ein Bone ganz ohne Frames für einen bestimmten Tick wird auf Rotation
0,0,0, Translation0,0,0und Skalierung1,1,1zurückgesetzt. - Keyframe-Datenpunkte dürfen in der
.bbmodelals Zeichenketten geschrieben sein. FMM parst sie als einfache Zahlen — eine leere Zeichenkette wird zu1bei der Skalierung und sonst zu0, und alles Nicht-Parsebare protokolliertFailed to parse supposed number value ...und wird zu0. Molang-Ausdrücke werden nicht ausgewertet. - Es wird nur der erste Datenpunkt eines Keyframes gelesen, Blockbenchs getrennte Vorher-/Nachher-Werte eines Step-Keyframes fallen also zu einem zusammen.
Was nicht animiert wird
- Der
hitbox-Bone. Animationsspuren, die auf ihn zielen, werden vollständig übersprungen. - Blockbench-Effektspuren (Sound-, Partikel- und Timeline-Instruction-Animatoren). Jeder Animator, dessen Typ nicht
boneodernull_objectist, wird ignoriert, FMM löst also keine Sounds oder Partikel aus einer Animations-Timeline aus. Steuere diese stattdessen über ein Lua-Skript oder dein eigenes Plugin an. - Bones, die nicht per Name aufgelöst werden konnten. Eine Spur, die auf einen fehlenden Bone zeigt, protokolliert
Failed to get bone <name> from model <model>!und wird übersprungen.
Inverse Kinematik (IK)
Blockbench-Null-Objekte fungieren als IK-Controller. FMM löst Ketten zur Laufzeit mit FABRIK (Forward And Backward Reaching Inverse Kinematics) auf, begrenzt auf 10 Iterationen mit einer Toleranz von 0.001.
Wie das zusammenspielt:
- Ein Null-Objekt mit sowohl
ik_source(Wurzel-Bone der Kette) als auchik_target(End-Bone oder Locator) definiert eine Kette. Die Kette wird ermittelt, indem die Hierarchie vom Target zur Source hinaufgelaufen wird. - Es werden nur die Positions-Keyframes des Null-Objekts gelesen. Sie werden zu einem Ziel-Offset pro Frame relativ zur Ruheposition des Controllers; Rotations- und Skalierungsspuren auf einem Null-Objekt werden ignoriert.
- In jedem Tick wird der Ziel-Offset für den aktuellen Frame angewendet und die Kette gelöst. In einem Frame ohne IK-Daten werden die IK-Rotationen der Kette stattdessen zurückgesetzt.
lock_ik_target_rotationam Null-Objekt wird aus dem Modell gelesen.
Ketten, die nicht aufgelöst werden können, werden mit einer benannten Konsolenwarnung übersprungen — siehe Hinweise zur Modellerstellung für die genauen Meldungen und die Erstellungsbeschränkungen.
Bedrock-Export
Jedes konvertierte Modell schreibt zusätzlich eine Bedrock-Animationsdatei unter animations/<model_id>.animation.json im erzeugten Bundle:
- Animationsbezeichner lauten
animation.fmm.<model_id>.<animation_name>, wobei die Namen für Bedrock bereinigt werden. animation_lengthist die Dauer in Sekunden, nach unten auf0.05begrenzt, damit eine Ein-Tick-Animation weiterhin gültig ist.- Der Loop-Modus wird wie in der Tabelle Loop-Modi gezeigt abgebildet.
- Ein Modell ohne Animationen erhält trotzdem einen einzelnen No-Op-
idle-Eintrag, damit die Bedrock-Entitätsdefinition gültig bleibt. - Es werden nur sichtbare Bones exportiert.
hitbox, die automatisch erzeugten Namensschild-Bonesfmm_nametag_bone_*undm_-Mountpoint-Bones werden aus der Geometrie und damit aus dem Animations-Bone-Block ausgeschlossen. Der von dir erstelltetag_-Bone wird nicht ausgeschlossen — er wird wie jeder andere Bone exportiert (meist als leerer, würfelloser Bone); nur sein generiertes Namensschild-Gegenstück wird herausgefiltert. - Pro Animation wird ein Animations-Controller erzeugt, umgeschaltet über eine Entitätseigenschaft — so spielt FMM eine bestimmte Animation auf einem Bedrock-Client ab.
Siehe Ressourcenpaket-Ausgabe dafür, wo das Bundle auf der Festplatte landet.
Animationen aus anderen Systemen abspielen
| Aufrufer | Einstiegspunkt |
|---|---|
| Plugin (Java) | ModeledEntity#playAnimation(String, boolean blend, boolean loop) / #stopCurrentAnimations() / #hasAnimation(String) |
| Prop-Lua-Skript | context.prop:play_animation(name, blend, loop) / context.prop:stop_animation() |
| Beliebige Lua-Entitätstabelle | entity.model:play_animation(name, blend, loop) / entity.model:stop_animations() (verfügbar, wenn entity.is_modeled true ist) |
Siehe den API- und Entwicklerleitfaden und Lua: Prop- und Item-API für die umgebenden Schnittstellen.
Fehlerbehebung
Meine Animation läuft nie automatisch.
Nur spawn, idle, walk, attack und death starten von selbst. Alles andere braucht einen expliziten Aufruf von playAnimation / play_animation.
Mein Modell tut überhaupt nichts.
Wahrscheinlich hat es weder eine spawn- noch eine idle-Animation, sodass bei der Erzeugung kein Zustand betreten wird. Füge eine idle hinzu.
Meine Animation läuft, aber nichts bewegt sich. Prüfe die Animationslänge. Eine Animation der Länge null wird als statische Pose behandelt und absichtlich stillschweigend übersprungen.
Rotationen sind gespiegelt.
Prüfe meta.format_version in der .bbmodel. FMM dreht das Vorzeichen der X-/Y-Rotation ab Formatversion 5 um; eine Datei, die die eine Version deklariert, aber die Daten der anderen enthält, kommt gespiegelt heraus.
Die Konsole meldet Malformed animation timeline for model ....
Eine Spur in dieser Animation konnte nicht gelesen oder interpoliert werden. Die Warnung erscheint einmal pro Animation und benennt den beteiligten Bone bzw. IK-Controller; die übrigen Animationen des Modells werden weiterhin konvertiert.
Sounds und Partikel in meiner Blockbench-Timeline tun nichts. Effektspuren werden nicht importiert. Löse sie über ein Lua-Skript oder dein eigenes Plugin aus.