Comment mettre en œuvre des zones de bord doux avec des particules

13

Mon jeu est créé à l'aide de Phaser, mais la question elle-même est indépendante du moteur.

Dans mon jeu, j'ai plusieurs environnements, essentiellement des zones polygonales dans lesquelles les personnages joueurs peuvent se déplacer et être affectés par. Par exemple, glace, feu, poison, etc. 'L'élément graphique de ces zones est la zone de polygone remplie de couleur elle-même et les particules du type approprié (dans cet exemple, les éclats de glace). Voici comment j'implémente actuellement ceci - avec un masque polygonal couvrant un carreau avec le motif de particules:

entrez la description de l'image ici

Le bord dur semble mauvais. Je voudrais m'améliorer en faisant deux choses: 1. Rendre la zone de remplissage du polygone pour avoir un bord doux et se fondre dans l'arrière-plan. 2. Demandez à certains fragments de sortir de la zone du polygone, afin qu'ils ne soient pas coupés au milieu et que la zone n'ait pas de ligne droite

par exemple (maquette):

entrez la description de l'image ici

Je pense que 1 peut être atteint en brouillant le polygone, mais je ne sais pas comment procéder avec 2.

Comment feriez-vous pour mettre en œuvre cela?

OpherV
la source
2
Ça a l'air génial. Puis-je avoir un lien vers votre jeu s'il vous plaît? :)
ashes999
@GameAlchemist Voici l'image en mosaïque i.imgur.com/y54CeQ9.png
OpherV
@ ashes999 C'est toujours un travail en cours. Je posterai certainement un lien ici une fois que je l'
aurai
Notez que c'est un PNG transparent avec des objets blancs. Si vous la visualisez sur un fond blanc (comme c'est souvent le cas lors de l'ouverture d'une image dans un navigateur), vous ne verrez rien
OpherV
@OpherV ce serait génial. Modifiez simplement votre question et publiez un lien - c'est probablement la façon la plus
pertinente

Réponses:

2

1.Si vous voulez quelque chose qui est proche de votre maquette, j'utiliserais des particules (il n'est pas nécessaire que ce soit un système de particules entièrement soufflé).

Rendez vos particules sous forme de polygone sur une texture de rendu. Assurez-vous d'utiliser un mélange additif sur les particules. Les particules à l'intérieur du polygone se fondront doucement les unes dans les autres tandis que les particules à l'extérieur donneront le bord doux que vous souhaitez. (Un exemple de l'effet peut être regardé dans cette vidéo youtube: Vidéo sur les particules additives Rendez maintenant la texture de rendu sur votre écran principal et vous avez terminé. La texture de rendu est nécessaire pour que les particules ne se mélangent pas avec votre arrière-plan.

Vous pouvez essayer de mettre les triangles directement sur la texture des particules et voir comment cela fonctionne. Sinon, rendez-les au-dessus de votre "soupe de particules" en tant que couche séparée.

Création d'une maquette rapide dans un jsfiddle mis à jour qui ressemble à ceci Démo Vous pouvez trouver la démo mise à jour ici

2.Chaque particule a une vitesse et une origine. Lorsque votre joueur touche le polygone, vous modifiez la vitesse de chaque particule proportionnellement à la vitesse du joueur. Plus une particule est éloignée de votre joueur, moins elle est affectée par la vitesse du joueur.

La formule pour calculer une vitesse de particules serait quelque chose comme ceci:

//player.velocity and particle.velocity are vectors 
//k is a factor to enhance or weaken the influence of players velocity
var distanceToPlayer = (player.position - particle.position).length();
particle.velocity = particle.velocity + ((k * player.velocity) + particle.velocity) * (1/distanceToPlayer);

Pour calculer la position de la particule, vous mettez ceci dans votre méthode de mise à jour:

var speedY = -(springConstant * (particle.position.y - particle.origin.y)) - (dampingFactor * particle.velocity.y);
var speedX = -(springConstant * (particle.position.x - particle.origin.x)) - (dampingFactor * particle.velocity.x);

particle.position.y = particle.position.y + speedY;
particle.position.x = particle.position.x + speedX;

particle.velocity.x = particle.velocity.x + speedX;
particle.velocity.y = particle.velocity.y + speedY;

Cela devrait vous donner un "fluide" où chaque particule oscille autour de son origine lorsque le joueur remue le fluide. Le springConstant change la distance à laquelle une particule s'éloigne de son origine et le facteur d'amortissement à quelle vitesse la particule s'arrête. Vous devrez peut-être modifier le code car il s'agit de la version modifiée d'une simulation 1d que j'utilise dans mon jeu.

Maintenant avec une démo: Démo Ajustez simplement les 3 constantes en haut jusqu'à ce que le fluide se comporte comme vous le souhaitez.

