✚ Sviluppo videogiochi

Collisioni nei giochi 2D: rettangoli AABB, cerchi e punti

Come rilevare le collisioni in un gioco 2D con rettangoli allineati agli assi, cerchi e punti: formule, codice di esempio ed errori da evitare.

Quasi ogni gioco deve rispondere centinaia di volte al secondo alla stessa domanda: questi due oggetti si stanno toccando? Il proiettile ha colpito il nemico, il giocatore ha raccolto la moneta, il personaggio è atterrato sulla piattaforma. Per i giochi 2D bastano quasi sempre poche forme semplici, e conoscerne le formule permette di scrivere collisioni affidabili anche senza un motore fisico completo.

Perché usare forme semplici

Lo sprite di un personaggio può avere una sagoma complessa, ma confrontare pixel per pixel due immagini è costoso e raramente necessario. Si associa invece a ogni oggetto una forma di collisione semplificata, chiamata spesso hitbox o collider. Le più usate sono:

  • il rettangolo allineato agli assi (AABB, axis-aligned bounding box);
  • il cerchio;
  • il punto, utile per proiettili piccolissimi o per il cursore del mouse.

Il giocatore non vede la forma di collisione, ma ne percepisce gli effetti. Una hitbox leggermente più piccola dello sprite del giocatore rende il gioco più «generoso», mentre una hitbox più grande dei nemici fa sembrare ingiusti i colpi ricevuti.

Rettangolo contro rettangolo

Un AABB si descrive con la posizione dell'angolo in alto a sinistra e con larghezza e altezza, oppure con centro e semidimensioni. I suoi lati sono sempre paralleli agli assi dello schermo, ed è questo che rende il test così economico.

Due rettangoli si sovrappongono se e solo se si sovrappongono le loro proiezioni su entrambi gli assi:

funzione aabb_sovrapposti(a, b):
    return a.x < b.x + b.larghezza and
           a.x + a.larghezza > b.x and
           a.y < b.y + b.altezza and
           a.y + a.altezza > b.y

Basta che una sola delle quattro condizioni sia falsa perché i rettangoli siano separati. È il controllo più usato nei giochi 2D, dai platform ai giochi di ruolo visti dall'alto.

Attenzione alla scelta tra < e <=: con il minore stretto due rettangoli che si toccano esattamente su un bordo non risultano in collisione. Per un personaggio appoggiato a terra può essere proprio il comportamento desiderato; per una moneta da raccogliere forse no. L'importante è decidere e restare coerenti.

Cerchio contro cerchio

Due cerchi si toccano se la distanza tra i centri è minore della somma dei raggi. Per evitare la radice quadrata, operazione relativamente costosa, si confrontano i quadrati:

funzione cerchi_sovrapposti(a, b):
    dx = a.cx - b.cx
    dy = a.cy - b.cy
    r = a.raggio + b.raggio
    return dx*dx + dy*dy < r*r

I cerchi sono ideali per oggetti tondi o che ruotano, come asteroidi, palle e personaggi visti dall'alto. Hanno un vantaggio importante: la rotazione non cambia la forma, quindi il test resta identico qualunque sia l'orientamento.

Cerchio contro rettangolo

Il caso misto è molto comune, per esempio una palla che rimbalza contro i mattoncini in un clone di Breakout. Il metodo consiste nel trovare il punto del rettangolo più vicino al centro del cerchio, limitando le coordinate del centro all'interno del rettangolo:

funzione cerchio_rettangolo(c, r):
    px = limita(c.cx, r.x, r.x + r.larghezza)
    py = limita(c.cy, r.y, r.y + r.altezza)
    dx = c.cx - px
    dy = c.cy - py
    return dx*dx + dy*dy < c.raggio * c.raggio

Se il centro del cerchio è dentro il rettangolo, il punto più vicino coincide con il centro stesso e la distanza è zero: la collisione viene rilevata correttamente.

Punto dentro una forma

Il test più semplice di tutti serve per clic del mouse, tocchi sullo schermo e proiettili minuscoli:

  • punto in un AABB: la coordinata x è tra il bordo sinistro e quello destro, la y tra quello superiore e quello inferiore;
  • punto in un cerchio: il quadrato della distanza dal centro è minore del quadrato del raggio.

Rilevare non basta: rispondere

Sapere che due oggetti si toccano è solo metà del lavoro. Poi bisogna decidere che cosa succede, e le risposte sono molto diverse:

Situazione Risposta tipica
Giocatore e moneta Rimuovere la moneta, aumentare il punteggio
Proiettile e nemico Applicare danno, distruggere il proiettile
Giocatore e muro Separare gli oggetti, azzerare la velocità su quell'asse
Palla e mattoncino Invertire la componente della velocità perpendicolare al lato colpito

Per separare due AABB si calcola la penetrazione su ciascun asse e si sposta l'oggetto lungo l'asse con penetrazione minore. È il criterio più semplice per capire da quale lato è avvenuto il contatto.

Errori frequenti

  • Oggetti troppo veloci: un proiettile che in un aggiornamento si sposta più della larghezza del bersaglio può attraversarlo senza mai sovrapporsi. Si risolve con passi più piccoli, con test lungo il segmento percorso o con un raycast.
  • Origine dello sprite diversa da quella della hitbox: se lo sprite è disegnato dal centro e il rettangolo dall'angolo, le collisioni appaiono spostate. Disegnare le hitbox in modalità debug evita ore di ricerca.
  • Rettangoli ruotati trattati come AABB: se l'oggetto ruota, l'AABB non è più adatto. Serve un test per rettangoli orientati, per esempio con il teorema dell'asse separatore, oppure un cerchio.
  • Confronti tra tutti gli oggetti: con molti oggetti il numero di coppie cresce in fretta; servono tecniche di partizione dello spazio per scartare subito le coppie lontane.

In sintesi

  • Le collisioni si calcolano su forme semplificate, non sui pixel degli sprite.
  • Due AABB collidono se si sovrappongono le proiezioni su entrambi gli assi.
  • Per i cerchi si confronta il quadrato della distanza con il quadrato della somma dei raggi.
  • Il caso cerchio-rettangolo si risolve con il punto del rettangolo più vicino al centro.
  • Dopo il rilevamento serve una risposta: raccolta, danno, separazione o rimbalzo.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche