4: L'OGGETTO Surface

COS'E' UNA Surface

Uno degli oggetti più usati in pygame è la Surface (cioè superficie): esso rappresenta una porzione rettangolare dello schermo sulla quale possiamo disegnare, scrivere, caricare immagini, ecc. Come abbiamo visto nella lezione precedente, la funzione pygame.set_mode() che crea la finestra principale ci restituisce proprio una Surface, che rappresenta l'intero spazio utile della nostra finestra (e che assegneremo da ora in poi alla variabile screen). Nella lezione precedente abbiamo anche usato il metodo fill(), che colora interamente una Surface di un dato colore: ad esempio, se surf è una variabile di tipo Surface, scrivendo surf.fill((255, 0, 0)) la coloriamo di rosso (al solito servono due parentesi, quelle esterne per la funzione e quelle interne che indicano la tuple di 3 valori per il colore RGB).

Vediamo ora in maniera più approfondita l'uso dell'oggetto Surface. Per proseguire dovete conoscere il sistema di coordinate di solito usato nella computer grafica, molto simile a quello del piano cartesiano (se ne avete bisogno trovate una breve spiegazione qui): la posizione di un punto sullo schermo è indicata in pygame da una coppia (cioè una tuple di due numeri interi) di coordinate x - y.

IL SOTTOMODULO draw

Il sottomodulo draw di pygame contiene alcune funzioni che servono a disegnare su una Surface. Per ogni sottomodulo la documentazione ufficiale di pygame contiene una pagina dove sono elencate e spiegate (in Inglese) tutte le funzioni definite in esso, che vi consiglio di tenere sempre d'occhio per riferimento, anche se non capite tutto quello che c'è scritto. Questo è il link alla documentazione del modulo draw, del quale vediamo ora alcune funzioni.

Ad esempio la funzione circle() è così definita:

circle(Surface, color, pos, radius, width=0) -> Rect.

La funzione serve e disegnare un cerchio e questo è il significato dei parametri:

Parametro Tipo di dato Significato
Surface Un oggetto di tipo Surface La surface sulla quale vogliamo disegnare il cerchio
color Una tuple di tre numeri interi RGB o una string con il nome di un colore Il colore del cerchio
pos Una tuple di due numeri interi Le coordinate del centro del cerchio
radius Un numero Il raggio del cerchio (in pixel)
width=0
(parametro opzionale)
Un numero Lo spessore del contorno. Se viene omesso il cerchio viene riempito
Rect
(valore restituito)
Un oggetto Rect (ne parleremo nella prossima lezione)
NUOVO PROGRAMMA: prova_surface.py

import pygame

# inizializza pygame: chiamare sempre per prima
pygame.init()

# finestra principale (prende come parametro una tupla con le dimensioni)
screen = pygame.display.set_mode((800, 600))

pygame.draw.circle(screen, "red", (200, 200), 120)

# aggiorna lo schermo dopo che abbiamo disegnato su screen
pygame.display.flip()

#termina correttamente il programma
input("Premi INVIO per terminare il programma")
pygame.quit()

La riga #9 disegna quindi un cerchio rosso sullo schermo. In #12 abbiamo usato la flip() per aggiornare lo schermo (provate a toglierla e non vedrete nulla!).

Vediamo ora la funzione line(), che serve a tracciare un segmento:

line(Surface, color, start_pos, end_pos, width=1) -> Rect.

Possiamo già accorgerci che molti dei parametri sono uguali alla precedente; anzichè il centro ed il raggio dovremo fornire due coppie di coordinate (i punti start_pos ed end_pos di inizio e fine del segmento). Di nuovo l'ultimo parametro width è opzionale: se lo omettiamo lo spessore del segmento sarà di 1 pixel. Aggiungete questa riga dopo la riga #9:


.   .   .
pygame.draw.line(screen, "green", (400, 100), (600, 500), 4)
.   .   .

e vedrete ora anche un segmento verde piuttosto spesso.

ESERCIZIO 4.1: Se avete capito come si usano le due funzioni cercate di modificare i loro parametri. Cambiate i loro colori, i punti di inizio e fine del segmento, il centro ed il raggio del cerchio e per ultimo disegnate un cerchio vuoto anzichè pieno (cioè solo la circonferenza).

Un po' più difficili da usare sono le funzioni draw.polygon() e draw.lines() che prendono come parametro una lista (o tuple) di punti. Per non rendere illeggibile la chiamata di funzione è probabilmente meglio assegnare la lista ad una variabile. Ad esempio provate ad aggiungere queste righe (naturalmente sempre prima della flip()!)


lista_punti = ((100, 400), (250, 600), (350, 550), (400, 450), (200, 400))
pygame.draw.polygon(screen, "yellow", lista_punti)
ESERCIZIO 4.2: Disegnate con la draw_polygon()un triangolo rettangolo, un quadrato, un rombo, un trapezio.
SOLUZIONI

Nel modulo ci sono ancora altre funzioni, come rect(), ellipse(), arc(), aaline(), aalines() il cui uso potete cercare di capire da soli. Vi assicuro che leggere la documentazione in inglese può essere all'inizio ostico, ma più diventerete esperti più diventerà indispensabile.

COSTRUIRE ALTRE Surface - IL METODO blit()

Oltre alla Surface della nostra finestra, restituita dalla set_mode(),possiamo creare altre Surface con la funione costruttore (ve ne ho già parlato qui). Il costruttore di una Surface prende come parametro una dupla con la larghezza e l'altezza della Surface, quindi scrivendo

surf = pygame.Surface((200, 100))

otteniamo una Surface rettangolare di 200x100 pixel e la assegniamo alla variabile surf.

Quando però creiamo una Surface in questo modo, essa non è "disegnata" da nessuna parte: per essere visibile essa deve essere copiata sulla Surface principale (la nostra screen) o su un'altra Surface con il metodo blit(). Ecco un esempio:

NUOVO PROGRAMMA: prova_blit.py

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))

# creiamo una nuova Surface, la coloriamo di bianco e vi disegniamo un cerchio
surf = pygame.Surface((200, 200))
surf.fill("white")
pygame.draw.circle(surf, "red", (50, 50),  20)

# disegniamo surf sulla superficie principale
screen.blit(surf, (50, 50))

# aggiorniamo lo schermo
pygame.display.flip()

# terminiamo correttamente il programma
input("Premi INVIO per terminare il programma")
pygame.quit()

Notate che in #7 abbiamo creato una nuova Surface quadrata di 200x200 pixel e l'abbiamo assegnata alla variabile surf. Abbiamo poi colorato surf di bianco e vi abbiamo disegnato un cerchio rosso. Tutte queste operazioni non si vedrebbero però senza la riga #12 che copia surf sulla nostra superficie principale screen. Notate che la blit() è un metodo dell'oggetto Surface, e quindi va chiamata con la sintassi con il punto nome_variabile.nome_metodo(parametri). Vedremo più in dettaglio lo schema della funzione nella prossima lezione, per il momento ricordate che:

ESERCIZIO 4.3: Provate a commentare (cioè ad inserire un # all'inizio) la riga #12 e verificate che effettivamente senza di essa si ottiene uno schermo nero.
ESERCIZIO 4.4: Posizionate il quadrato bianco nell'angolo in alto a sinistra dello schermo (facile), poi in quello in alto a destra, in basso a sinistra ed in basso a destra (dovete fare un po' di calcoli con le coordinate e modificare il secondo parametro della blit(), cioè il punto a partire dal quale copiate surf). Infine, più difficile di tutti, posizionate il quadrato esattamente al centro dello schermo.
SOLUZIONI

Fine della lezione