zilluss
la source
C'est une idée vraiment intéressante pour résoudre # 1! Je l'aime. Comment proposeriez-vous la mise en œuvre du mouvement / espacement du triangle?
OpherV
1
J'ai modifié le message d'origine pour répondre à la question n ° 2.
zilluss
ajouté une petite démo de l'effet de particules. Je pense que vous pourriez obtenir l'effet souhaité avec un petit ajustement.
zilluss
J'ai fini par utiliser votre solution, c'est la plus proche de l'effet que je cherchais à atteindre. Merci! Une question cependant - comment pourrais-je restreindre l'élasticité dans vos exemples, afin que de très légers mouvements ne fassent pas sauter les particules sur de si grandes distances?
OpherV
Vous pouvez jouer avec l'amortisseurFactor et le springConstant. Un amortissement élevé ramènera les particules plus rapidement au repos. Une constante de ressort inférieure abaisse la vitesse des particules. Malheureusement, les deux valeurs permettent à la soupe de particules de se sentir plus visqueuse. Donc, à la place, lorsque votre joueur touche la particule, vous pouvez restreindre la vitesse maximale que le joueur ajoute à la particule, comme ceci: particule.velocity.x = clamp (maxVelocity, -maxVelocity, particule.velocity.x + ((playerInfluenceFactor * deltaVelocityX ) + particule.vitesse.x) * (1 / distanceToPlayer)); pour la pince, voir: stackoverflow.com/a/11409944
zilluss
4

Mes réflexions sur ces deux points:

  1. Vous pouvez utiliser un flou de shader, mais cela va coûter très cher. Au lieu de cela, je dessinerais une bordure supplémentaire de triangles qui passeraient de translucide au centre à transparent sur les bords, pour simuler le "flou". Je l'ai fait dans un de mes jeux et cela fonctionne plutôt bien. Voici deux captures d'écran d'un booster arc-en-ciel dans mon jeu.

    entrez la description de l'image ici entrez la description de l'image ici

    La bordure extérieure a un dégradé. Dans ma situation, la bordure ne commence pas à la même opacité que la partie intérieure, mais si vous définissez ces opacités égales, vous aurez un joli fondu.

  2. Je programmerais un système de particules et ferais suivre les particules au polygone. Ce faisant, vous n'avez pas à vous soucier de ce qui se passera sur les bords. La dynamique de votre système de particules garantira que les particules sont à l'intérieur du polygone et réparties uniformément. Vous pouvez essayer de faire en sorte que les particules les plus proches se repoussent, mais faites-le avec beaucoup de «masse» pour avoir une inertie et un aspect lisse. Pour rendre cette chose rapide, il existe quelques possibilités, mais le gros problème sera la complexité temporelle du mécanisme de poussée mutuelle. Si vous faites pousser chaque particule sur toutes les autres, vous aurez O (n ^ 2), ce qui n'est pas bon, si vous avez par exemple 100 particules dans votre système. Une bonne lecture sur la façon dont vous pouvez optimiser ceci est cette présentation de PixelJunk:http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    Une approche plus simple serait de connecter chaque particule à trois ou quatre autres particules lors de la construction du système de particules. Désormais, chaque particule n'aura plus qu'à pousser les quatre autres particules auxquelles elle est connectée. Cependant, cette approche rend les turbulences dans votre système de particules impossibles. Mais cela ne semble pas être un problème, car votre situation actuelle utilise une texture statique. Cette approche sera O (n) ce qui est génial.

Martijn Courteaux
la source
Merci! 1. J'ai du mal à visualiser cela. Pouvez-vous publier une maquette de son apparence \ dans votre jeu? 2. Intéressant! lira à ce sujet
OpherV
Merci pour les images. Je peux voir comment cela fonctionnerait dans une forme de tube ou de ligne, mais comment cela fonctionnera-t-il avec un polygone? Les gradients des triangles projetés de chaque côté ne seront-ils pas bien alignés ...?
OpherV
Faites-les bien s'ajuster. Telle est l'idée. Cela implique des points d'intersection mathématiques et informatiques, etc. Vous pouvez également subdiviser la bordure et la lisser. Des tonnes de possibilités.
Martijn Courteaux
3

L'idée que j'ai eue en lisant votre message était celle-ci:
• construire un ensemble de tuiles que vous utiliserez pour vos zones.
• rendre le polygone de surface sur une petite toile temporaire à la résolution des tuiles (ex: si les tuiles sont 16X16, rendre à une résolution (16X, 16X) inférieure).
• utilisez ce canevas temporaire pour décider de rendre ou non les tuiles sur le canevas principal:
si un point est défini sur le canevas basse résolution, dessinez un carreau «aléatoire» sur le canevas principal. si un point n'est qu'un voisin d'un point de consigne, dessinez une tuile 'aléatoire' avec une opacité inférieure (pour faire la transition) sur la toile principale.

J'avais peur qu'une baisse de la résolution ne crée un effet de bloc, mais même avec des tuiles 20X20, cela semble assez bon:

