Ombres réalistes pour roguelike

image

Bon moment, communauté Habr.

Il y a plusieurs années, je suis tombé sur un post (1) . Ensuite, j'ai été intrigué par l'opportunité de créer des éléments intéressants pour le gameplay dans roguelike (2) . Supposons que l'ennemi puisse être derrière le mur, nous ne le voyons pas tant que nous ne le rencontrons pas en ligne de mire. Mais je préfère la situation où nous, voyageant le long des couloirs du donjon, révélons progressivement les caractéristiques de la localisation des objets en fonction de la portée.

Plus tard dans les articles: (3) , (4) et (5) , les questions de la projection d'ombres dans les jeux 2D ont été examinées. Comme l'ont noté les auteurs eux-mêmes et dans les commentaires, le calcul des ombres est assez volumineux et n'est pas une tâche facile, à la fois pour la calculatrice et pour la conception.

D'une manière ou d'une autre, j'ai eu quelques jours libres et j'ai décidé de revenir sur la question des ombres plus prometteuses. Il est clair que la carte vidéo gère les ombres avec succès et rapidement, mais dans ce cas, je voulais traiter les ombres pour un jeu 2D, et il semblait superflu de transférer les calculs sur la carte vidéo. Oui, et la puissance du processeur ces dernières années dans son ensemble a augmenté, en fait un article sur ce qui s'est finalement passé.

Le programme a été écrit en Pascal, simplement parce que je le connais bien, et Lazarus est un IDE ouvert avec une large gamme de composants.

L'idée originale était de tracer des lignes, de l'observateur à travers chacun des coins de la tuile, puis d'assombrir la figure résultante.

image

Cependant, une telle ombre semble quelque peu artificielle lorsque l'angle de vue change. Les ombres sont maintenant plus larges, maintenant plus étroites.

image

L'ombre d'un objet rond est bien meilleure. Pour construire une telle ombre, vous devez dessiner deux tangentes du point d'observation au cercle et aux bordures de l'écran. Le diamètre du cercle correspondra à la taille de la tuile.

Dans mon programme, j'ai utilisé la fonction suivante:

//       function tangent_to_circle(x1,y1,x2,y2,r:Single; var x3,y3,x4,y4:Single):Boolean; var l,dx,dy,i,ii,ij:Single; begin dx := x1 - x2; dy := y1 - y2; l := Sqrt(dx*dx + dy*dy); if l<=r then begin tangent_to_circle:=false; exit; end; i := r/l; ii := i*i; ij := i * Sqrt(1 - ii); x3 := x2 + dx*ii - dy*ij; y3 := y2 + dx*ij + dy*ii; x4 := x2 + dx*ii + dy*ij; y4 := y2 - dx*ij + dy*ii; tangent_to_circle:=true; end; 

Où (x1, y1) est le point d'observation, (x2, y2) est le centre du cercle, ® est son rayon, et (x3, y3) et (x4, y4) sont les points d'intersection des lignes et du cercle. La fonction ne renvoie true que lorsque l'observateur est en dehors du cercle.

Comme le processeur n'est pas très amical avec la trigonométrie, j'ai essayé de l'utiliser au minimum. S'appuyant en fait sur une règle simple (modèle approximatif), les experts vous expliqueront pourquoi.

(Mauvais) SIN, COS ..> '/', SQRT> 'DIV', 'MOD'> 'SHR', 'SHL'> '*'> ': =', '+', '-', 'AND ',' XOR '.. (Bon)

C’est un plaisir d’implémenter la partie graphique des primitives sur la toile, il existe de nombreuses bibliothèques et moteurs qui facilitent le travail. Lors du développement sur Delphi, j'ai dû utiliser la bibliothèque Agg2D, sur Lazarus il y a son port (6) , et sur celui-ci j'ai décidé de réaliser l'idée. En fait, le gain de la bibliothèque est qu'un canal alpha est ajouté aux couleurs RVB, et les primitives sont lissées, et en raison de l'accès direct aux pixels et à diverses astuces, le traitement est beaucoup plus rapide que le canevas.

Lors du dessin de l'ombre de la tuile, j'allais à l'origine remplir le secteur avec de l'ombre, mais l'image à l'intérieur de la tuile était à peine reconnaissable (le secteur en question sur la figure 3. est rempli de vert). Après avoir expérimenté différentes options, je me suis arrêté à sélectionner un secteur dans la zone d'ombre.

Pour dessiner le secteur, nous avons besoin d'un angle en radians, mais la trigonométrie ne pouvait toujours pas le faire. (arctan2 - fonction de bibliothèque du module mathématique)

 //     function alpha_angle(x1,y1,x2,y2:Single):Single; begin alpha_angle := arctan2(y1 - y2, x1 - x2); end; 

En fait, tout est prêt pour l'assemblage d'images. Nous prenons une carte de tuiles et sur une couche distincte, nous appliquons séquentiellement les ombres, une par une. Pour les arbres, les ombres sont plus sombres, pour les autres objets, les ombres sont plus transparentes.

image

L'image finie est appliquée sur la couche principale de carreaux. Un peu de design d'arrière-plan et choisissez des ensembles de tuiles plus génériques. En fait, il m'a fallu deux jours pour rechercher des tuiles appropriées, celles qui sont dans le domaine public ou de très mauvaise qualité ou coûtent cher. En conséquence, il a lui-même dessiné les arbres et emprunté d'autres éléments à l'utilisateur Joe Williamson (7) (excellent style).

image

Ce serait fini, mais il y avait du sédiment dans la performance. Avec le nombre d'objets, environ cinq cents rabattements commencent. Diverses méthodes d'optimisation ont été envisagées, et en se divisant en noyaux et en restreignant la zone de dessin à un certain rayon, en changeant la forme de l'ombre (à moins cher que les arcs), j'ai même pensé à transférer le calcul en vidéo.

En conséquence, je suis arrivé à la conclusion que la meilleure option serait de réduire l'échantillonnage de l'image servant de masque d'ombre. Car le nombre de calculs est considérablement réduit, ainsi que l'effet inattendu de pixellisation des contours d'ombres, ce qui donne un certain charme old-school.

image

J'ai tellement aimé l'effet que j'ai dû faire de la mise à l'échelle un processus dynamique, à travers un paramètre de multiplicité donné.

image

Il ne restait plus qu'à créer des murs opaques et à présenter le résultat à la communauté.

image

J'attends avec impatience de nouveaux jeux utilisant cet effet ou son développement.
Je vous remercie!

Démo où vous pouvez toucher les poignées (exe pour les fenêtres).

Partie 2 , partie 3

Références:
1) habr.com/post/16927/
2) en.wikipedia.org/wiki/Roguelike
3) habr.com/post/204782/
4) habr.com/post/305252/
5) habr.com/post/319530/
6) wiki.freepascal.org/BGRABitmap
7) twitter.com/joecreates

Source: https://habr.com/ru/post/fr430438/


All Articles