Ray Tracing

Je l'ai simplement adapté pour que le calcul de la ligne soit toujours valable dans un monde où la gauche et la droite sont connectés, ainsi que le haut et le bas:

def Brensenham_line(pos1, pos2, taille):
    """
    D'après l'algorithme :
    Brensenham line algorithm, par Phillip Lenhardt
    http://mail.python.org/pipermail/python-list/1999-July/007163.html
    """
    steep = 0
    coords = []
    x,y,x2,y2 = pos1[0], pos1[1], pos2[0], pos2[1]
    
    if x2 > x + taille/2:
        x += taille
    if x > x2 + taille/2:
        x2 += taille
    if y2 > y + taille/2:
        y += taille
    if y > y2 + taille/2:
        y2 += taille
        
    dx = abs(x2 - x)
    if (x2 - x) > 0:
        sx = 1
    else:
        sx = -1
        
    dy = abs(y2 - y)
    if (y2 - y) > 0:
        sy = 1
    else:
        sy = -1
        
    if dy > dx:
        steep = 1
        x,y = y,x
        dx,dy = dy,dx
        sx,sy = sy,sx
        
    d = (2 * dy) - dx
    
    for i in range(0,dx):
        if steep:
            coords.append((Replace(y, taille), Replace(x, taille)))
        else:
            coords.append((Replace(x, taille), Replace(y, taille)))
        while d >= 0:
            y = Replace(y + sy, taille)
            d = d - (2 * dx)
        x = Replace(x + sx, taille)
        d = d + (2 * dy)
    
    return coords

Cette fonction, qui accepte en entrée les deux positions pos1 et pos2, et la taille du monde taille, fourni en sortie la liste des positions formant une ligne entre pos1 et pos2.

On utilise ensuite cette fonction pour tracer une ligne imaginaire entre le joueur et chaque case affichée. Si on rencontre une case au travers de laquelle on ne peut pas regarder, la valeur booléenne vue_libre devient fausse, et toutes les cases situées derrière ne seront pas visibles.

                    vue_libre = True
                    if [xx, yy] <> self.pos:
                        for pos in el.Brensenham_line(self.pos, (xx, yy), self.jeu.cfg.taille_zone * self.monde.taille)[1:]:
                            # On évalue chaque pos entre le joueur et (xx, yy)
                            zone, posxy = self.l1(pos)
                            vue_libre = zone.Est_Visible(posxy)
                            if not vue_libre:
                                break

self.pos est la position du joueur dans le monde, et (xx, yy) la position de la case qu'on veut afficher à l'écran. Le test if xx, yy == self.pos: est juste une exception pour ne pas prendre en compte la case courante.

Grille sur tuile

Ensuite, si vue_libre est vrai, la tuile est affichée normalement, sinon elle est affichée avec une grille dessus. Les objets et les animaux ne sont ensuite affichées que sur les cases visibles.

L'affichage de la grille est ce qui me pose le plus de problème. Il s'agit pourtant simplement d'afficher un quadrillage sur la partie de la tuile qui n'est pas transparente, mais je n'ai pas encore trouvé de moyen élégant (et rapide) pour le faire. Je passe par surfarray pour le faire, mais c'est lent et pas très propre:

tab1 = pygame.surfarray.pixels3d(self.tuile_iso[(xx,yy)])
tab2 = pygame.surfarray.pixels3d(self.monde.tiletech.tuile_iso_horsvue1)
                            
tabres = ((tab1 * (tab1 <> [255, 0, 255])) & tab2) + ([255, 0, 255] * (tab1 == [255, 0, 255]))
 surf = pygame.Surface((54, 54))
                            
pygame.surfarray.blit_array(surf, tabres)
surf.set_colorkey((255, 0, 255))

Voila le résultat pour l'instant :

Fov