Preferirei lanciare raggi d'ombra anziché raggi di linea di vista.
Supponiamo che questa sia la tua area di visualizzazione (l'area potenzialmente visibile)
######################
#####.............####
###................###
##..................##
#....................#
#....................#
#..........@.........#
#....................#
#....................#
##..................##
###................###
#####.............####
######################
I blocchi # non sono visibili mentre il. sono visibili
Mettiamo un ostacolo X:
######################
#####.............####
###................###
##.....X.....XXX....##
#......X.......X.....#
#...X.XX.............#
#...X......@.........#
#...X..........X.....#
#...XXXXXX...........#
##..................##
###....X...........###
#####.............####
######################
Hai un elenco della X che si trova all'interno dell'area di visualizzazione, quindi contrassegni come nascoste tutte le tessere che si trovano dietro ciascuno di questi ostacoli: quando un ostacolo viene contrassegnato come nascosto, lo rimuovi dall'elenco.
######################
#####.............####
###................###
##.....X.....XXX....##
#......X.......X.....#
#...X.XX.............#
#...X......@.........#
#...X..........X.....#
#...XXXXX*...........#
##......##..........##
###....*#..........###
#####.###.........####
######################
Nell'esempio sopra puoi vedere l'ombra proiettata dall'estrema destra della parete inferiore e come questa ombra elimina l'ostacolo nascosto dall'elenco dell'ostacolo che devi controllare (X deve controllare; * controllato).
Se riesci a ordinare l'elenco usando un partiton binario in modo da controllare prima la cosest X, potresti accelerare leggermente il tuo controllo.
Puoi usare una sorta di algoritmo "Battaglie navali" per controllare il blocco di X in una volta (sostanzialmente alla ricerca di una X adiacente che è in una direzione che può allargare il cono d'ombra)
[MODIFICARE]
Sono necessari due raggi per proiettare correttamente un'ombra e, poiché una piastrella è rettangolare, si possono fare molte ipotesi usando le simmetrie disponibili.
Le coordinate del raggio possono essere calcolate usando un semplice partizionamento dello spazio attorno alla tessera ostacolo:
Ogni area rettangolare costituisce una scelta su quale angolo della piastrella dovrebbe essere preso come bordo del cono d'ombra.
Questo ragionamento può essere spinto ulteriormente per collegare più tessere adiacenti e consentire loro di lanciare un singolo cono più largo come segue.
Il primo passo è garantire che non vi siano ostacoli verso la direzione dell'osservatore, in tal caso si considera invece l'ostacolo più vicino:
Se la tessera gialla è un ostacolo, quella tessera diventa la nuova tessera rossa.
Ora consideriamo il bordo del cono superiore:
Le tessere blu sono tutte possibili candidate per allargare il cono d'ombra: se almeno una di esse è un ostacolo, il raggio può essere spostato usando lo spazio che divide intorno a quella tessera come visto in precedenza.
La tessera verde è candidata solo se l'osservatore si trova sopra la linea arancione che segue:
Lo stesso vale per l'altro raggio e per le altre posizioni dell'osservatore rispetto all'ostacolo rosso.
L'idea alla base è quella di coprire quanta più area possibile per ogni lancio del cono e di abbreviare il più rapidamente possibile l'elenco degli ostacoli da controllare.