entrez la description de l'image ici

Les étapes pour cela sont: prenez votre polygone:
entrez la description de l'image ici

Dessinez le polygone à la résolution de votre tuile: entrez la description de l'image ici(!! oui c'est la chose rouge du centre commercial).

Ensuite, utilisez l'imageData du canevas basse résolution pour décider de dessiner une tuile ou une note.
Si un pixel est défini sur le canevas basse résolution, cela signifie que nous devons dessiner la tuile: choisissez un index de tuile «aléatoire» pour choisir la tuile à dessiner. Cet index aléatoire doit toujours être le même pour une zone / tuile donnée.
Si un point est vide mais à côté d'un point rempli, dessinez également une tuile, mais avec une demi-opacité.

entrez la description de l'image ici

Alors dessinons les tuiles:

entrez la description de l'image ici

Pour le polygone, je dessine simplement plusieurs fois le polygone, en le réduisant et en augmentant l'opacité à chaque dessin (on pourrait également utiliser le globalCompositeOperation 'plus léger').

entrez la description de l'image ici

Une fois que vous avez tout ajouté, cela donne:

entrez la description de l'image ici

le violon est là:

http://jsfiddle.net/gamealchemist/T7b4Y/

faites-moi savoir si cela aide.

GameAlchemist
la source
Merci d'avoir élaboré votre solution et fourni le code! Que voulez-vous dire par "Ensuite, utilisez les données image du canevas basse résolution pour décider de dessiner une vignette ou une note". Comment utilisez-vous les données de petite image pour décider où \ comment dessiner sur la grande image? Et en utilisant cette méthode, comment puis-je éviter le chevauchement des triangles afin d'obtenir un espacement similaire à ma maquette?
OpherV
Je veux dire que c'est un test booléen complet: dois-je remplir cette tuile? , vrai ou faux, est donné par le test du test basse résolution sur imageData [(x + y * largeur) * 4]! = 0, c'est-à-dire == 'ai-je dessiné quelque chose sur la toile de résolution inférieure à cet endroit de tuiles? '. Ensuite, si oui, j'utilise une formule élaborée remplie de nombres premiers (getRandomNumber) pour passer de (x, y) à un index de tuile `` aléatoire '' qui fournira toujours le même numéro pour une zone donnée + (x, y). Je ne vois pas comment les choses pourraient se chevaucher si vous définissez correctement votre polygone, donc je n'ai pas votre deuxième question.
GameAlchemist
1

Juste une idée:

Dans votre tuile, les "pièces" ont une largeur maximale d'environ 80 pixels. Je dirais, en faisant 2 zones. Vous dessinez votre polygone d'origine et vous en faites une maquette à environ 80 pixels de chaque bord. Vous dessinez ensuite vos tuiles dans le plus grand polygone.

Ensuite, toutes les "pièces" qui ont un pixel à l'extérieur du polygone intérieur, et aucune intersection avec le polygone intérieur, vous pouvez les inonder et les remplir de transparence.

C'est un niveau très élevé, mais j'ai pensé que je le partagerais avec vous. Il y a beaucoup de détails à déterminer ici.

Une image brute pour démontrer:

entrez la description de l'image ici

Si le polygone noir intérieur était l'original, vous effaceriez tous les polygones avec un point rouge.

user46560
la source
Comment pourriez-vous vérifier l'intersection des pièces intégrées dans l'image de la tuile avec le polygone intérieur?
OpherV
@OpherV Uhmm, vous pouvez déterminer si le point X est dans un polygone non? Vous pouvez parcourir tous les pixels du polygone extérieur et, pour chaque pixel blanc, vérifier tous les pixels et voir s'ils se trouvent dans l'intérieur / l'extérieur. Cela ne semble pas particulièrement efficace, mais une fois que vous avez quelque chose, vous pouvez penser à des moyens d'optimiser?
user46560
C'est un post-traitement effectué sur le CPU. À peine optimisable sur lui-même. Votre idée pourrait bien fonctionner si le polygone intérieur et l'extérieur sont reliés par une bande triangulaire. L'OP pourrait ajouter des informations d'attribut de sommet et marquer chaque sommet comme à l'intérieur ou à l'extérieur. Ensuite, dans le vertex shader, l'opacité / alpha peut être interpolée linéairement d'une valeur moins transparente à une valeur opaque complète.
teodron
@teodron C'est le point que j'ai essayé de faire dans la réponse. C'est une idée de haut niveau et je ne suis pas vraiment un développeur de jeux. Je viens d'avoir une idée.
user46560
@ user46560 oui, mais de cette façon, vous n'avez pas du tout à calculer les pixels dans cette bande inter-polygones .. ni sur le GPU, ni sur le CPU. Comme vous n'êtes pas habitué aux méthodes de développement de jeux comme vous le dites, vous méritez un +1 pour votre idée :).
teodron