Export in Engines
Das Export-Fenster
Exportieren (Ctrl+E) sitzt im Fensterkopf direkt nach Importieren und öffnet ein Fenster, das wie das von Importieren gestaltet ist (D51):
- Asset-Pipeline – zu Beginn die, die die Asset-Auswahl im Kopf zeigt. Was sie schreibt, wird im Asset-Graphen entworfen.
- Exportordner – tippe einen Pfad ein oder Wählen… einen. Das Projekt behält ihn.
- Jetzt exportieren – das Projekt so, wie es offen ist, gespeichert oder nicht: Exportieren speichert es nie, und ein unbenanntes Projekt wird so exportiert, wie es ist.
Bevor du auf Exportieren drückst, listet das Fenster jede Datei auf, die der Export schreiben wird, so wie pxr names sie benennt: jede mit ihrem Pfad im Ordner und ihrer Art (Sprite-Sheet, JSON, GIF…), und wird ersetzt bei einer Datei, die der Ordner schon hat. Die Liste wird neu ermittelt – mit einer kleinen Ladeanzeige, ohne das Fenster aufzuhalten –, wenn du die Asset-Pipeline, den Ordner oder das Projekt änderst. Eine Pipeline, die so nicht exportiert werden kann (etwa zwei Ausgaben, die eine Datei schreiben), sagt dort, warum, und Exportieren wartet, bis es behoben ist.
Nach dem Drücken sind genau diese Zeilen, an ihren Plätzen, der Export: jede mit einem Ladesymbol, bis sie geschrieben ist, dann ein Häkchen, ihre Größe, Öffnen (in dem Programm, mit dem dein System sie öffnet) und Ordner zeigen. Was schiefgeht, steht bei der Datei, an der es anhielt. Stopp beendet einen Export auf halbem Weg: Was geschrieben wurde, bleibt, die gerade geschriebene Datei wird entfernt. Das Fenster lässt sich schließen, während er läuft; „Exportieren“ öffnet es wieder.
Es führt genau das aus, was die Kommandozeile ausführt: pxr render PROJECT --pipeline NAME -o FOLDER, in einem eigenen Prozess, sodass Pixor reaktionsfähig bleibt – auf einem Schnappschuss des Projekts, so wie es offen ist, in den Ordner der erzeugten Dateien geschrieben (mit absolut gemachten Dateipfaden) und entfernt, wenn der Export endet. Die Dateien werden so benannt, wie pxr render die dieses Projekts benennt: nach dem Projekt oder, bei einem unbenannten, nach seinem Modell. Jede Datei wird frisch aus der Pipeline geschrieben: Was die Nodes des Asset-Graphen erzeugen, wird nie kopiert.
Jede Datei kommt in den Ordner. Das Sheet nimmt seinen Dateinamen von der PNG-Node des Projekts (out/hero.png schreibt FOLDER/hero.png); eine Datei, deren Pfad unter dem Ordner des Sheets liegt, behält ihren Platz unter FOLDER, und jeder andere Pfad (ein Archiv, eine Animation, anderswo benannte Icons) behält nur seinen letzten Teil.
Was ein Export schreibt
Jeder Export schreibt ein Sheet: eine Reihe pro Action und Seite, eine Spalte pro Frame, alle Zellen gleich groß, mit dem Pivot auf demselben Pixel in jeder. Füge dem Sheet im Asset-Graphen Datei-Nodes hinzu (oder nutze --export auf der Kommandozeile), um daneben Dateien mit demselben Namen zu bekommen. Jede ist eine Node, mit dem Sheet verbunden, mit eigenen Einstellungen. --export all schreibt jedes Format unten außer p8 und video, die nur geschrieben werden, wenn man sie nennt: Eine Cartridge passt nur zu einem Sheet, das dafür gemacht ist, und ein unkomprimiertes Video jedes Clips und jeder Seite kann Gigabytes groß sein. Keine zwei davon schreiben dieselbe Datei: pxr names lehnt ein Projekt ab, in dem zwei es täten.
| Format | Datei | Für |
|---|---|---|
| PNG | name.png |
das Sheet, ein indiziertes PNG (Index 0 transparent) |
| JSON | name.json |
Zellenrechtecke, Frame-Dauern, ein Tag pro Action und Seite, der Pivot. Aseprites „array“-Layout, sodass für Aseprite geschriebene Importer es lesen |
| Aseprite | name.aseprite |
eine indizierte Aseprite-Datei: Ebenen final, lines, flat und eine pro zusätzlichem Ausgang des Style-Graphen; ein Tag pro Action und Seite; Dauer pro Frame; ein pivot-Slice |
| Normal | name_normal.png |
eine Normal Map mit demselben Layout, für 2D-Beleuchtung |
| Tiefe | name_depth.png |
Tiefe mit demselben Layout: Weiß das Nächste, Dunkel das Fernste, ein Maßstab für das ganze Sheet (meta.pixor.depth gibt beides in Metern); transparent, wo nichts ist. Für Sortierung, Nebel und 2.5D-Beleuchtung |
| Emission | name_emission.png |
jedes leuchtende Pixel in seiner eigenen Farbe, so hell, wie es leuchtet (ein leuchtendes Material oder die Emissive Map des Modells); sonst transparent. Für Leuchten und Bloom |
| Ebenen | name_lines.png, name_flat.png und name_LAYER.png für jeden zusätzlichen Ausgang des Style-Graphen |
die Linien- und Flachfarben-Ebenen als Sheets und das Bild einer Node, wo der Style-Graph eines benennt |
| Palette | name.hex, name.gpl |
die Palette (Lospec- und GIMP-Formate) |
| Godot | name.tres |
eine Godot-4-Ressource SpriteFrames |
| gif | name_walk_Southeast.gif, … |
ein animiertes GIF pro Action und Seite, Haltezeiten als Frame-Verzögerungen, zum Teilen und für Vorschauen |
| APNG | name_walk_Southeast.apng, … |
dasselbe als animierte PNGs, mit exakten Millisekunden-Verzögerungen |
| Video | name_walk_Southeast.avi, … |
ein Video pro Action und Seite: ein unkomprimiertes AVI, jedes Pixel, wie es ist, für einen Trailer oder eine Shop-Seite |
| light-kit | name_ramps.png, name_normal.png, name_light.png, Shader |
palettentreue Beleuchtung in Engines (siehe unten) |
| Bericht | name_report.png |
das Sheet mit den markierten Befunden jeder Prüfung (siehe unten) |
| p8 | name.p8 |
eine PICO-8-Cartridge (siehe Konsolenmodi) |
| ZIP | der Pfad an seiner Node | eine Node ZIP-Archiv im Asset-Graphen: die damit verbundenen Dateien oder alles, was der Export geschrieben hat |
Eine Zeile ist nach ihrer Action und Seite benannt: walk_Southeast.
Welche Frames ein Sheet nimmt, wie sie angeordnet sind und wie viele Dateien ein Render schreibt, ist Sache des Asset-Graphen: eine Sheet-Node und ihre Datei-Nodes, bis du ihn neu verbindest.
Wie die Frames heißen und was sie sind
Jeder Frame in einem Sheet hat einen Namen und eine ID, und sie beantworten zwei verschiedene Fragen.
Der Name ist eine Vorlage, ein Muster aus den eigenen Wörtern deines Projekts; so ist der schlichte Standard genau das, was Einsteiger wollen, und ein Studio kann einer Konvention folgen, die es nicht selbst gewählt hat:
{project}_{action}_{side}_{index:2}.{ext} hero_walk_East_00.png
Die Wörter sind {project}, {object}, {action}, {side}, {layer}, {set} (das Teile-Set, mit dem eine Sprites-Node den Frame gezeichnet hat), {size}, {index} und {ext}. {index:3} füllt eine Zahl mit Nullen auf drei Stellen auf. {{ und }} schreiben eine geschweifte Klammer. Ein Wort, das Pixor nicht kennt, ist ein Fehler, wenn du die Vorlage eingibst, keine Datei namens hero_{genre}_00.png, und ein Wort ohne Inhalt nimmt das Trennzeichen davor mit, sodass ein Sprite ohne Seite hero_Static_00.png heißt.
Ein Wert, der nicht Teil eines Dateinamens sein kann (/ \ : * ? " < > |), wird abgelehnt statt stillschweigend ersetzt; ein Leerzeichen wird zu _. Die einzige Ausnahme ist Pixors eigenes Wort: Ein Bibliotheksclip namens lib:walk heißt in einem Namen lib-walk, denn dieser Doppelpunkt gehört Pixor und nicht dir.
Zwei Frames, die auf denselben Namen fallen würden, werden abgelehnt, bevor irgendetwas gerendert wird. Setze es mit --names auf der Kommandozeile oder speichere es im Projekt:
pxr project set hero.pixor --names '{object}/{action}-{side}-{index:3}.{ext}'
pxr names hero.pixor # what it will write, without rendering
pxr names hero.pixor --json # the same, for a build script
Die ID sagt, was ein Frame ist, nie, wo er gelandet ist. Sie ist ein Hash aus dem Objekt, der Action, der Seite, der Zeit in der Action und der Ebene, und sie steht neben jedem Frame im JSON und in den .aseprite-Benutzerdaten. Ein Sheet neu zu packen, einen Clip hinzuzufügen oder das Padding zu ändern, verschiebt Rechtecke und lässt IDs in Ruhe; ein Build, der Frames per ID anspricht, bricht also nicht jedes Mal, wenn der Packer läuft. Einen Clip mit einer anderen Framerate neu abzutasten, ändert seine IDs, denn das sind andere Frames.
Kleinere Sheets
An der Node Anordnen des Asset-Graphen (oder auf der Kommandozeile):
- Leeren Raum beschneiden (
--trim) schneidet jeden Frame auf seine Pixel zu. Das JSON gibt den Platz jedes Frames in der vollen Zelle an (spriteSourceSize,trimmed: true), und die Godot-Datei setzt diemarginjedes Frames, sodass Engines trotzdem jeden Frame auf den Pivot setzen. - Wiederholte Frames einmal speichern (
--dedupe): Frames, die exakt gleich sind (gehaltene Posen, Seiten eines ruhenden Objekts), teilen sich einen Platz. - Max. Sheet-Breite (
--max-width 4096) beginnt eine neue Zeile, bevor das Sheet breiter wird, für Engines und GPUs mit einer Texturgrößengrenze. - Max. Sheet-Höhe (
--max-height 2048) teilt ein höheres Sheet in Seiten auf, ganze Clips pro Seite:hero_1.png,hero_2.png, jede mit eigener JSON und den anderen Dateien daneben. - Frames pro Zeile (
--columns 8) setzt so viele Frames in eine Zeile, und jeder Clip läuft nach dem letzten weiter: ein Kontaktabzug oder das feste Raster, das der Importer einer Engine verlangt. - Eine Seite aus einer anderen gezeichnet (die Spiegeln-Node des Asset-Graphen): Ein links-rechts-symmetrisches Modell sieht von links genauso aus wie eine gespiegelte Ansicht von rechts, also muss die Westseite gar nicht gerendert werden – nimm die Sprites der Ostkamera, spiegle sie als
West, und das Sheet hatwalk_Westauswalk_Eastgezeichnet, Pixel, Normalen, Boxen und Root Motion gespiegelt. Rendere nur die Kameras, die sich unterscheiden; spiegle den Rest. - Die Grad jeder Seite stehen in der JSON: auf jedem Frame (
pixor.degrees) und, für alle, untermeta.pixor.sides({"South": 0, "Southeast": 45, ...}): Grad von vorn, gegen den Uhrzeigersinn von oben gesehen, so wie--sidessie nimmt. Ein Spiel macht mit dieser Tabelle aus einem Winkel eine Zeile.
Schattenebene
Schattenebene (--shadow contact oder --shadow drop) schreibt name_shadow.png, angeordnet wie das Sheet: schwarz, wo der Schatten fällt, sonst transparent. Contact ist ein Fleck unter den Füßen, so groß wie die Standfläche des Modells; Drop ist die Silhouette, die vom Hauptlicht weg auf den Boden geworfen wird. Zeichne sie mit der gewünschten Deckkraft unter deine Sprites oder sortiere sie getrennt. Die Ebenen-Node eines Asset-Graphen kann shadow nennen, und ein Überlagern legt sie in einem Sheet unter das Sprite (Asset-Graph).
Farbzyklus zur Laufzeit
Bei zyklischen Materialien listet das JSON jedes unter meta.pixor.cycles ("material" und seine "indices" in der Palette, in Zyklusreihenfolge), und Pixor schreibt name_index.png, das Sheet als Palettenindizes. Eine Engine kann diese Paletteneinträge bei jedem Tick rotieren, statt mehr Frames zu speichern. Andere Materialien, die dieselben Schattierungen teilen, laufen mit, wie bei jedem Palettenzyklus; gib einem zyklischen Material eigene Farben, um es abzugrenzen.
Szenen aus mehreren Modellen und Parallaxe-Hintergründe
Ein Projekt kann mehr als ein Ding enthalten: Modelle, auf einer Bodenebene angeordnet und als ein Bild gerendert, mit einem Licht und Schatten zwischen ihnen — eine Dorfecke, ein Dungeonraum, ein Lager, Store-Seiten-Grafik aus der kostenlosen Bibliothek.
Jedes ist ein Item: ein Modell, wo es steht, wohin es schaut und wie groß es ist – eine Item-Node des Szenen-Graphen, ans Ende seiner Kette angehängt, die ein Kranz oder ein Verstreuen danach wiederholt. Auf der Kommandozeile ist jedes --item eines:
pxr project new camp.pixor \
--item tent.glb@-1.8,-1.6,25,1.2 \
--item campfire.pixoritem@0,0 \
--item barrel.glb@2,1,0,1,2 \
--ground 7,5,#5d7a45 \
--size 200
pxr render camp.pixor
@x,z[,yaw[,scale[,layer]]] ist, wo ein Item steht (Meter, x nach rechts, z zur Kamera hin); --ground W,D[,#rrggbb] legt eine Bodenebene darunter. Füge :clip[,phase] hinzu, und dieses Item spielt einen eigenen Clip ab, an seiner eigenen Stelle darin, während die daneben stillstehen. Pfade sind relativ zum Projekt.
Parallaxe-Ebenen (eine Parallaxe-Ebenen-Datei-Node, 2 bis 8 Ebenen, oder --parallax N) teilen das Bild nach Tiefe in Ebenen für einen scrollenden Hintergrund: Jede wird allein auf derselben Bühne und Palette gerendert, und fernere Ebenen werden zur haze-Farbe hin (--haze) dunkler und blauer, so wie Entfernung aussieht (Ferne Ebenen dunstig aus oder --haze none lässt jede Ebene unverändert auf der Palette, für ein Spiel mit fester Palette). Die layer eines Items legt es in eine Ebene (0 ist die fernste); die übrigen werden nach Tiefe verteilt. Pixor schreibt name_layer0.png, name_layer1.png, …, name_parallax.json (das Bild jeder Ebene und eine empfohlene Scroll-Geschwindigkeit, von 0.25 für die fernste bis 1 für die nächste) und name_parallax.png, die Ebenen gestapelt. Jedes Modell lässt sich aufteilen, nicht nur eine Szene aus mehreren. Die Ebenen-Node eines Asset-Graphen benennt eine Ebene als layer0, layer1, …, um sie auf ein eigenes Sheet zu legen (Asset-Graph). pxr project set --parallax N --haze #rrggbb|none setzt beides für ein Projekt.
Konsolenmodi
Für Homebrew- und Fantasy-Konsolen wähle unter Style eine Konsole (oder --console). Pixor nutzt dann die eigenen Farben der Konsole und ihre Grenzen:
| Konsole | Farben | Pro Sprite | Notizen |
|---|---|---|---|
| Game Boy | die 4 Grüntöne | 3 + transparent | Schattierungen nach Helligkeit |
| NES | die 54-Farben-Masterpalette | 3 + transparent | auch pro Kachel von 8 × 8 geprüft |
| PICO-8 | sein 16 | alle 16 | eine .p8-Cartridge exportieren (hake p8 an; das Sheet muss in 128 × 128 passen: Setz eine maximale Breite von 128) |
| TIC-80 | seine 16 (Sweetie 16) | alle 16 | das PNG mit import sprites von TIC-80 importieren |
| C64 | sein 16 | 3 + transparent | Multicolor-Sprites: Pixel doppelt so breit; halte die Breite gerade (C64-Sprites sind 24 px) |
Wo ein Sprite nur drei Farben nutzen darf, wählt Pixor die drei Konsolenfarben, die dein Modell in Schatten, Grundfarbe und Licht am besten abdecken, sodass jeder Frame und jede Seite dieselben drei nutzt. Der Style-Abschnitt sagt, ob der Frame auf dem Bildschirm passt; pxr console check sheet.png prüft ein ganzes Sheet (Farben, Farben pro Frame und pro Kachel, doppelt breite Paare, Größe) und liest die Konsole aus dem Rezept im Sheet. Jeder Render in einem Konsolenmodus führt dieselbe Prüfung am geschriebenen Sheet aus und schlägt fehl (Exit-Status 1, die Probleme aufgelistet), wenn es nicht passt. Eine eigene Palette bleibt unter einem Konsolenmodus erhalten und wird nicht durch die der Konsole ersetzt – eine Sechzehn-Farben-Palette auf einem Game Boy wird also laut gemeldet, statt still gegen die vier Grüntöne getauscht. Die NES-Farben berechnet Pixor aus dem Videosignal der Konsole, die anderen sind die veröffentlichten Werte der Konsolen.
Palettentreue Beleuchtung in Engines
Engines beleuchten Sprites aus Normal Maps mit weicher Schattierung, was Farben hereinbringt, die deine Palette nie hatte. Hake Licht-Kit an (oder --export light-kit), und Sprites reagieren auf Licht im Spiel, während jedes beleuchtete Pixel auf einer Stufe seiner eigenen Farbrampe bleibt, mit Pixors Lichtstufen, Farbtonverschiebung und Glanzlichtern. Pixor schreibt neben das Sheet:
| Datei | Was es ist |
|---|---|
name_ramps.png |
die Farbrampe jedes Pixels (Rampennummer + 1 in Rot; 0 für Pixel, die kein Licht trifft, wie Linien) |
name_normal.png |
die Normalen, im Ansichtsraum: x rechts, y oben, z zur Kamera hin |
name_light.png |
die Lookup-Textur: eine Zeile pro Rampe, eine Spalte pro Lichtstufe, dann die Glanzlichtfarbe, dann zwei Spalten, die gar keine Farben sind – die eigenen Glanzlichtschwellen dieser Rampe, denn ein glänzendes oder metallisches Material bekommt sein Glanzlicht leichter als ein mattes |
pixor_palette_light.gdshader, name_light.tres |
der Godot-Shader und ein Material mit jeder gesetzten Textur: Leg das Material auf ein Sprite2D oder AnimatedSprite2D |
PixorPaletteLight.shader |
der Unity-Shader: Erstell damit ein Material für einen SpriteRenderer und setz seine drei Maps |
pixor_palette_light.fsh, .vsh |
der GameMaker-Shader; die Kommentare zeigen, wie die Maps gebunden werden |
Die Shader beleuchten mit einem Hauptlicht (light_dir, zum Licht hin, im Raum der Normalen), dem Fülllicht des Presets sowie Glanz- und Randlichtern, deren Schwellen aus der Lookup-Textur kommen, pro Rampe, so wie bei Pixor selbst. specular oder rim auf eine Zahl zwischen -1 und 1 zu setzen überschreibt sie für das ganze Sprite; über 1 schaltet diese Glanzlichter ab; unter -1 (die Vorgabe) nimmt die Werte der Lookup-Textur. Ein Glanzlicht wird nur gezeichnet, wo auch eines der vier Nachbarpixel eines bekommt – Pixors eigene Regel gegen ein einzelnes helles Pixel; min_highlight 1 schaltet das ab. Beweg das Licht per Skript, zum Beispiel zu einer Fackel hin: material.set_shader_parameter("light_dir", dir). Importiere die drei Maps ohne Filterung, ohne Kompression und ohne Mipmaps. Um es vor dem Export zu sehen, schalte die 2D-Lichtvorschau (L) über dem Sprite ein und wähle Beleuchten als: das Licht-Kit: Das Licht dreht sich zum Mauszeiger, und der Frame wird über dieselbe Lookup-Textur nach denselben Regeln beleuchtet (Glanzlichter nur neben einem anderen, Pixel ohne Rampe unberührt), wie die Shader ihn beleuchten. Mit dem Licht des Renders sieht ein Frame genau so aus, wie Pixor ihn gezeichnet hat (ausgenommen ein paar Pixel an Stufenkanten); Schlagschatten, Dithering und die Flackerglättung animierter Sheets gibt es nur in Pixor, also schalte Schlagschatten für Sheets ab, die du in der Engine beleuchtest. Das JSON listet die Dateien und das Licht unter meta.pixor.light_kit.
Palettenvarianten
Variante hinzufügen (--variant NAME, wiederholbar) exportiert dasselbe Sheet in anderen Farben. Pixor zeichnet in Palettenindizes, also ändert eine Variante nur die Palette: Jedes Pixel, jede Linie und jede Schattierung bleibt, wo es ist.
- Effekte:
hit-flash,frozen,poisoned,petrified,burning,silhouette,selected, die Tageszeitendawn,noon,dusk,nightund die Jahreszeitenautumnundwinter(Grün wird orange oder blass und verschneit). - Teamfarben:
team:blue(oderred,green,yellow,purple,orange,teal,pink,white,blackoderteam:#3050e0) färbt nur die Teamfarbe um — die mit--teamoder unter Materialien markierten Materialien oder Farben — und lässt Haut, Stahl und Gold, wie sie sind. Jede Schattierung behält ihre Helligkeit, die Rampe bleibt also lesbar. Vier Teams aus einem Sprite:--team cloth --variant team:red --variant team:blue --variant team:green --variant team:yellow. Das JSON listet die Palettenindizes des Teams untermeta.pixor.team, für Engines, die zur Laufzeit über die Lookup-Textur unten umfärben. - Jede Farbe gedreht:
hue:120dreht jede farbige Schattierung um 120 Grad; Grau bleibt grau. - Andere Paletten:
palette:pixor-8oderpalette:my-colours.hexbringt jede Farbe auf die nächste Farbe dieser Palette und hält dabei Hell und Dunkel auseinander.
Jede Variante ist name_<variant>.png. Mit jeder Variante schreibt Pixor auch zwei Dateien zum Tauschen von Paletten zur Laufzeit, sodass ein Sheet jeder Stufe und jedem Team dient:
name_index.png: das Sheet mit dem Palettenindex jedes Pixels als Grauwert (0 ist transparent);name_lut.png: eine Lookup-Textur, 256 Pixel breit, eine Zeile pro Palette (Zeile 0 die eigene des Sheets, Zeile k Variante k).
Ein Shader schlägt lut(index / 255, row) nach. Das JSON listet die Varianten und ihre Zeilen unter meta.pixor.variants.
Das Rezept in jedem Export
Jede Datei, die Pixor exportiert, merkt sich das Projekt, das sie gemacht hat: das Sheet, seine Ebenen-Sheets und Maps (_lines, _flat, _normal, _depth, _emission, _shadow), seine Palettenvarianten und das Index-Sheet, die .aseprite und jedes GIF (in einem Kommentar) und APNG. Leg eine davon auf Pixor (oder wähle sie unter Projekt öffnen), um das Projekt zurückzubekommen: die .pixor-Datei, wenn sie noch da ist, oder ein neues Projekt, aus dem Rezept wiederaufgebaut. Pfade werden relativ zur exportierten Datei gespeichert; ein Pfad, der nicht relativ werden kann, behält nur seinen Dateinamen, sodass ein geteiltes Sheet deine Ordnernamen nicht verrät. Entferne den Haken bei Rezept in Dateien (oder übergib --no-recipe), um es wegzulassen.
Godot 4
- Kopiere
name.pngundname.tresnebeneinander in dein Projekt. - Die
.treslädt das Sheet ausres://name.png. Legst du es woanders ab, übergib beim Export auf der Kommandozeile--godot-path res://path/name.pngoder bearbeite den Pfad oben in der.tres. - Erstelle ein
AnimatedSprite2Dund setze seine Sprite Frames aufname.tres. Jede Action und Seite ist eine Animation, in Schleife, mit ihren gehaltenen Frames. - Für scharfe Pixel setze Texture > Filter auf Nearest.
Unity
- Mit dem Aseprite-Importer-Paket (2D Aseprite Importer): Ziehe
name.asepritein Assets. Jedes Tag wird zu einem Animationsclip; verwende die Ebenefinal. - Ohne es: Importiere
name.pngals Sprite (Multiple), Filter Mode Point, Compression None, und schneide es nach Zellgröße (die Zellgröße steht inname.jsonuntermeta.pixor.cell). Der Pivot steht inmeta.pixor.pivot, in Pixeln ab der oberen linken Ecke der Zelle.
GameMaker
Importiere name.png als Sprite-Streifen: Nutze pro Animation einen Export im Layout Strip (--layout strip) oder schneide das Raster nach Zellgröße. Setz den Ursprung auf den Pivot aus name.json.
Aseprite
Öffne name.aseprite oder klick an der Aseprite-Datei-Node auf Öffnen (Pixor findet Aseprite im PATH und in den üblichen Steam- und itch-Ordnern und fragt sonst, wo es liegt). Die Tags listen jede Action und Seite. Die Ebene final ist sichtbar; lines und flat sind verborgene Helfer zum Nachbessern von Hand, ebenso jede zusätzliche Ausgabe, die der Style-Graph nennt, über final. Die Datei ist im indizierten Modus mit Pixors Palette.
Übermale es und behalte deine Arbeit. Füge eigene Ebenen hinzu und male, dann ändere das Modell oder den Look in Pixor und backe neu:
pxr rebake out/hero.aseprite
Pixor gehört, was es geschrieben hat, und sonst nichts. Ein Neu-Backen rendert das Projekt erneut und:
- ersetzt die Pixel der Ebenen, die Pixor erstellt hat (
final,lines,flat), wo niemand darauf gemalt hat; - lässt deine Ebenen genau so, wie sie sind – nie verschoben, umbenannt, umsortiert oder umgefärbt –, mit jeder gemalten Cel auf dem Frame, auf dem sie gemalt wurde. Jeder Frame trägt eine ID aus dem, was er ist (Action, Seite, Zeit), sodass deine gemalten Augen auf ihren eigenen Posen bleiben, wenn der Gang in der Mitte drei Frames dazubekommt, statt auf neue zu rutschen – und das Re-Bake sagt das Frame für Frame:
moved your paint on frame 1 is on frame 2 now, und welche Frames neu sind (movedundnew_atin--json); - behält jede Farbe, mit der du gemalt hast, an ihrem Index und fügt neue Farben am Ende der Palette an – oder schreibt den Render auf einem Sheet, das du in Aseprite auf Graustufen oder RGB umgestellt hast, passend in Grau- oder Farbtönen;
- behält deine Slices, ihre Keys auf den Frames, auf denen sie waren, wohin diese Frames auch gewandert sind;
- markiert Frames, in denen sich das Modell unter deiner Malerei weggeschoben hat, mit einem Tag,
pxr check, und lässt die Malerei, wo sie ist.
Zwei Dinge entscheidet es nicht allein und behält beides, bis du entscheidest:
| Was passiert ist | Was das Re-Bake macht |
|---|---|
| Du hast auf einer von Pixors eigenen Ebenen gemalt | Pixors Ebene bekommt den neuen Render; deine Änderung wandert auf eine eigene Ebene, final edits, direkt darüber; der Frame bekommt den Tag pxr conflict |
| Ein Frame, den du übermalt hast, ist nicht im neuen Render (der Clip wurde kürzer) | der Frame wird am Ende behalten, mit deiner Malerei, getaggt pxr removed |
So oder so geht nichts verloren. pxr rebake endet dann mit Code 7, bis du sagst, in welche Richtung es geht: --resolve keep behält deine Änderungen als deine eigenen Ebenen, --resolve pixor nimmt Pixors Render und verwirft sie. --dry-run sagt, was ein Re-Bake tun würde, ohne etwas zu schreiben, und --json sagt es für ein Tool; die Erweiterung stellt dir dieselbe Frage in einem Dialog.
GIF und APNG
Jede Action und Seite wird zu einer eigenen Datei in Schleife (ein Clip ohne Schleife läuft einmal). Die Frames nutzen die Palette des Sprites, mit Index 0 transparent. Maßstab an der GIF- oder APNG-Node (--anim-scale K) vergrößert sie um eine ganze Zahl, von 1 bis 16, sodass ein Sprite mit 64 px als GIF mit 256 px rausgehen kann und jedes Pixel scharf bleibt.
GIF speichert Verzögerungen in Hundertstelsekunden, daher wird die Verzögerung jedes Frames gerundet, aber die Gesamtlänge des Clips bleibt erhalten. Browser zeigen Verzögerungen unter 20 ms als 100 ms, also ist kein GIF-Frame kürzer als 20 ms: Über 50 fps lässt das GIF die Frames weg, die kürzer zu sehen wären, und läuft so lange wie der Clip. APNG speichert die exakten Millisekunden, gerundet auf die laufende Summe wie im JSON, sodass die Frames eines Clips mit 12 fps 83 und 84 ms lang sind. Benenne eine .apng-Datei in .png um, wenn eine Website nur PNG annimmt. Ein Clip, den die Ebene-Node eines Asset-Graphen gezeichnet hat, animiert diese Ebene – nur die Linien, die flachen Farben – so, wie das Sheet sie zeigt; eine Ebene der Normal-, Tiefen- oder Emission-Maps animiert das Sprite, da ein GIF nur Palettenfarben hält.
Video
Video pro Clip schreibt jede Action und Seite als name_walk_Southeast.avi: ein unkomprimiertes AVI mit 24-Bit-Farbe, das jeder Editor und Konverter öffnet und das nichts verliert — kein Codec verschmiert ein Pixel. Seine Node hat drei Einstellungen:
- Maßstab (1 bis 16, anfangs 4): wie viele Videopixel ein Art-Pixel ist.
- Frames pro Sekunde (1 bis 100, anfangs 30): Ein Video läuft mit einer Rate, also wird ein Sprite-Frame so oft geschrieben, wie er dauert, und der Clip behält seine Länge bis auf einen Video-Frame genau.
- Hintergrund: was hinter dem Sprite ist. Ein Video hat keine Transparenz.
--export video auf der Kommandozeile nimmt die Startwerte, oder --video-scale K, --video-fps N und --video-background #RRGGBB. --export all lässt Videos weg: Nenne sie.
Es ist nicht komprimiert, also groß – ein Sprite mit 64 px bei Maßstab 4 hat etwa 200 KB pro Frame –, und ein Video über einem Gigabyte wird abgelehnt statt geschrieben. Um es online zu stellen, wandle es um: ffmpeg -i hero_walk_South.avi -crf 0 hero_walk_South.mp4.
Schlichte Engines und eigener Code
Lies name.json: frames[i].frame ist das Zellrechteck und frames[i].duration seine Haltedauer in Millisekunden; meta.frameTags fasst Frames zu Animationen zusammen, und ein Tag, der einmal läuft statt zu loopen, trägt "repeat": "1", so wie Aseprite es schreibt. frames[i].pixor nennt den tag des Frames (den Namen seines Frame-Tags), seinen index darin, seine action und side, seine id und seinen pivot – den Punkt in der Zelle, auf den die Engine das Sprite stellt, also den des Sheets, sofern nicht eine Tag-Node dem Clip einen eigenen gegeben hat. Der Pivot-Slice in meta.slices hat einen Key, wo immer sich der Pivot ändert, und der Pivot-Slice der .aseprite-Datei dieselben Keys.
Root Motion
Ein An Ort und Stelle exportierter Clip hat zwei weitere Werte pro Frame, in Pixeln mit erhaltenen Nachkommastellen (x nach rechts, y nach unten):
frames[i].pixor.root: wo die Wurzel des Modells wäre, gemessen ab ihrer Position zu Beginn des Clips.frames[i].pixor.root_delta: wie weit sich die Wurzel bis zum nächsten Frame bewegt. Für den letzten Frame ist es die Bewegung bis zum Ende des Clips, damit sich wiederholende Gehzyklen mit gleicher Geschwindigkeit weiterlaufen.
Um die Figur so zu bewegen, wie es der Clip tat, addiere root_delta zur Position des Sprites, jedes Mal wenn ein Frame endet.
Inventar-Icons
pxr icons (oder eine Icons-Node im Asset-Graphen, erzeugt beim Export des Projekts) macht aus Modellen passende Inventar-Icons: jedes Modell aus demselben ¾-Winkel unter dem Licht-Rig Studio, in 16, 24, 32 und 48 Pixeln (oder --sizes), mit der Silhouette in der Farbe seiner Seltenheit (--rarity common|uncommon|rare|epic|legendary) und mit --framed auf einer gerahmten Kachel wie ein Inventarplatz. Jedes Icon ist ein PNG, und jede Größe bekommt einen Atlas icons_N.png mit icons_N.json, das sagt, wo jedes Icon liegt. Richte es auf einen Ordner, um ein ganzes Pack in ein Icon-Set zu verwandeln — in der App ziehst du den Ordner auf das Fenster und schaltest Icons statt Sprites ein: Größen, Seltenheit (aus dem Namen jeder Datei, sofern du keine wählst) und Rahmen sind dort, und das Rezept wird neben den Icons als icons.pixoricons gespeichert:
pxr icons library/pickups --out icons --rarity epic --framed
--rarity from-name gibt jedem Modell die Seltenheit, die ein Wort in seinem Dateinamen nennt (potion_rare.glb, Sword-Epic.glb; ohne ein solches Wort ist es gewöhnlich), und die JSON nennt die jedes Icons. Dateien werden in Namensreihenfolge genommen, sodass der Atlas gleich bleibt, egal wie der Ordner sie auflistet.
Ein Rezept hält das Paket fest: --save pack.pixoricons schreibt die Ordner und die Einstellungen (Pfade relativ zum Rezept), und pxr icons pack.pixoricons erstellt das Paket erneut, Byte für Byte. Eine dem Ordner hinzugefügte Requisite kommt beim nächsten Lauf dazu; ein Flag nach dem Rezept ändert eine Einstellung für diesen Lauf (pxr icons pack.pixoricons --sizes 64).
Voxel und Sprite-Stacks
Eine MagicaVoxel-.vox-Datei öffnet sich wie jedes andere Modell: jedes Modell ihrer Szene dort, wo der Szenengraph es hinsetzt (gedreht und verschoben, wie MagicaVoxel es zeigt), ihre Palette, und die Voxel eines leuchtenden Materials leuchten. Ein Voxel gilt als ein Zehntel Meter, +Z oben.
pxr voxels MODEL -o hero.vox --height 32 macht aus jedem Modell Voxel, 32 hoch: die Oberfläche aus seinen Texturen und Farben abgetastet, das Innere gefüllt, jedes Voxel in der eigenen Palette des Looks (--preset, --palette und die anderen Look-Optionen), sodass die Voxel zu den Sprites passen. Mit --stack schreibt es auch einen Sprite-Stack: hero_stack.png, das Modell in waagerechte Scheiben geschnitten, nebeneinander, die unterste zuerst, jede von oben gesehen, und hero_stack.json mit Scheibengröße und -anzahl. Ein Spiel zeichnet Scheibe k ein Pixel über Scheibe k - 1 und dreht alle zusammen – so täuscht Sprite-Stacking 3D vor.
pxr voxels knight.glb -o knight.vox --height 32 --stack --preset selout
Prüfen, ob alles passt
pxr audit folder --style game.pixorkit liest jedes exportierte PNG und jede .aseprite-Datei in einem Ordner und prüft sie gegen das Kit, anhand des Rezepts in jeder Datei: Preset, Licht-Rig, Ansicht, Kameraneigung, Hauptlicht, Lichtstufen, Linien, Palette und Pixel pro Meter, und ob jede verwendete Farbe in der Palette des Kits ist. Ohne Kit ist die erste Datei die Referenz. Jeder Unterschied wird aufgelistet; jeder Unterschied setzt den Exit-Status auf 1, damit es einen Build absichern kann.
In der App zeigt die Konsistenz-Tafel (die Schaltfläche mit den drei Figuren, Konsistenz-Tafel: alle Seiten auf einmal, oder B) den aktuellen Frame von jeder Seite nebeneinander auf einer Grundlinie, mit markierter Oberkante jeder Silhouette und Breite, Höhe und Farbanzahl darunter. Unter der Schaltfläche:
- Silhouetten zeichnet jede Seite nur als ihre Form, in einer Farbe: Eine Pose, die als Silhouette nicht lesbar ist, ist es auch in Spielgröße nicht.
- Pivots markiert das Pixel, auf dem jede Seite steht und um das sie sich dreht. Eine Seite, deren Füße daneben liegen, rutscht, wenn sich das Sprite dreht.
- Farbanzahl schreibt die Anzahl jeder Seite; die Tafel sagt, wenn sich die Höhen zwischen Seiten um mehr als ein Pixel unterscheiden (Höhen unterscheiden sich … zwischen Seiten) oder eine Seite deutlich mehr Farben hat als eine andere (meist ein Licht, das nur eine Seite trifft).
pxr audit oben ist die ordnerweite Hälfte: jedes Sheet gegen ein Kit.
Was die Prüfungen gefunden haben, auf den gemeinten Pixeln
Jede Prüfung, die Pixor macht – Einzelpixel, mit einem Pixel gezeichnete Linienecken, dicke Linien, eine Farbe außerhalb der Palette, eine Kachel oder ein Frame mit mehr Farben, als ein Konsolenmodus erlaubt –, markiert die betroffenen Pixel, statt beim Export nur eine Textzeile auszugeben.
- In der App: Die Schaltfläche Prüfungen über dem Sprite (das Warndreieck) zeichnet die Markierungen auf den Frame, und der Abschnitt Bericht in den Schritten Style und Asset listet jeden Fund jedes bisher gerenderten Frames. Klicke auf einen, und Pixor springt mit eingeschalteten Markierungen zu diesem Frame und dieser Seite. Unter der Liste sagt jede Art von Fund, welche Einstellung darüber entscheidet – Einzelpixel die Bereinigung, gezackte Ecken die Linien, Farben die Palette, Konsolengrenzen der Konsolenmodus, eine gespiegelte Seite, die nicht zur Spiegelung des Exports passt –, und Zur Einstellung öffnet diese Einstellung.
- Gespiegelte Seiten: Mit einer Spiegeln-Node im Asset-Graphen wird eine Seite, die gespiegelt gezeichnet wird, mit der verglichen, die sie spiegelt, und wo das Modell dafür nicht symmetrisch genug ist, werden die Pixel markiert, die sich ändern, während du noch wählst – nicht erst als Warnung beim Export.
- Beim Export: Hake Bericht an (oder
--export report), und Pixor schreibtname_report.pngneben das Sheet: das Sheet mit jedem Fund markiert. Einzelne Pixel werden gefüllt; eine Kachel oder ein Frame wird umrahmt, sodass das Betroffene noch durchscheint.
| Farbe | Was |
|---|---|
| Cyan | ein verirrtes Pixel (ein Waisenpixel) |
| Gelb | eine Linie, die in einem Pixel um die Ecke biegt |
| Magenta | ein Zwei-mal-zwei-Block aus Linie: eine dicke Linie |
| Rot | ein Pixel außerhalb der Palette |
| Orange | eine 8 x 8-Kachel mit mehr Farben, als die Konsole erlaubt |
| Tieforange | ein Frame mit mehr Farben, als die Konsole erlaubt |
| Rosa | eine Farbe, die die Konsole nicht hat |
| Violett | ein Pixel, das von der Seite abweicht, von der es gespiegelt wird |
| grüne Kiste | ein Teil, in seiner schlichten Farbe gezeichnet, weil seine Texturdatei fehlt: Leg die Datei neben das Modell |
Pixeleffekte
Eine Effekt-Node des Szenen-Graph (in der Gliederung unter Effekte gelistet) fügt einen aus 3D-Partikeln gezeichneten Effekt hinzu: Explosion, Hit-spark, Slash, Magic-burst, Heal, Portal, Smoke-puff, Dust, Fire-loop, Rain, Snow, Fireflies und Falling-leaves. Jeder ist eine eigene Action (fx-explosion, …), durch dieselbe Pipeline gerendert wie das Modell; er übernimmt also Palette, Pixelgröße, Licht und Linien des Sprites und wirkt, als gehöre er ins selbe Spiel. Setze seine Frames, Größe, Energie, Position und seinen Seed (derselbe Seed ergibt immer dieselben Pixel); lass ihn einem Knochen folgen (ein Hieb aus der Hand, ein Blitz an einer Mündung) und über einem Clip abspielen (der Schwung unter dem Hieb oder ein in Pixor mit Keys erstellter Clip); hake Nur Effekt an, um ihn ohne das Modell zu zeichnen, als eigene Ebene, passend zum Sheet der Figur. Treffer-Frame markiert den Frame, in dem der Treffer landet: Das JSON listet ihn unter meta.pixor.hits. Auf der Kommandozeile: --effect fireflies:12 --effect-clip shatter --effect-hit 6, auch der Clip in Pixor erstellt — Splitter, die per Keys unter dem Glitzern fliegen. Effekt erstellen auf dem Bildschirm eines leeren Projekts, neben Importieren… und Freie Modelle durchstöbern (oder pxr effect explosion -o fx.png), erstellt einen Effekt ganz ohne Modell.
Hitboxen, Hurtboxen und Andockpunkte
Die Box eines Teils im Inspektor (oder --hitbox, --hurtbox) macht es zu einer Hitbox (es teilt Treffer aus: ein Schwert) oder einer Hurtbox (es kann getroffen werden: der Körper), und Andockpunkt im JSON eines Knochens (oder --socket) macht ihn zu einem Andockpunkt (eine Hand, eine Mündung). Das JSON jedes Frames trägt dann pixor.boxes (part, kind, x, y, w, h in Zellpixeln, aus den Pixeln, die jedes Teil wirklich bedeckt) und pixor.sockets (die Position jedes Knochens in Zellpixeln), damit Spielcode Treffer prüfen und Effekte anhängen kann, ohne zu raten. Auch eine Modelldatei kann Teile markieren (pxr.box).
Paper-Doll-Ebenen
Mit angehängten Requisiten schreibt Paper-Doll-Ebenen (--paper-doll) außerdem name_base.png, das Modell ohne seine Requisiten auf derselben Arbeitsfläche, und eine Ebene pro Requisite (name_sword.png), ihre sichtbaren Pixel mit den Linien darum. Übereinandergelegt, die Basis zuerst, ergeben sie das volle Sheet; wer die Ebene einer Requisite tauscht, tauscht die Ausrüstung. name_stacked.png zeigt sie so gestapelt, wie die Engine sie stapeln wird: die Vorschau, die zeigt, dass sie passen. Die Pixel jedes Stücks sind die des Sheets; die Basis ist der Körper ohne die Stücke gezeichnet, sie weicht vom Sheet also nur wenige Pixel um die Kante eines Stücks ab und dort, wo ein Stück einen Schatten auf den Körper wirft – schalte Schlagschatten aus (--no-shadow) für Ebenen, die exakt übereinanderpassen. Zeilen, die eine Sprites-Node mit einem Teile-Set zeichnet, gehören zum eigenen Sheet dieser Node, nicht zu den Ebenen. (Die App erzeugt sie mit pxr aus dem gespeicherten Projekt und speichert es vorher, wenn es sich geändert hat, sodass die Ebenen dem entsprechen, was auf dem Bildschirm ist.)
Ausrüstung, die Teil des Modells ist – ein Helm, ein Schild, ein Umhang, mit der Figur modelliert statt als Requisite angehängt –, ist ein Stück:
pxr render knight.glb --clip all --paper-doll --piece helmet:Knight_Helmet --piece gear:Round_Shield,1H_Sword
pxr project set knight.pixor --paper-doll --piece helmet:Knight_Helmet
Jedes Stück nennt die Teile, aus denen es besteht (wie die Gliederung sie auflistet), und wird zu einer eigenen Ebene, name_helmet.png, genau wie die einer Requisite (in der App macht Eigene Paper-Doll-Ebene eines Teils es zu einer, nach ihm benannt): nur seine sichtbaren Pixel, sodass ein Schild hinter dem Körper dort verdeckt ist, wo der Körper ihn verdeckt. Die Basis wird ohne alle Stücke und Requisiten gerendert, sodass dort gezeichnet wird, was ein Helm verdeckt hat – der Kopf darunter. --no-pieces entfernt sie aus einem Projekt. Die Ebene-Node eines Asset-Graphen nennt base oder ein Stück oder eine Requisite beim Namen als ihre Ebene, um die Ebenen nach Belieben anzuordnen (Asset-Graph).
Probier, was diese Seite beschreibt, mit deinem eigenen Modell aus, kostenlos im Browser.
Im Browser testen Pixor holen