Un oggetto che viene spesso usato insieme alla Surface è il Rect (rettangolo). Mentre la Surface è una porzione fisica di schermo
sulla quale si può disegnare, il Rect è un oggetto geometrico astratto, caratterizzato da una posizione e dalla lunghezza dei suoi
lati. Per creare un Rect basta usare la funzione costruttore Rect()
, che ha lo stesso nome
dell'oggetto. Ne esistono due versioni:
r = pygame.Rect(10, 10, 50, 80) |
Prende come parametri 4 numeri interi: le coordinate x, y dell'angolo in alto a sinistra, la larghezza e l'altezza |
r = pygame.Rect((10, 10), (50, 80)) |
Gli stessi parametri, ma sotto forma di due coppie di numeri |
Perchè i Rect sono così usati? Se avete provato a svolgere
l'Esercizio 4.4 della lezione precedente vi sarete sicuramente annoiati nel fare parecchi
calcoli banali con le coordinate (sommare la x del lato sinistro con la larghezza per trovare la x del lato destro ...). Il Rect rende
immediatamente disponibili tutti questi calcoli sotto forma di attributi: se r
è una variabile di
tipo Rect possiamo scrivere:
Attributo | Tipo di dato | Significato |
---|---|---|
r.left oppure r.x |
numero intero | la x del lato sinistro |
r.right |
numero intero | la x del lato destro |
r.top oppure r.y |
numero intero | la y del lato superiore |
r.bottom |
numero intero | la y del lato inferiore |
r.centerx |
numero intero | la x del centro del rettangolo |
r.centery |
numero intero | la y del centro del rettangolo |
r.topleft |
coppia di interi | le coordinate dell'angolo in alto a sinistra |
r.bottomright |
coppia di interi | le coordinate dell'angolo in basso a destra |
r.center |
coppia di interi | le coordinate del centro del rettangolo |
r.midtop |
coppia di interi | le coordinate del punto al centro del lato superiore |
e ve ne sono altri ancora che potete trovare nella documentazione dell'oggetto Rect: https://www.pygame.org/docs/ref/rect.html (sono elencati in un riquadro giallo dopo l'elenco delle funzioni: dovrebbe essere abbastanza facile capire il loro significato).
Ecco un semplice esempio che potete digitare direttamente su IDLE. Il costruttore crea un rettangolo di 200x100 pixel posizionato in (10, 20):
>>> import pygame . . . >>> r = pygame.Rect(10, 20, 200, 100) >>> r.left
10
>>> r.right
210
>>> r.topleft
(10, 20)
>>> r.bottomright
(210, 120)
r
.
Questi attributi possono essere sia letti che scritti: cambiando il valore di uno di essi tutti gli altri si modificheranno di conseguenza. Ad esempio se vogliamo spostare il Rect 10 pixel a destra ci basterà scrivere
r.left += 10
ma potremmo ottenere lo stesso risultato con r.right += 10
o r.centerx += 10
, e tutti gli altri attributi
saranno aggiornati per rispecchiare la nuova posizione.
Un'altra caratteristica molto utile del Rect è che l'oggetto ha anche dei metodi
per verificare facilmente le collisioni (cosa molto utile in un videogioco). Ad esempio, se
(x, y)
sono le coordinate di un punto e r
è un Rect, il metodo r.collidepoint(x, y)
restituirà True se il punto è interno al rettangolo, False altrimenti. Se invece
r
ed s
sono due Rect, r.colliderect(s)
restituirà True se i due
rettangoli si intersecano.
r
r
)collidepoint()
che il punto (20, 20) è interno al rettangolo e il punto (200, 300) è esternor
Una tecnica molto usata in pygame è quella di associare ad una Surface un Rect con le stesse dimensioni e di usare poi il Rect per posizionare la superficie o per verificare se un evento avviene all'interno di essa. Vediamo come usare questa tecnica per posizionare facilmente le Surface (e prossimamente le immagini) sullo schermo.
Ritorniamo al metodo blit()
, che, come abbiamo visto qui, serve a disegnare
una Surface all'interno di un'altra. Il metodo è piuttosto flessibile: se lo cerchiamo nella
documentazione ufficiale trovamo:
blit(source, dest, area=None, special_flags=0)->Rect
Spieghiamo dettagliatamente il significato dei vari parametri:
Parametro | Significato |
---|---|
source |
è la Surface da copiare (ricordo che la Surface destinazione è a sinistra del punto) |
dest |
è il punto della Surface destinazione in cui dobbiamo copiare source . Può essere una dupla
(x, y) (le coordinate del punto in cui copieremo l'angolo in alto a sinistra di source )
oppure può essere un Rect: in questo caso source sarà copiata a partire dal
topleft (l'angolo in alto a sinistra) del Rect |
area=None |
è un parametro opzionale che dovete usare solo se non volete copiare tutta la Surface source . In questo caso
potete usare un altro Rect per indicare quale parte della Surface copiare (lo utilizzeremo più avanti) |
special_flags=0 |
anche questo parametro è opzionale e permette di ottenere vari effetti grafici come una semitrasparenza. In questo tutorial non lo useremo. |
Rect |
ora possiamo dare un significato anche al valore restituito: è un oggetto Rect che rappresenta l'area della Surface destinazione effettivamente modificata dalla funzione (in genere non ci sarà bisogno di utilizzare questo valore) |
Nella blit()
useremo quasi sempre la forma in cui il secondo parametro è un Rect con le stesse
dimensioni della Surface da copiare. Per capire le potenzialità di questa tecnica vediamo un esempio: questo programma crea
due quadrati e li dispone affiancati sullo schermo.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
# creiamo la Surface surf1, la coloriamo di rosso e la posizioniamo sullo schermo
surf1 = pygame.Surface((200, 200))
surf1.fill("red")
rect1 = pygame.Rect(50, 50, 200, 200)
screen.blit(surf1, rect1)
# stessa cosa con surf2 (blu)
surf2 = pygame.Surface((100, 100))
surf2.fill("blue")
rect2 = pygame.Rect(0, 0, 100, 100)
rect2.topleft = rect1.topright
screen.blit(surf2, rect2)
# aggiorniamo lo schermo
pygame.display.flip()
# terminiamo correttamente il programma
input("Premi INVIO per terminare il programma")
pygame.quit()
Esaminiamo con attenzione il programma. Nella riga #9, dopo aver creato la Surface surf1
e averla colorata di rosso, creiamo il Rect rect1
con le stesse dimensioni e l'angolo in alto a sinistra in (50, 50);
nella #10 usiamo la blit()
dando come secondo parametro rect1
(quindi
surf1
sarà copiata a partire proprio da (50, 50)). Nelle righe successive facciamo lo stesso con surf2
(blu) e rect2
, ma ora osserviamo la riga #16: cambiamo il valore dell'attributo
rect2.topleft
ponendolo uguale a rect1.topright
: questo vuol dire che l'angolo in alto a
sinistra del quadrato blu sarà allineato all'angolo in alto a destra di quello rosso: abbiamo affiancato i due quadrati senza
dover fare nessun calcolo con le coordinate! Nella riga #17 usiamo di nuovo la blit()
con
rect2
come secondo parametro.
Quindi possiamo riassumere la nostra tecnica per posizionare facilmente le Surface così:
blit()
con il nostro Rect come secondo parametro (ripeto che la Surface verrà
disegnata a partire dall'angolo topleft
del Rect).C'è infine un'ulteriore comodità: anzichè creare i rettangoli con il costruttore
(facendo attenzione ad indicare esattamente le stesse dimensioni della Surface, con il rischio di sbagliare), possiamo farli creare
direttamente alla Surface con un metodo apposito. Il metodo get_rect()
dell'oggetto Surface restituisce
un Rect con le stesse dimensioni della Surface posizionato in (0, 0). Questo rende facile e sicuro ottenere il rettangolo
corretto.
surf1
un rettangolo delle giuste dimensioni (ma posizionato in (0, 0)) e nella
seconda lo posizioniamo in (50, 50). Sostituite anche la riga #15 allo stesso modo.
. . .
rect1 = surf1.get_rect()
rect1.topleft = (50, 50)
. . .
ESERCIZIO 5.4: Mantenendo invariata la posizione del quadrato rosso, posizionate quello blu come nelle figure qui sotto;
basta cambiare la riga #16 per allineare il secondo quadrato come vogliamo (ripassate tutti gli attributi
di un Rect nella tabella all'inizio).get_rect()
: proviamo a modificare le dimensioni delle due
Surface (possiamo anche farle diventare dei rettangoli) e notiamo che tutto va a posto automaticamente, senza bisogno di modificare
anche i Rect. Proviamo anche a modificare la posizione di rect1
e di nuovo il programma riposiziona tutto
automaticamente.Fine della lezione