Puis-je obtenir un effet de torche (zone plus claire autour d'une source de lumière) dans un jeu 2D?

16

Je pense m'écrire un simple jeu 2D. Il ne brillera pas avec des graphismes ou un gameplay parfaits au début, mais je considérerais cela comme ma première étape dans le développement de jeux PC. Imaginez donc un jeu 2D simple basé sur des sprites (comme Heroes IV ou Startcraft BroodWar).

Je veux que le gameplay supporte jour / nuit avec les changements d'éclairage correspondants et en même temps, ce sera une folie de devoir créer des sprites pour chaque nuance d'éclairage. J'ai donc décidé que l'ajout d'un calque semi-transparent au-dessus d'autres objets serait suffisant.

Le problème avec cette solution est que si j'ai un objet source de lumière dans le jeu (comme le héros portant une torche ou un bâtiment en feu), il doit y avoir une zone plus claire autour, non? Puisque je mets ma couche semi-transparente sur tout, comment proposeriez-vous pour obtenir l'effet visuel torchligt que je veux? Peut-être redessiner ce calque en ajoutant des «espaces» ou des zones de couleurs différentes en fonction de l'effet d'éclairage?

Ivaylo Slavov
la source
2
Le masque peut être le chemin à parcourir
Gustavo Maciel
5
"Torchlight" dans le titre peut être déroutant en raison du jeu nommé Torchlight.
Tetrad
4
@Tetrad devrait être ok tant qu'il n'est pas capitalisé. Quant à moi, Torchlight ne m'est venu à l'esprit que lorsque vous avez lu votre commentaire.
célèbregarkin
Néanmoins, j'ai suggéré une modification pour rendre le titre plus précis.
célèbregarkin
2
doublon possible de Comment l'éclairage 2D est-il implémenté?
bummzack

Réponses:

12

Je ne sais pas dans quoi vous programmez, mais voici comment je l'ai géré dans XNA:

  1. Lors de l'appel de dessin, un List<Light>objet est créé / effacé.
  2. Pendant la boucle de dessin des tuiles, chaque tuile est vérifiée pour voir si elle a des lumières associées. Si c'est le cas, les Lightobjets sont ajoutés au List<Light>.
  3. Les tuiles sont dessinées seules RenderTarget2D.
  4. Après la boucle de tuiles, la liste des Lights est itérée et dessinée par eux-mêmes en RenderTarget2Dutilisant une texture que j'ai faite qui ressemble à ceci:
    Texture claire(Remarque: j'ai utilisé les valeurs R, G et B ici, mais vous devriez probablement utiliser le canal alpha dans votre texture réelle.)
  5. En utilisant un shader personnalisé, je rend la surface de la tuile à l'écran et je passe la surface d'éclairage en tant que paramètre qui est échantillonné pour la valeur "d'obscurité" à chaque pixel.


Maintenant, il y a quelques choses à noter:

Concernant le point 4:

J'ai en fait deux shaders personnalisés, un pour dessiner les lumières sur la cible de rendu d'éclairage (étape 4) et un autre pour dessiner la cible de rendu des tuiles sur l'écran à l'aide de la cible de rendu d'éclairage (étape 5).
Le shader utilisé au point 4 me permet d'ajouter (ce que j'appelle) une valeur de "luminosité". Cette valeur est floatmultipliée par chaque pixel de la texture avant d'être ajoutée à la cible de rendu afin que je puisse essentiellement rendre les lumières plus claires ou plus sombres.
À ce stade, je prends également en compte la valeur "d'échelle" de la lumière, ce qui signifie que je peux avoir des lumières grandes ou petites en utilisant une seule texture.

Concernant le point 5:

Considérez la cible de rendu d'éclairage comme ayant essentiellement une valeur pour chaque pixel de 0 (noir) à 1 (blanc). Le shader multiplie essentiellement cette valeur par rapport aux valeurs RVB d'un pixel de la cible de rendu de tuile pour créer l'image dessinée finale.

J'ai également un peu plus de code ici où je passe (au shader) une valeur à utiliser comme couleur de superposition jour / nuit. Il est également multiplié par les valeurs RVB et inclus dans les calculs de cible de rendu d'éclairage.


Maintenant, cela ne vous permettra pas de faire des choses comme bloquer la lumière autour des objets et ainsi de suite, mais, au moins pour mes besoins, c'est simple et fonctionne bien.

J'ai écrit des articles de blog plus détaillés ici et ici qui peuvent vous aider. Je n'ai pas le temps pour le moment, mais si vous voulez, je peux aller plus en détail ici sur gamedev.

Oh, et voici un coup d'oeil dans mon éditeur de carte:entrez la description de l'image ici

Richard Marskell - Drackir
la source
Générer et effacer une liste chaque trame peut ne pas être trop coûteuse?
Gustavo Maciel
@Gtoknu ne fait aucune différence notable dans mon jeu. La liste contient simplement des références à des objets qui existent déjà en mémoire, ce n'est donc pas comme si chaque lumière était recréée ou quoi que ce soit, juste une liste.
Richard Marskell - Drackir
vous avez peut-être raison, pas totalement, mais vous l'êtes. Bien sûr, vous ne créez pas d'objets complets, mais vous ajoutez des pointeurs vers des références, toujours à faible utilisation, mais toujours consommatrices. Vous vous débrouillez dans le bon sens, mais je pense qu'il serait peut-être préférable de mettre la liste en dehors de la méthode de tirage, car la logique dans la mise à jour est beaucoup plus rapide que dans le tirage
Gustavo Maciel
@Gtoknu Bien sûr, vous pouvez déclarer la liste où vous voulez, mais le fait est que les lumières sont associées aux tuiles. La Drawméthode des tuiles est l'endroit où vous découvrez si une tuile a des lumières ou non. Je ne passe pas en revue toutes les tuiles dessinées dans la Updateméthode, donc j'ajouterais des frais supplémentaires pour cela. De plus, XNA essaie de garantir qu'il Updatesera appelé 60 fois par seconde afin qu'il puisse sacrifier les Drawappels pour cela, ce qui signifie que ce code serait en fait appelé moins souvent.
Richard Marskell - Drackir
Cela dit, c'est un point discutable car j'ai finalement déplacé les lumières dans leurs propres listes basées sur le partitionnement spatial et j'ai simplement dessiné toutes les lumières dans des sections qui coupent l'écran. Je n'en ai pas parlé dans mon article par manque de temps, mais c'est mentionné dans le deuxième article de blog que j'ai lié.
Richard Marskell - Drackir
9

Normalement, l'éclairage dans les jeux 2D se fait en ayant une carte normale pour tous vos sprites, puis calculez les effets d'éclairage 3D sur vos sprites 2D. Ceci est appelé vaguement "2.5D". Je ne recommanderais cependant pas de le faire dans votre premier jeu car c'est complexe.

Voici une superbe vidéo de quelqu'un qui a fait cela dans XNA: http://www.youtube.com/watch?v=-Q6ISVaM5Ww

Cela dit, il existe probablement des moyens de tricher et d'obtenir un système de pseudo-éclairage qui pourrait fonctionner avec diverses hypothèses.

John McDonald
la source
Vous avez déjà vu cette vidéo auparavant, +1 pour avoir mentionné une technique aussi incroyable.
Gustavo Maciel
Merci pour les conseils et le lien vidéo. En effet, une carte semble être une solution. J'essaierais moi-même d'utiliser la carte sur ma couche supérieure pour créer un «espace» ou pour modifier l'effet qu'elle a sur les objets sous-jacents.
Ivaylo Slavov
5

Il est difficile de suggérer une approche si vous n'êtes pas complètement précis sur l'effet que vous essayez d'obtenir. Des détails tels que si les lumières doivent être obstruées par l'environnement ou non, quel est le point de vue de votre jeu, dans quelle mesure la lumière doit-elle interagir avec l'environnement, etc.

Je laisserai tomber mes deux cents cependant. Voyez si ce tutoriel de Catalin Zima intitulé Dynamic 2D Shadows correspond à votre facture. Comme vous pouvez le voir, la lumière a un rayon et ne traverse pas d'obstacles. Vous pouvez animer un peu le rayon et la couleur pour la rapprocher d'une véritable torche.

entrez la description de l'image ici

Dans ce cas, la lumière agit comme une sorte de superposition au-dessus de votre scène, mais n'interagit pas avec elle dans la même mesure que dans l'exemple de John, bien qu'elle prenne en compte les obstacles.

Éditer

Catalin renvoie à un autre article qu'il a utilisé comme référence, mais le lien est rompu. Voici un lien mis à jour .

David Gouveia
la source
Merci, je pense que ce n'est pas l'effet que je recherche, mais encore merci pour le partage :)
Ivaylo Slavov