Esportare verso i motori di gioco

La finestra Esporta

Esporta (Ctrl+E) sta subito dopo Importa nell’intestazione della finestra, e apre una finestra disegnata come quella di Importa (D51):

  1. Pipeline di Asset: per cominciare, quella mostrata dal selettore Asset dell’intestazione. Ciò che scrive si progetta nel grafo di asset.
  2. Cartella di esportazione: scrivi un percorso, o Scegli… una cartella. Il progetto la ricorda.
  3. Esporta ora: il progetto così com’è aperto, salvato o no: esportare non lo salva mai, e un progetto senza titolo si esporta così com’è.

La finestra Esporta: la pipeline di asset, la cartella, i file che scriverà e il pulsante Esporta

Prima che tu prema Esporta la finestra elenca ogni file che l’esportazione scriverà, come li nomina pxr names: ognuno con il suo percorso nella cartella e il suo tipo (sprite sheet, JSON, GIF…), e sostituirà su un file che la cartella ha già. L’elenco viene ricalcolato (con un piccolo indicatore di caricamento, senza mai bloccare la finestra) quando cambi la pipeline di Asset, la cartella o il progetto. Una pipeline che non si può esportare così com’è (due uscite che scrivono lo stesso file, per esempio) dice lì il perché, ed Esporta aspetta che sia sistemata.

Premuto, quelle stesse righe, al loro posto, sono l’esportazione: ognuna con un indicatore di caricamento finché non viene scritta, poi una spunta, la sua dimensione, Apri (nel programma con cui la apre il tuo sistema) e Mostra cartella. Ciò che va storto viene detto sul file in cui si è fermato. Ferma interrompe un’esportazione a metà: ciò che è stato scritto resta, il file in scrittura viene rimosso. La finestra si può chiudere mentre lavora; Esporta la riapre.

Esegue esattamente ciò che esegue la riga di comando: pxr render PROJECT --pipeline NAME -o FOLDER, in un processo a sé, così Pixor resta reattivo, su un’istantanea del progetto così com’è aperto, scritta nella cartella generata (con i percorsi dei suoi file resi assoluti) e rimossa al termine dell’esportazione. I file sono chiamati come pxr render chiama quelli di quel progetto: con il nome del progetto, o per un progetto senza titolo con quello del suo modello. Ogni file viene scritto da zero dalla pipeline: ciò che i nodi del grafo di Asset Generano non viene mai copiato.

Ogni file va nella cartella. Lo sheet prende il nome del file dal nodo PNG del progetto (out/hero.png scrive FOLDER/hero.png); un file il cui percorso è sotto la cartella dello sheet mantiene il suo posto sotto FOLDER, e qualsiasi altro percorso (un archivio, un’animazione, icone nominate altrove) mantiene solo la sua ultima parte.

Cosa scrive un’esportazione

Ogni esportazione scrive uno sheet: una riga per azione e lato, una colonna per fotogramma, tutte le celle della stessa dimensione, con il pivot sullo stesso pixel in ciascuna. Aggiungi nodi File allo sheet nel grafo di Asset (o usa --export sulla riga di comando) per avere accanto file con lo stesso nome. Ognuno è un nodo collegato dallo sheet, con le sue impostazioni. --export all scrive ogni formato qui sotto tranne p8 e video, che vengono scritti solo se nominati: una cartuccia contiene solo uno sheet fatto apposta, e un video non compresso di ogni clip e lato può pesare gigabyte. Mai due di loro scrivono lo stesso file: pxr names rifiuta un progetto in cui due lo farebbero.

Formato File Per
png name.png lo sheet, un PNG indicizzato (indice 0 trasparente)
json name.json rettangoli delle celle, durate dei fotogrammi, un tag per azione e lato, il pivot. Il layout “array” di Aseprite, così gli importatori scritti per Aseprite lo leggono
aseprite name.aseprite un file Aseprite indicizzato: livelli final, lines, flat, e uno per ogni uscita extra del grafo di Stile; un tag per azione e lato; durate per fotogramma; una slice pivot
normale name_normal.png una normal map con lo stesso layout, per l’illuminazione 2D
profondità name_depth.png la profondità con lo stesso layout: bianco il più vicino, scuro il più lontano, un’unica scala per tutto lo sheet (meta.pixor.depth le dà entrambe in metri); trasparente dove non c’è nulla. Per l’ordinamento, la nebbia e l’illuminazione 2.5D
emissione name_emission.png ogni pixel luminoso nel suo colore, luminoso quanto brilla (un materiale luminoso, o la mappa emissiva del modello); trasparente altrove. Per bagliore e bloom
livelli name_lines.png, name_flat.png e name_LAYER.png per ogni uscita aggiuntiva del grafo di stile i livelli di linee e di colori piatti come sheet, e l’immagine di un nodo dove il grafo di Stile ne nomina una
palette name.hex, name.gpl la palette (formati Lospec e GIMP)
godot name.tres una risorsa SpriteFrames di Godot 4
gif name_walk_Southeast.gif, … una GIF animata per azione e lato, con le tenute come ritardi dei fotogrammi, per condivisione e anteprime
apng name_walk_Southeast.apng, … lo stesso come PNG animati, con ritardi esatti in millisecondi
video name_walk_Southeast.avi, … un video per azione e lato: un AVI non compresso, ogni pixel com’è, per un trailer o una pagina dello store
light-kit name_ramps.png, name_normal.png, name_light.png, shader illuminazione fedele alla palette nei motori (vedi sotto)
rapporto name_report.png lo sheet con i risultati di ogni controllo segnati (vedi sotto)
p8 name.p8 una cartuccia PICO-8 (vedi Modalità della console)
zip il percorso sul suo nodo un nodo Archivio ZIP nel grafo di Asset: i file collegati a esso, o tutto ciò che l’esportazione ha scritto

