FreeMinecraftModels Animationen
FreeMinecraftModels importiert Animationsdaten aus .bbmodel- und .fmmodel-Dateien. Diese Seite beschreibt reservierte Namen, Frame-Zeiten, Interpolation, Loop-Modi und inverse Kinematik (IK).
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 | Bei horizontalem Stillstand; wechselt zu walk, wenn die X- oder Z-Geschwindigkeit ungleich null ist |
walk | ja | Bei horizontaler Bewegung; wechselt am Boden mit X- und Z-Geschwindigkeit null zu idle |
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 horizontale Geschwindigkeit der zugrunde liegenden Entity; reine Vertikalbewegung startet keine Laufanimation. Statische Entities und Spieler-Verkleidungen haben für diesen Zweck keine zugrunde liegende Entity; stationäre Props bewegen sich nicht horizontal. Ihre zusätzlichen Animationen werden durch Skripte, die API oder FMMs Verkleidungs-Controller gesteuert.
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 ergänzt einen Controller pro Tick, der Animationen über dieselbe Wiedergabe-Engine anfordert. Seine fünf reservierten Namen sind attack, jump, sneak, walk und idle. Er prüft sie in dieser Reihenfolge, solange der Countdown einer einmaligen Animation nicht aktiv ist. Fehlt idle, warnt er in der Konsole. Die vollständige Tabelle und die zeitliche Einschränkung dieser Animationen stehen unter Spieler-Verkleidungen.
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.- Es gibt nur einen Warteplatz; eine spätere eingereihte Anfrage ersetzt die vorherige. Eine benutzerdefinierte Animation startet ohne aktuellen Zustand sofort. Ein eingereihter eingebauter Zustand kann bei einem aktuellen Zustand von null nicht fortschreiten; verwende dann
blend=false. loopgilt nur für benutzerdefinierte Animationen. Ein eingebauter Zustand verwendet unabhängig vom übergebenen Wert seine eigene Loop-Einstellung.- Verwende für benutzerdefinierte Animationen und
hasAnimationdie exakte Schreibweise: Beide Suchvorgänge unterscheiden Groß- und Kleinschreibung. Wiedergabeanfragen für eingebaute Zustände akzeptieren andere Schreibweisen, ihre Registrierung verlangt aber weiterhin den kleingeschriebenen Namen im Modell. - Wenn eine nicht wiederholte benutzerdefinierte Animation endet, fordert sie den gespeicherten zuletzt bestätigten eingebauten Zustand an, oder
idle, wenn keiner erfasst wurde. Gemeint ist der letzte eingebaute Zustand, den der Manager zuvor verlassen hat. Dieser kann vom unmittelbar vor der benutzerdefinierten Animation aktiven Zustand abweichen. Existiert der angeforderte Rückkehrzustand nicht, bleibt der benutzerdefinierte Zustand ohne weitere Frame-Aktualisierungen ausgewählt. playAnimationgibt bei unbekannten Namenfalsezurück, außer bei den unten beschriebenen unterdrückten Angriffsanfragen. Ein erfolgreicher Rückgabewert bedeutet, dass die Anfrage angenommen wurde, nicht dass bereits ein sichtbarer Frame abgespielt wurde.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. - Der Todeszustand ist in der gemeinsamen Zustandsmaschine endgültig: Neue Anfragen geben
falsezurück, eingereihte Übergänge werden verworfen und das Stoppen von Animationen ändert diesen Zustand nicht. Die öffentliche Stoppmethode sendet zusätzlich eine separate Stoppanfrage an Bedrock; verwende sie daher nicht zur Steuerung einer Todessequenz auf beiden Clients.
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). Ein Keyframe bei 0,37 s trägt damit zur Interpolation zwischen Ticks bei. Frames werden bei ganzen Ticks von0bisduration - 1abgetastet. Ein Keyframe genau am deklarierten Ende beeinflusst die Interpolation, wird aber nicht selbst abgetastet. Platziere eine Endpose vor dieser Grenze, wenn ein dargestellter Frame sie erreichen muss. - 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 steuert die exportierte Bedrock-Animation:
| Blockbench-Loop-Modus | Bedrock-Export |
|---|---|
loop | "loop": true |
once | "loop": false |
hold | "loop": "hold_on_last_frame" |
Die Java-Wiedergabe verwendet die Wiederholungsregel des eingebauten Zustands beziehungsweise das loop-Argument einer benutzerdefinierten Animation. Sie übernimmt die Wiederholungsregel nicht aus diesem Blockbench-Feld. Daher können sich Java- und Bedrock-Wiedergabe unterscheiden, wenn diese Einstellungen voneinander abweichen.
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. - Sound- und Timeline-Instruction-Keyframes in Blockbench-Effektspuren. FMM importiert aus einer Effektspur nur die Partikel-Keyframes; siehe Partikel. Spiele Sounds stattdessen über ein Lua-Skript oder dein eigenes Plugin ab.
- 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
ik_source(Wurzel-Bone) undik_target(End-Bone oder Locator) definiert eine Kette. Die Erkennung prüft die Hierarchie und unterstützt auch Suchen unter Geschwistern und nach unten; Geschwisterziele auf der Wurzelebene ergeben eine Kette nur mit dem Quell-Bone. - Nur die Positions-Keyframes des Null-Objekts steuern IK. Sie ergeben pro Frame einen Versatz, der zur Ruheposition des Ziel-Bones oder Locators addiert wird. Der Solver verwendet die gespeicherte Ruheposition des Controllers nicht als Zielbasis. Rotation und Skalierung steuern IK nicht.
- In jedem Tick erhalten die zugeordneten IK-Ketten der aktuellen Animation ihre Zielversätze und werden gelöst. Eine zugeordnete Kette ohne Frame-Daten wird zurückgesetzt. Jeder Animationswechsel sowie
stopCurrentAnimations()setzt die IK-Rotationen aller Ketten zurück, sodass eine IK-Pose nicht in die nächste Animation übernommen wird. lock_ik_target_rotationwird gelesen und gespeichert, vom aktuellen Solver aber nicht angewendet.
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>.a_<hex>, wobei<hex>die UTF-8-Bytes des Animationsnamens in hexadezimaler Schreibweise sind. Zwei Namen, die sich nur in Zeichen unterscheiden, die Bedrock nicht erlaubt, erhalten dadurch getrennte Bezeichner. 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. - Die Geometrie schließt
hitbox, generierte Namensschild-Bonesfmm_nametag_bone_*und Mountpointsm_aus; selbst erstelltetag_-Anker bleiben enthalten. Der Animationsexport schreibt vorberechnete Bone-Spuren ohne denselben Filter für sichtbare Bones. Animiere daher keine ausgeschlossenen Mount-Bones in der Erwartung sichtbarer Geometrie. - Der Bedrock-Animationsexport verwendet vorberechnete Frames für Rotation, Position und Skalierung. Er übernimmt nicht die zur Laufzeit berechneten IK-Rotationen in diese Spuren; prüfe IK-abhängige Modelle gesondert auf Bedrock.
- Pro Animation wird ein Animations-Controller erzeugt, umgeschaltet über eine Entitätseigenschaft — so spielt FMM eine bestimmte Animation auf einem Bedrock-Client ab.
- Partikel-Keyframes werden zur
particle_effects-Timeline der Animation, sodass Bedrock-Clients sie nativ abspielen. Siehe Partikel.
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) |
Die zugehörigen Schnittstellen beschreiben der API- und Entwicklerleitfaden und Lua: Prop-API.
Die Lua-Standardwerte unterscheiden sich: context.prop:play_animation(name) verwendet blend=true, loop=true, während entity.model:play_animation(name) die Werte false, false verwendet. Übergib beide booleschen Werte ausdrücklich, wenn der Unterschied wichtig ist.
Fehlerbehebung
Meine Animation läuft nie automatisch.
Die gemeinsame Zustandsmaschine erkennt die kleingeschriebenen Namen spawn, idle, walk, attack und death. Bewegung steuert die Übergänge zwischen idle und walk; Angriff und Tod benötigen weiterhin ihren Laufzeitauslöser. Andere Namen brauchen einen expliziten Aufruf von playAnimation / play_animation, außer den zusätzlichen Namen, die der Verkleidungs-Controller auswählt.
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 in meiner Blockbench-Timeline tun nichts. Sound-Keyframes werden nicht importiert. Löse Sounds über ein Lua-Skript oder dein eigenes Plugin aus. Partikel-Keyframes werden importiert; falls sie nicht erscheinen, siehe Partikel.