J'ai une matrice de tuiles, sur certaines de ces tuiles il y a des objets. Je veux calculer quelles tuiles sont visibles pour le joueur, et lesquelles ne le sont pas, et je dois le faire assez efficacement (pour que cela calcule assez rapidement même si j'ai de grandes matrices (100x100) et beaucoup d'objets).
J'ai essayé de le faire avec l' algorithme de ligne de Bresenham , mais c'était lent. De plus, cela m'a donné quelques erreurs:
----XXX- ----X**- ----XXX-
-@------ -@------ -@------
----XXX- ----X**- ----XXX-
(raw version) (Besenham) (correct, since tunnel walls are
still visible at distance)
(@ is the player, X is obstacle, * is invisible, - is visible)
Je suis sûr que cela peut être fait - après tout, nous avons NetHack, Zangband, et ils ont tous réglé ce problème d'une manière ou d'une autre :)
Quel algorithme pouvez-vous recommander pour cela?
Pour mes besoins, je définirai visible comme ceci: la tuile est visible quand au moins une partie (par exemple un coin) de la tuile peut être connectée au centre de la tuile du joueur avec une ligne droite qui ne coupe aucun obstacle.
la source
Réponses:
Votre définition du visible est la suivante:
Vous pouvez implémenter ce concept littéralement en traçant les rayons de votre tuile de joueur et en les croisant avec votre scène. Vous rompez à chaque itération une fois que le rayon frappe un obstacle (ou dépasse un certain seuil de distance) car vous n'êtes intéressé que par les tuiles que le joueur peut voir directement. Je vais interrompre le processus pour vous:
Voici une photo montrant 3 exemples de rayons. Les carreaux de couleur plus foncée sont le "résultat" de chaque rayon, c'est-à-dire où la collision s'est produite. Vous devrez cependant répéter tout autour du cercle:
Ajustez la distance maximale et le nombre de rayons pour les performances. Trop peu et vous manquerez de tuiles, trop et vos performances en souffriront. De plus, plus les rayons doivent parcourir le plus loin, plus «l'erreur» sera grande et plus vous aurez besoin de précision.
modifier
Consultez le didacticiel suivant sur la diffusion de rayons, en particulier les étapes 3 et 4, pour vous aider à implémenter le bit d'intersection de l'algorithme:
http://www.permadi.com/tutorial/raycast/rayc7.html
la source
Je préfère projeter des rayons d'ombre au lieu de rayons de ligne de vue.
Disons que c'est votre zone de vue (la zone potentiellement visible)
Les # blocs ne sont pas visibles lorsque le. sont visibles
Mettons un obstacle X:
Vous avez une liste des X qui se trouvent dans la zone de vue, puis vous marquez comme cachée chaque tuile qui se trouve derrière chacun de ces obstacles: lorsqu'un obstacle est marqué comme caché, vous le supprimez de la liste.
Dans l'exemple ci-dessus, vous pouvez voir l'ombre projetée par le plus à droite du mur inférieur et comment cette ombre supprime l'obstacle caché de la liste des obstacles que vous devez vérifier (X doit vérifier; * vérifié).
Si vous obtenez un tri de la liste à l'aide d'une partition binaire afin que le X le plus cosest soit vérifié en premier, vous pouvez accélérer légèrement votre vérification.
Vous pouvez utiliser une sorte d'algorithme de "batailles navales" pour vérifier le bloc de X à la fois (essentiellement à la recherche d'un X adiaque dans une direction qui peut élargir le cône d'ombre)
[MODIFIER]
Deux rayons sont nécessaires pour projeter correctement une ombre et, comme une tuile est rectangulaire, beaucoup d'hypothèses peuvent être faites en utilisant les symétries disponibles.
Les coordonnées des rayons peuvent être calculées à l'aide d'une simple partition d'espace autour de la tuile obstacle:
Chaque zone rectangulaire constitue un choix quant au coin du carreau qui doit être pris comme bord du cône d'ombre.
Ce raisonnement peut être poussé plus loin pour connecter plusieurs tuiles adjacentes et les laisser jeter un seul cône plus large comme suit.
La première étape consiste à s'assurer qu'aucun obstacle ne se trouve dans la direction de l'observateur, dans ce cas, l'obstacle le plus proche est considéré à la place:
Si la tuile jaune est un obstacle, cette tuile devient la nouvelle tuile rouge.
Considérons maintenant le bord supérieur du cône:
Les carreaux bleus sont tous des candidats possibles pour élargir le cône d'ombre: si au moins l'un d'entre eux est un obstacle, le rayon peut être déplacé en utilisant le partage d'espace autour de ce carreau comme vu précédemment.
La tuile verte n'est candidate que si l'observateur est au-dessus de la ligne orange qui suit:
Il en va de même pour l'autre rayon et pour les autres positions de l'observateur autour de l'obstacle rouge.
L'idée sous-jacente est de couvrir autant de surface que possible pour chaque coulée de cône et de raccourcir le plus rapidement possible la liste des obstacles à vérifier.
la source
Le problème que vous essayez de résoudre est parfois appelé Field of View, FOV pour faire court. Comme vous avez mentionné les roguelikes comme exemples, vous devriez jeter un œil à ce que le wiki de RogueBasin a à dire sur le sujet (il y a même des liens vers des implémentations): http://www.roguebasin.com/index.php?title=Field_of_Vision
Il existe plusieurs algorithmes différents avec des avantages et des inconvénients différents - une comparaison très pratique est également disponible sur RogueBasin: http://www.roguebasin.com/index.php?title=Comparative_study_of_field_of_view_algorithms_for_2D_grid_based_worlds
la source
J'ai également trouvé ceci qui a une démo qui fonctionne:
http://www.redblobgames.com/articles/visibility/
la source
Vous trouverez peut-être utile http://blogs.msdn.com/b/ericlippert/archive/2011/12/12/shadowcasting-in-c-part-one.aspx avec le reste de la série .
la source