Una riga prende il nome dalla sua azione e dal suo lato: walk_Southeast.

Quali fotogrammi prende uno sheet, come sono disposti e quanti file scrive un render lo decide il grafo di Asset: un nodo Sheet e i suoi nodi File finché non lo ricolleghi.

Come si chiamano i fotogrammi e cosa sono

Ogni fotogramma in uno sheet ha un nome e un id, e rispondono a due domande diverse.

Il nome è un modello, uno schema basato sulle parole del tuo progetto, così il semplice default è ciò che vuole un principiante e uno studio può rispettare una convenzione che non ha scelto:

{project}_{action}_{side}_{index:2}.{ext}     hero_walk_East_00.png

Le parole sono {project}, {object}, {action}, {side}, {layer}, {set} (il set di parti con cui un nodo Sprite ha disegnato il fotogramma), {size}, {index} e {ext}. {index:3} completa un numero con zeri fino a tre cifre. {{ e }} scrivono una parentesi graffa. Una parola che Pixor non conosce è un errore quando digiti il modello, non un file chiamato hero_{genre}_00.png, e una parola vuota si porta via il separatore che la precede, così uno sprite senza lato è hero_Static_00.png.

Un valore che non può far parte di un nome di file (/ \ : * ? " < > |) viene rifiutato invece di essere sostituito in silenzio; uno spazio diventa _. L'unica eccezione è la parola propria di Pixor: una clip della libreria chiamata lib:walk diventa lib-walk in un nome, perché quei due punti sono di Pixor e non tuoi.

Due fotogrammi che finirebbero sullo stesso nome vengono rifiutati prima che si renderizzi qualsiasi cosa. Impostalo con --names da riga di comando, o tienilo nel progetto:

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

L'id dice cos'è un fotogramma, mai dove è finito. È un hash dell'oggetto, dell'azione, del lato, del tempo nell'azione e del livello, ed è scritto accanto a ogni fotogramma nel JSON e nei dati utente del .aseprite. Reimpaginare uno sheet, aggiungere una clip o cambiare il margine sposta i rettangoli e lascia stare gli id, quindi una build che fa riferimento ai fotogrammi per id non si rompe ogni volta che gira l'impaginatore. Ricampionare una clip a un'altra frequenza di fotogrammi cambia i suoi id, perché quelli sono fotogrammi diversi.

Sheet più piccoli

Sul nodo Disponi del grafo di Asset (o sulla riga di comando):

  • Ritaglia lo spazio vuoto (--trim) riduce ogni fotogramma ai suoi pixel. Il JSON dà la posizione di ogni fotogramma nella cella intera (spriteSourceSize, trimmed: true) e il file Godot imposta il margin di ogni fotogramma, così gli engine piazzano comunque ogni fotogramma sul pivot.
  • Memorizza una volta i fotogrammi ripetuti (--dedupe): i fotogrammi identici (pose tenute, lati di un oggetto fermo) condividono un unico posto.
  • Larghezza massima dello sheet (--max-width 4096) inizia una nuova riga prima che lo sheet diventi più largo, per motori e GPU con un limite di dimensione delle texture.
  • Altezza massima dello sheet (--max-height 2048) divide uno sheet più alto di così in pagine, clip intere per pagina: hero_1.png, hero_2.png, ognuna con il suo JSON e gli altri file accanto.
  • Fotogrammi per riga (--columns 8) mette quel numero di fotogrammi su una riga, ogni clip che prosegue dopo l’ultima: un provino a contatto, o la griglia fissa che chiede l’importatore di un motore.
  • Un lato disegnato da un altro (il nodo Specchia del grafo di asset): un modello simmetrico tra sinistra e destra appare da sinistra uguale a una vista ribaltata da destra, quindi il lato ovest non serve affatto renderizzarlo: prendi gli sprite della camera est, ribaltali come Ovest, e lo sheet ha walk_West disegnato da walk_East, con pixel, normali, riquadri e root motion specchiati. Renderizza solo le camere che differiscono; ribalta le altre.
  • I gradi di ogni lato sono nel JSON: su ogni fotogramma (pixor.degrees) e, per tutti, sotto meta.pixor.sides ({"South": 0, "Southeast": 45, ...}): gradi dal davanti, in senso antiorario visti dall’alto, come li accetta --sides. Un gioco trasforma un angolo in una riga con quella tabella.

Livello delle ombre

Livello delle ombre (--shadow contact o --shadow drop) scrive name_shadow.png, disposto come lo sheet: nero dove cade l'ombra, trasparente altrove. Di contatto è una macchia sotto i piedi grande quanto l'impronta del modello; Proiettata è la sagoma proiettata sul terreno dalla parte opposta alla luce principale. Disegnala sotto i tuoi sprite con l'opacità che preferisci, o ordinala a parte. Il nodo Livello di un grafo di Asset può indicare shadow, e una Sovrapposizione la mette sotto lo sprite in un unico sheet (Grafo di Asset).

Ciclo dei colori in fase di esecuzione

Con materiali a ciclo, il JSON li elenca uno per uno sotto meta.pixor.cycles ("material" e i suoi "indices" nella palette, nell’ordine del ciclo), e Pixor scrive name_index.png, lo sheet come indici della palette. Un motore può far ruotare quelle voci della palette a ogni tick invece di memorizzare altri fotogrammi. Gli altri materiali che condividono le stesse tonalità ciclano con loro, come in ogni ciclo di palette; dai a un materiale a ciclo colori suoi per tenerlo separato.

Scene con più modelli e sfondi in parallasse

Un progetto può contenere più di una cosa: modelli disposti su un piano di terra e renderizzati come un'unica immagine, con una sola luce e ombre tra di loro — un angolo di villaggio, una stanza di dungeon, un accampamento, una grafica per la pagina dello store dalla libreria gratuita.

Ognuno è un elemento: un modello, dove sta, verso dove guarda e quanto è grande; un nodo Elemento del grafo di Scena, aggiunto alla fine della sua catena, che un anello o una dispersione dopo di esso ripete. Sulla riga di comando, ogni --item è uno di essi:

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]]] è dove si trova un elemento (in metri, x a destra, z verso la camera); --ground W,D[,#rrggbb] mette un piano del terreno sotto. Aggiungi :clip[,phase] e quell’elemento riproduce una clip tutta sua, a un suo punto, mentre quelli accanto restano fermi. I percorsi sono relativi al progetto.

I livelli di parallasse (un nodo File Livelli di parallasse, da 2 a 8 livelli, o --parallax N) dividono l'immagine per profondità in livelli per uno sfondo a scorrimento: ognuno viene renderizzato da solo sullo stesso palco e con la stessa palette, e i livelli più lontani sfumano più scuri e più blu verso il colore della foschia (--haze), come appare la distanza (Foschia sui livelli lontani disattivato, o --haze none, lascia ogni livello sulla palette così com'è, per un gioco con palette fissa). Il livello di un elemento lo mette in un livello (0 è il più lontano); gli altri vengono ripartiti per profondità. Pixor scrive name_layer0.png, name_layer1.png, …, name_parallax.json (l'immagine di ogni livello e una velocità di scorrimento suggerita, da 0.25 per il più lontano a 1 per il più vicino) e name_parallax.png, i livelli impilati. Qualsiasi modello può essere diviso, non solo una scena con più elementi. Il nodo Livello di un grafo di Asset indica un livello come layer0, layer1, … per metterlo su uno sheet creato apposta (Grafo di Asset). pxr project set --parallax N --haze #rrggbb|none imposta entrambi su un progetto.

Modalità della console

Per le console homebrew e fantasy, scegli una Console sotto Stile (o --console). Pixor usa allora i colori della console e i suoi limiti:

Console Colori Per sprite Note
Game Boy le 4 tonalità di verde 3 + trasparente tonalità per luminosità
NES la palette principale da 54 colori 3 + trasparente controllato anche per tile 8 × 8
PICO-8 il suo 16 tutti 16 esporta una cartuccia .p8 (spunta p8; lo sheet deve stare in 128 × 128: imposta una larghezza massima di 128)
TIC-80 i suoi 16 (Sweetie 16) tutti 16 importa il PNG con import sprites di TIC-80
C64 il suo 16 3 + trasparente sprite multicolore: pixel larghi il doppio; mantieni pari la larghezza (gli sprite del C64 sono da 24 px)

Dove uno sprite può usare solo tre colori, Pixor sceglie i tre colori della console che meglio coprono il tuo modello in ombra, colore base e luce, così ogni fotogramma e ogni lato usa gli stessi tre. La sezione Stile dice se il fotogramma a schermo rientra; pxr console check sheet.png controlla un intero sheet (colori, colori per fotogramma e per tile, coppie a doppia larghezza, dimensione) e legge la console dalla ricetta dentro lo sheet. Ogni render in una modalità console esegue lo stesso controllo sullo sheet che ha scritto, e fallisce (codice di uscita 1, con i problemi elencati) quando non rientra. Una palette tua viene mantenuta sotto una modalità console, non sostituita da quella della console: così una palette di sedici colori su un Game Boy viene segnalata, ad alta voce, invece di essere scambiata in silenzio con i quattro verdi. I colori del NES sono calcolati da Pixor a partire dal segnale video della console, gli altri sono i valori pubblicati delle console.

Illuminazione fedele alla palette nei motori

I motori illuminano gli sprite dalle normal map con uno shading morbido, che introduce colori che la tua palette non ha mai avuto. Spunta Light kit (o --export light-kit) e gli sprite reagiscono alla luce del gioco mentre ogni pixel illuminato resta su un gradino della rampa del proprio colore, con le bande, lo spostamento di tinta e le luci alte di Pixor. Pixor scrive, accanto allo sheet:

File Cos’è
name_ramps.png la rampa di colori di ogni pixel (numero della rampa + 1 in rosso; 0 per i pixel che la luce non tocca, come le linee)
name_normal.png le normali, spazio della vista: x a destra, y in su, z verso la camera
name_light.png il lookup: una riga per rampa, una colonna per livello di luce, poi il colore della luce alta, poi due colonne che non sono affatto colori: le soglie della luce alta di quella rampa, perché un materiale lucido o metallico prende la luce alta più facilmente di uno opaco
pixor_palette_light.gdshader, name_light.tres lo shader di Godot e un materiale con ogni texture impostata: metti il materiale su uno Sprite2D o AnimatedSprite2D
PixorPaletteLight.shader lo shader di Unity: crea con esso un materiale per uno SpriteRenderer e imposta le sue tre mappe
pixor_palette_light.fsh, .vsh lo shader di GameMaker; i commenti mostrano come collegare le mappe

Gli shader illuminano con una luce principale (light_dir, verso la luce, nello spazio delle normali), la luce di riempimento del preset e luci alte speculari e di contorno le cui soglie vengono dalla texture di lookup, per rampa, come faceva Pixor. Impostare specular o rim a un numero tra -1 e 1 le sostituisce per l’intero sprite; sopra 1 spegne quelle luci alte; sotto -1 (il valore predefinito) usa quelle del lookup. Una luce alta viene disegnata solo dove anche uno dei quattro pixel vicini ne prende una, che è la regola di Pixor contro il pixel luminoso isolato: min_highlight 1 la disattiva. Muovi la luce da uno script, per esempio verso una torcia: material.set_shader_parameter("light_dir", dir). Importa le tre mappe senza filtro, senza compressione e senza mipmap. Per vederlo prima di esportare, attiva l’Anteprima dell’illuminazione 2D (L) sopra lo sprite e scegli Luce come: il light kit: la luce si gira verso il puntatore e il fotogramma è illuminato attraverso lo stesso lookup, con le stesse regole (luci alte solo accanto a un’altra, pixel senza rampa intatti), come lo illuminano gli shader. Con la luce del render un fotogramma appare esattamente come l’ha disegnato Pixor (le eccezioni sono pochi pixel ai bordi delle bande); ombre proiettate, dithering e l’attenuazione dello sfarfallio degli sheet animati sono solo di Pixor, quindi spegni le ombre proiettate per gli sheet che illumini nel motore. Il JSON elenca i file e la luce sotto meta.pixor.light_kit.

Varianti di palette

Aggiungi variante (--variant NAME, ripetibile) esporta lo stesso sheet in altri colori. Pixor disegna in indici di palette, quindi una variante cambia solo la palette: ogni pixel, linea e tonalità resta dov’è.

  • Effetti: hit-flash, frozen, poisoned, petrified, burning, silhouette, selected, le ore del giorno dawn, noon, dusk, night, e le stagioni autumn e winter (i verdi diventano arancioni, o pallidi e innevati).
  • Colori della squadra: team:blue (o red, green, yellow, purple, orange, teal, pink, white, black, o team:#3050e0) ricolora solo il colore della squadra — i materiali o i colori segnati con --team o sotto Materiali — e lascia pelle, acciaio e oro come sono. Ogni tonalità mantiene la sua luminosità, quindi la rampa si legge ancora. Quattro squadre da un solo sprite: --team cloth --variant team:red --variant team:blue --variant team:green --variant team:yellow. Il JSON elenca gli indici di palette della squadra sotto meta.pixor.team, per gli engine che ricolorano in fase di esecuzione tramite la texture di lookup qui sotto.
  • Ogni colore ruotato: hue:120 ruota ogni tonalità colorata di 120 gradi; i grigi restano grigi.
  • Altre palette: palette:pixor-8 o palette:my-colours.hex porta ogni colore al più vicino di quella palette, tenendo separati chiari e scuri.

Ogni variante è name_<variant>.png. Con qualsiasi variante, Pixor scrive anche due file per scambiare le palette durante l’esecuzione, così un solo sheet serve ogni livello e squadra:

  • name_index.png: lo sheet con l'indice di palette di ogni pixel come valore di grigio (0 è trasparente);
  • name_lut.png: una texture di lookup larga 256 pixel, una riga per palette (la riga 0 è quella dello sheet, la riga k la variante k).

Uno shader cerca lut(index / 255, row). Il JSON elenca le varianti e le loro righe sotto meta.pixor.variants.

La ricetta dentro ogni esportazione

Ogni file che Pixor esporta ricorda il progetto che l’ha creato: lo sheet, i suoi sheet di livello e mappe (_lines, _flat, _normal, _depth, _emission, _shadow), le sue varianti di palette e lo sheet di indici, il .aseprite, e ogni GIF (in un commento) e APNG. Rilasciane uno qualsiasi su Pixor (o sceglilo in Apri progetto…) per riavere il progetto: il file .pixor se c’è ancora, o un nuovo progetto ricostruito dalla ricetta. I percorsi sono salvati relativi al file esportato; un percorso che non si può rendere relativo tiene solo il nome del file, così uno sheet che condividi non mostra i nomi delle tue cartelle. Togli la spunta a Ricetta nei file (o passa --no-recipe) per ometterla.

Godot 4

  1. Copia name.png e name.tres nel tuo progetto, uno accanto all’altro.
  2. Il .tres carica lo sheet da res://name.png. Se lo metti altrove, passa --godot-path res://path/name.png quando esporti dalla riga di comando, o modifica il percorso in cima al .tres.
  3. Crea un AnimatedSprite2D e imposta il suo Sprite Frames su name.tres. Ogni azione e lato è un’animazione, in loop, con le tenute dei suoi fotogrammi.
  4. Per pixel nitidi imposta Texture > Filter su Nearest.

Unity

  • Con il pacchetto Aseprite Importer (2D Aseprite Importer): trascina name.aseprite in Assets. Ogni tag diventa una clip d'animazione; usa il livello final.
  • Senza: importa name.png come Sprite (Multiple), Filter Mode Point, Compression None, e taglialo per dimensione della cella (la dimensione della cella è in name.json sotto meta.pixor.cell). Il pivot è in meta.pixor.pivot, in pixel dall'angolo in alto a sinistra della cella.

GameMaker

Importa name.png come striscia di sprite: usa un’esportazione con layout Strip (--layout strip) per animazione o taglia la griglia per dimensione della cella. Imposta l’origine sul pivot da name.json.

Aseprite

Apri name.aseprite, o fai clic su Apri sul nodo del file Aseprite (Pixor trova Aseprite nel PATH e nelle solite cartelle di Steam e itch, e altrimenti chiede dov’è). I tag elencano ogni azione e lato. Il livello final è visibile; lines e flat sono livelli di supporto nascosti per i ritocchi a mano, e così ogni uscita extra che il grafo di Stile nomina, sopra final. Il file è in modalità indicizzata con la palette di Pixor.

Dipingici sopra e conserva il tuo lavoro. Aggiungi i tuoi livelli e dipingi, poi cambia il modello o il look in Pixor e rifai il bake:

pxr rebake out/hero.aseprite

Pixor possiede ciò che ha scritto, e nient'altro. Un nuovo bake renderizza di nuovo il progetto e:

  • sostituisce i pixel dei livelli creati da Pixor (final, lines, flat), dove nessuno ci ha dipinto sopra;
  • lascia i tuoi livelli esattamente come sono (mai spostati, rinominati, riordinati o ricolorati) con ogni cel dipinto sul fotogramma su cui è stato dipinto. Ogni fotogramma porta un id fatto di ciò che è (azione, lato, tempo), così se la camminata guadagna tre fotogrammi nel mezzo, gli occhi che hai dipinto restano sulle loro pose invece di scivolare su quelle nuove, e la ricottura lo dice, fotogramma per fotogramma: moved your paint on frame 1 is on frame 2 now, e quali fotogrammi sono nuovi (moved e new_at in --json);
  • mantiene ogni colore con cui hai dipinto al suo indice, aggiungendo i nuovi colori in fondo alla palette, oppure, su uno sheet che hai reso in scala di grigi o RGB in Aseprite, scrive il render in grigi o a colori di conseguenza;
  • mantiene le tue slice, con le loro chiavi sui fotogrammi in cui erano, ovunque siano finiti quei fotogrammi;
  • segna con un tag i fotogrammi in cui il modello si è spostato da sotto la tua pittura, pxr check, e lascia la pittura dov’è.

Due cose che non deciderà da solo, e di cui tiene entrambe le versioni finché non decidi tu:

Cosa è successo Cosa fa la ricottura
Hai dipinto su uno dei livelli di Pixor stesso Il livello di Pixor riceve il nuovo render; la tua modifica si sposta su un livello tuo, final edits, subito sopra; il fotogramma riceve il tag pxr conflict
Un fotogramma che hai dipinto non è nel nuovo render (la clip si è accorciata) il fotogramma viene tenuto alla fine, con la tua pittura, con il tag pxr removed

Non si perde nulla in nessun caso. pxr rebake esce allora con il codice 7 finché non dici quale strada prendere: --resolve keep conserva le tue modifiche come livelli tuoi, --resolve pixor prende il render di Pixor e le scarta. --dry-run dice cosa farebbe un nuovo bake senza scrivere nulla, e --json lo dice per uno strumento; l’estensione ti pone la stessa domanda in una finestra di dialogo.

GIF e APNG

Ogni azione e lato diventa un file a sé in loop (una clip che non va in loop si riproduce una volta). I fotogrammi usano la palette dello sprite, con l’indice 0 trasparente. Scala, sul nodo GIF o APNG (--anim-scale K), li ingrandisce di un numero intero, da 1 a 16, così uno sprite da 64 px può uscire come GIF da 256 px con ogni pixel ancora nitido.

La GIF memorizza i ritardi in centesimi di secondo, quindi il ritardo di ogni fotogramma viene arrotondato, ma la durata totale della clip si mantiene. I browser mostrano i ritardi sotto i 20 ms come 100 ms, quindi nessun fotogramma di una GIF dura meno di 20 ms: sopra i 50 fps la GIF omette i fotogrammi che resterebbero visibili meno a lungo, e dura quanto la clip. L’APNG memorizza i millisecondi esatti, arrotondati sul totale progressivo come nel JSON, quindi i fotogrammi di una clip a 12 fps durano 83 e 84 ms. Rinomina un file .apng in .png se un sito accetta solo PNG. Una clip disegnata dal nodo Livello di un grafo di Asset anima quel livello (solo le linee, i colori piatti) come lo mostra lo sheet; un Livello delle mappe normal, depth o emission anima lo sprite, perché una GIF contiene solo colori di palette.

Video

Video per clip scrive ogni azione e lato come name_walk_Southeast.avi: un AVI non compresso, colore a 24 bit, che ogni editor e convertitore apre e che non perde nulla — nessun codec sbava un pixel. Il suo nodo ha tre impostazioni:

  • Scala (da 1 a 16, 4 all'inizio): quanti pixel video vale un pixel dell'arte.
  • Fotogrammi al secondo (da 1 a 100, 30 all’inizio): un video va a una sola frequenza, quindi un fotogramma dello sprite viene scritto tante volte quanto dura, e la clip mantiene la sua durata entro un fotogramma del video.
  • Sfondo: ciò che sta dietro lo sprite. Un video non ha trasparenza.

--export video da riga di comando prende i valori iniziali, oppure --video-scale K, --video-fps N e --video-background #RRGGBB. --export all esclude i video: indicali per nome.

Non è compresso, quindi è grande (uno sprite da 64 px in scala 4 pesa circa 200 KB per fotogramma) e un video oltre il gigabyte viene rifiutato invece che scritto. Per metterlo online, convertilo: ffmpeg -i hero_walk_South.avi -crf 0 hero_walk_South.mp4.

Motori semplici e il tuo codice

Leggi name.json: frames[i].frame è il rettangolo della cella e frames[i].duration la sua tenuta in millisecondi; meta.frameTags raggruppa i fotogrammi in animazioni, e un tag che si riproduce una volta invece che in loop porta "repeat": "1", come lo scrive Aseprite. frames[i].pixor indica il tag del fotogramma (il nome del suo frame tag), il suo index al suo interno, la sua action e il suo side, il suo id e il suo pivot: il punto della cella su cui il motore posa lo sprite, che è quello dello sheet a meno che un nodo Tag non abbia dato alla clip il suo. La slice del pivot in meta.slices ha una chiave ovunque il pivot cambi, e la slice del pivot del file .aseprite le stesse chiavi.

Root motion

Una clip esportata Sul posto ha due valori in più per fotogramma, in pixel con le frazioni conservate (x verso destra, y verso il basso):

  • frames[i].pixor.root: dove si troverebbe la radice del modello, misurata da dove era all'inizio della clip.
  • frames[i].pixor.root_delta: di quanto si sposta la radice fino al fotogramma successivo. Per l'ultimo fotogramma è lo spostamento fino alla fine della clip, così le camminate in loop proseguono alla stessa velocità.

Per muovere il personaggio come faceva la clip, aggiungi root_delta alla posizione dello sprite ogni volta che finisce un fotogramma.

Icone d’inventario

pxr icons (o un nodo Icone nel grafo di Asset, creato quando il progetto viene esportato) trasforma i modelli in icone d'inventario coordinate: ogni modello dalla stessa angolazione ¾ sotto l'impianto luci Studio, a 16, 24, 32 e 48 pixel (o --sizes), con la sagoma nel colore della sua rarità (--rarity common|uncommon|rare|epic|legendary) e, con --framed, su un tile incorniciato come uno slot d'inventario. Ogni icona è un PNG, e ogni dimensione ha un atlante icons_N.png con icons_N.json che dice dove si trova ogni icona. Puntalo su una cartella per trasformare un intero pack in un set di icone — nell'app, trascina la cartella sulla finestra e attiva Icone al posto degli sprite: ci sono le dimensioni, la rarità (dal nome di ogni file, a meno che tu non ne scelga una) e la cornice, e la ricetta viene salvata accanto alle icone come icons.pixoricons:

pxr icons library/pickups --out icons --rarity epic --framed

--rarity from-name dà a ogni modello la rarità indicata da una parola del nome del file (potion_rare.glb, Sword-Epic.glb; senza una parola simile è comune), e il JSON indica quella di ogni icona. I file vengono presi in ordine di nome, così l’atlante è lo stesso comunque la cartella li elenchi.

Una ricetta conserva il pacchetto: --save pack.pixoricons scrive le cartelle e le impostazioni (percorsi relativi alla ricetta), e pxr icons pack.pixoricons ricrea il pacchetto, byte per byte. Un oggetto aggiunto alla cartella entra nell’esecuzione successiva; un flag dopo la ricetta cambia un’impostazione per quell’esecuzione (pxr icons pack.pixoricons --sizes 64).

Voxel e sprite stack

Un .vox di MagicaVoxel si apre come qualsiasi altro modello: ogni modello della sua scena dove lo mette il grafo della scena (ruotato e spostato come lo mostra MagicaVoxel), la sua palette, e i voxel di un materiale luminoso che brillano. Un voxel vale un decimo di metro, +Z in alto.

pxr voxels MODEL -o hero.vox --height 32 trasforma qualsiasi modello in voxel, alto 32: la superficie campionata dalle sue texture e dai suoi colori, l’interno riempito, ogni voxel nella palette del look (--preset, --palette e le altre opzioni del look), così i voxel corrispondono agli sprite. Con --stack scrive anche uno sprite stack: hero_stack.png, il modello tagliato in fette orizzontali affiancate, dal basso, ognuna vista dall’alto, e hero_stack.json con la dimensione e il numero delle fette. Un gioco disegna la fetta k un pixel sopra la fetta k - 1 e le ruota tutte insieme: è così che lo sprite stacking finge il 3D.

pxr voxels knight.glb -o knight.vox --height 32 --stack --preset selout

Verificare che tutto corrisponda

pxr audit folder --style game.pixorkit legge ogni PNG e file .aseprite esportato in una cartella e lo confronta con il kit, usando la ricetta dentro ogni file: preset, impianto luci, vista, inclinazione della camera, luce principale, bande di luce, linee, palette e pixel per metro, e che ogni colore usato sia nella palette del kit. Senza un kit, il riferimento è il primo file. Ogni differenza viene elencata; qualsiasi differenza rende il codice di uscita 1, così può fare da guardia a una build.

Nell’app, la tavola di coerenza (il pulsante con tre figure, Tavola di coerenza: tutti i lati insieme, o B) mostra il fotogramma attuale da ogni lato, uno accanto all’altro su un’unica linea del suolo, con la cima di ogni silhouette segnata e sotto la sua larghezza, altezza e numero di colori. Sotto il pulsante:

  • Sagome disegna ogni lato solo come forma, in un unico colore: una posa che non si legge come sagoma non si legge alle dimensioni di gioco.
  • Pivot segna il pixel su cui ogni lato poggia e attorno a cui ruota. Un lato con i piedi fuori dal pivot scivola quando lo sprite si gira.
  • Conteggio dei colori scrive il conteggio di ogni lato; la tabella segnala quando le altezze differiscono di più di un pixel tra i lati (Le altezze differiscono … tra i lati), o quando un lato ha diversi colori più di un altro (di solito una luce che colpisce un solo lato).

pxr audit qui sopra è la metà a livello di cartella: ogni sheet confrontato con un unico kit.

Cosa hanno trovato i controlli, sui pixel in questione

Ogni controllo che Pixor fa (pixel isolati, angoli di linea disegnati in un pixel, linee spesse, un colore fuori palette, un tile o un fotogramma con più colori di quanti ne consenta una modalità console) evidenzia i pixel a cui si riferisce invece di stampare solo una riga di testo al momento dell’esportazione.

  • Nell’app: il pulsante Controlli sopra lo sprite (il triangolo di avviso) disegna i segni sul fotogramma, e la sezione Rapporto nelle fasi Stile e Asset elenca ogni rilievo di ogni fotogramma renderizzato finora. Fai clic su uno e Pixor va a quel fotogramma e lato con i segni attivi. Sotto l’elenco, ogni tipo di rilievo dice quale impostazione lo decide (i pixel isolati la pulizia, gli angoli frastagliati le linee, i colori la palette, i limiti della console la modalità console, un lato ribaltato che non corrisponde alla specularità dell’esportazione) e Vai a apre quell’impostazione.
  • Lati specchiati: con un nodo Specchia nel grafo di asset, un lato che verrà disegnato ribaltato viene confrontato con quello che ribalta e, dove il modello non è abbastanza simmetrico, i pixel che cambiano vengono segnati mentre stai ancora scegliendo, non solo con un avviso all’esportazione.
  • All’esportazione: spunta report (o --export report) e Pixor scrive name_report.png accanto allo sheet: lo sheet con ogni rilievo segnato. I singoli pixel vengono riempiti; un tile o un fotogramma viene incorniciato, così ciò di cui si tratta resta visibile.
Colore Cosa
ciano un pixel isolato (un orfano)
giallo una linea che gira un angolo in un solo pixel
magenta un blocco di linea due per due: una linea spessa
rosso un pixel fuori dalla palette
arancione un tile 8 x 8 con più colori di quanti la console ne permetta
arancione scuro un fotogramma con più colori di quanti la console ne permetta
rosa un colore che la console non ha
viola un pixel che differisce dal lato da cui è specchiato
scatola verde una parte disegnata nel suo colore semplice perché manca il file della texture: metti il file accanto al modello

Effetti pixel

Un nodo Effetto del grafo di Scena (elencato sotto Effetti nella Struttura) aggiunge un effetto disegnato da particelle 3D: Explosion, Hit-spark, Slash, Magic-burst, Heal, Portal, Smoke-puff, Dust, Fire-loop, Rain, Snow, Fireflies e Falling-leaves. Ognuno è un'azione a sé (fx-explosion, …), renderizzata con la stessa pipeline del modello, quindi prende la palette, la dimensione dei pixel, la luce e le linee dello sprite: sembra parte dello stesso gioco. Imposta i suoi fotogrammi, la dimensione, l'energia, la posizione e il seme (lo stesso seme dà sempre gli stessi pixel); fallo seguire un osso (un fendente dalla mano, un lampo alla bocca di un'arma) e riprodurre sopra una clip (il colpo sotto il fendente, o una clip con chiavi creata in Pixor); spunta Solo effetto per disegnarlo senza il modello, come livello a sé allineato allo sheet del personaggio. Fotogramma del colpo segna il fotogramma in cui il colpo va a segno: il JSON lo elenca sotto meta.pixor.hits. Da riga di comando: --effect fireflies:12 --effect-clip shatter --effect-hit 6, con la clip creata anch'essa in Pixor — schegge con chiavi che volano sotto lo scintillio. Crea un effetto nella schermata di un progetto vuoto, accanto a Importa… e Sfoglia modelli gratuiti (o pxr effect explosion -o fx.png), crea un effetto senza alcun modello.

Hitbox, hurtbox e punti di aggancio

Il Riquadro di una parte nell'Ispettore (o --hitbox, --hurtbox) la rende una hitbox (infligge colpi: una spada) o una hurtbox (può essere colpita: il corpo), e il Punto di aggancio nel JSON di un osso (o --socket) lo rende un punto di aggancio (una mano, una bocca da fuoco). Il JSON di ogni fotogramma contiene allora pixor.boxes (part, kind, x, y, w, h in pixel della cella, dai pixel che ogni parte copre davvero) e pixor.sockets (la posizione di ogni osso in pixel della cella), così il codice di gioco può verificare i colpi e agganciare effetti senza tirare a indovinare. Anche un file di modello può segnare le parti (pxr.box).

Livelli paper doll

Con oggetti di scena agganciati, Livelli paper doll (--paper-doll) scrive anche name_base.png, il modello senza i suoi oggetti di scena sulla stessa tela, e un livello per oggetto (name_sword.png), i suoi pixel visibili con le linee intorno. Sovrapposti a partire dalla base, danno lo sheet completo; scambiare il livello di un oggetto scambia l’equipaggiamento. name_stacked.png li mostra sovrapposti in quel modo, come li sovrapporrà il motore: l’anteprima che mostra che combaciano. I pixel di ogni pezzo sono quelli dello sheet; la base è il corpo disegnato senza i pezzi, quindi differisce dallo sheet solo entro pochi pixel dal bordo di un pezzo, e dove un pezzo proietta un’ombra sul corpo: spegni le ombre proiettate (--no-shadow) per livelli che si sovrappongono esattamente. Le righe che un nodo Sprite disegna con un set di parti appartengono allo sheet di quel nodo, non ai livelli. (L’app li crea con pxr dal progetto salvato, salvandolo prima se è cambiato, così i livelli sono ciò che vedi a schermo.)

L’equipaggiamento che fa parte del modello (un elmo, uno scudo, un mantello modellati con il personaggio invece che attaccati come oggetto di scena) è un pezzo:

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

Ogni pezzo nomina le parti di cui è fatto (come le elenca la Struttura) e diventa un livello a sé, name_helmet.png, esattamente come un oggetto di scena (nell’app, il Livello paper doll proprio di una parte ne fa uno, con il suo nome): solo i suoi pixel che si vedono, così uno scudo dietro il corpo è nascosto dove il corpo lo nasconde. La base viene renderizzata senza alcun pezzo né oggetto di scena, così ciò che un elmo copriva (la testa sotto) viene disegnato lì. --no-pieces li toglie da un progetto. Il nodo Livello di un grafo di Asset nomina come suo livello base o un pezzo o un oggetto di scena per nome, per disporre i livelli come preferisce (Grafo di Asset).

Prova quanto descritto in questa pagina sul tuo modello, gratis nel browser.

Prova nel browser Ottieni Pixor