Come gia' accennato in una precedente pagina, da un po' di tempo mi diverto nello sviluppo
di semplici giochini, utilizzando il linguaggio C, librerie SDL, il Gimp per
la creazione e il ritocco di alcuni disegni, Moonlight Atelier 3D per la
crezione dei modelli 3D (che, renderizzati, creano i disegni).
Avevo anche accennato a quanto noiosa sia la parte che riguarda la creazione degli sprite. Gli sprite (dall'inglese "folletto"), per chi non lo sapesse sono tutti quegli oggetti che, in un gioco, si muovono. Creare uno sprite significa: preparare un disegno base, creare tutti i disegni che costituiranno poi ogni frame dello sprite ed infine unire tutti questi disegni in un'unica immagine. In realta' questo e' il metodo piu' semplice, esistono anche altri metodi, diciamo piu' "professionali". Ma io non sono un professionista sviluppatore e seguo la via piu' semplice. Poniamo il caso che voglia fare uno sprite che rappresenti un bonus. Lo disegno con Moonlight Atelier 3D (beh, questo e' un mio personale metodo, c'e' chi i disegni li fa a mano, poi li scannerizza e li colora col Gimp): ![]() dopodiche' eseguo il rendering ottenendo la seguente immagine che verra' salvata in formato JPEG: ![]() Inizia cosi' la prima delle parti noiose. Vogliamo
far ruotare il bonus, in modo da renderlo un pochettino dinamico, ruotiamo
allora la lettera "A" all'interno di Moonlight e facciamo il rendering avendo
cura di salvare il file con un nome diverso da quello precedente e con un
nome che faccia capire che si tratta del secondo frame (ad esempio bonus2.jpg).
Alla fine avremo tutte le immagini necessarie a creare lo sprite.
A questo punto, inizia la seconda parte da amanuenso. Aprire tutte le immagini col Gimp, e incollarle tutte una di fianco all'altra in una nuova immagine. Ma e' un lavoro inutile !! Gimp infatti ha a disposizione un utilissimo strumento che si chiama Script-Fu. In pratica si tratta di un interprete in grado di eseguire delle istruzioni scritte in un file oppure date "a mano" tramite un'apposita console. Il linguaggio utilizzato e' lo Scheme, una sorta di "dialetto" del Lisp. Beh, non ho imparato proprio bene questo linguaggio, ma ho ottenuto quello che mi serviva leggiucchiando qualche tutorial qua e la' e soprattutto leggendo gli altri script presenti in /usr/share/gimp/1.2/scripts/. Qui sotto allego il mio script il quale, tramite una finestra di dialogo, chiede 8 nomi di file (le otto immagini per comporre lo sprite) e se si vuole utilizzare l'autocrop. Dopodiche' crea un'immagine vuota e vi copia/incolla dentro tutte le immagini una di fianco all'altra. Il risultato lo potete vedere qui sotto: ![]() ; script-fu-sprite.scm
; This script creates a sprite from 8 frames. ; REMEMBER: images must have same width and height ! ; ; It would be c00l if we could work on a dynamic number of frame, ; and using just 1 file base name and creating the other ones ; just concatenating a string, something like (pseudo-code): ; ; basename = "/home/darko/sprite" ; for(i to n_frames) ; filename[i] = basename + "1.jpg" ; ; let me study Scheme for another while to get that :-\ !! ; ; ; INSTALL NOTE: copy this script in /usr/share/gimp/1.2/scripts/ ; and do "Refresh" from Xtns menu of Gimp. ; ; by darko(at)autistici.org NO(C) means this is Free Software ! (define copypaste(lambda (layer n) (gimp-edit-copy layer) (gimp-rect-select sprite (* n width) 0 width height 2 0 0) (gimp-edit-paste spritelay 0) (gimp-image-merge-visible-layers sprite 0) ) ) (define (script-fu-sprite fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 test) ; load image images (set! img1( car (gimp-file-load 0 fr1 fr1) ) ) (set! img2( car (gimp-file-load 0 fr2 fr2) ) ) (set! img3( car (gimp-file-load 0 fr3 fr3) ) ) (set! img4( car (gimp-file-load 0 fr4 fr4) ) ) (set! img5( car (gimp-file-load 0 fr5 fr5) ) ) (set! img6( car (gimp-file-load 0 fr6 fr6) ) ) (set! img7( car (gimp-file-load 0 fr7 fr7) ) ) (set! img8( car (gimp-file-load 0 fr8 fr8) ) ) ; get active layers (set! lay1( car (gimp-image-get-active-layer img1) ) ) (set! lay2( car (gimp-image-get-active-layer img2) ) ) (set! lay3( car (gimp-image-get-active-layer img3) ) ) (set! lay4( car (gimp-image-get-active-layer img4) ) ) (set! lay5( car (gimp-image-get-active-layer img5) ) ) (set! lay6( car (gimp-image-get-active-layer img6) ) ) (set! lay7( car (gimp-image-get-active-layer img7) ) ) (set! lay8( car (gimp-image-get-active-layer img8) ) ) ; You should use autocrop _only_ if you know that all images autocropped ; will have same width and same height ! (if (eq? test TRUE)(plug-in-autocrop 1 img1 lay1) ) (if (eq? test TRUE)(plug-in-autocrop 1 img2 lay2) ) (if (eq? test TRUE)(plug-in-autocrop 1 img3 lay3) ) (if (eq? test TRUE)(plug-in-autocrop 1 img4 lay4) ) (if (eq? test TRUE)(plug-in-autocrop 1 img5 lay5) ) (if (eq? test TRUE)(plug-in-autocrop 1 img6 lay6) ) (if (eq? test TRUE)(plug-in-autocrop 1 img7 lay7) ) (if (eq? test TRUE)(plug-in-autocrop 1 img8 lay8) ) ; Remeber: width and height should be the same for all images ! (set! width( car (gimp-image-width img1) ) ) (set! height( car (gimp-image-height img1) ) ) ; create a new empty image (set! sprite( car (gimp-image-new (* 14 width) height 0) ) ) ; create a layer for the new image (set! spritelay( car (gimp-layer-new sprite (* 14 width) height 0 "spritelay" 100 0) ) ) ; add the layer just created (gimp-image-add-layer sprite spritelay -1) ; do the follow massive copy'n'paste ! (copypaste lay1 0) (copypaste lay2 1) (copypaste lay3 2) (copypaste lay4 3) (copypaste lay5 4) (copypaste lay6 5) (copypaste lay7 6) (copypaste lay8 7) (copypaste lay7 6) (copypaste lay6 5) (copypaste lay5 4) (copypaste lay4 3) (copypaste lay3 2) (copypaste lay2 1) ; display the new image (gimp-display-new sprite) ) (script-fu-register "script-fu-sprite" "<Toolbox>/Xtns/Script-Fu/Anim/Sprite" "Give 8 images and I will create a sprite !" "Darko Romanov" "No(c)" "April, 11 2003" "" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-VALUE "Image to load:" "\"\"" SF-TOGGLE "Autocrop:" FALSE ) Allego anche un breve programmino in C scritto da me che serve a testare le sprite (insomma, per non aver bisogno di metterle dentro a un gioco e completare due livelli prima di vedere come son venute!) : /* * Compile with: gcc -lSDL -lSDL_image -I/usr/include/SDL -o spritester spritester.c */ #include <stdio.h> #include "SDL.h" SDL_Surface *screen, *img; int fr, maxfr, wfr; void wait_event() { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: if(event.key.keysym.sym == SDLK_ESCAPE) { exit(0); } } } } void anim_sprite(void) { SDL_Rect r, s; r.x = (640 >> 1) - (wfr >> 1); r.y = (480 >> 1) - (img->h >> 1); r.w = wfr; r.h = img->h; s.x = fr * wfr; s.y = 0; s.w = wfr; s.h = img->h; SDL_BlitSurface(img, &s, screen, &r); if(++fr == maxfr) fr = 0; } int main(int argc, char **argv) { if(argc != 3) { printf("Usage: %s filename n_frames\n", argv[0]); exit(-1); } if((SDL_Init(SDL_INIT_VIDEO)==-1)) { printf("Could not initialize SDL: %s.\n", SDL_GetError()); exit(-1); } screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); atexit(SDL_Quit); SDL_WM_SetCaption("-= Sprite Tester by darko =-", "SpriteR"); img = (SDL_Surface *)IMG_Load(argv[1]); maxfr = atoi(argv[2]); wfr = img->w / (maxfr - 1); fr = 0; while(1) { anim_sprite(); wait_event(); SDL_UpdateRect(screen, 0, 0, 0, 0); SDL_Delay(30); } } by darko |