Je suis sûr que Stage3D n'est pas étranger à la plupart des lecteurs. c'est la nouvelle API qui permet aux programmeurs AS3 d'accéder au GPU. Cependant, coder en opcode dans Stage3D n'est peut-être pas le choix préféré de tous. Il est donc heureux qu'il existe un raccourci: Starling, une bibliothèque développée pour encapsuler cette programmation de bas niveau pour la rendre beaucoup plus facile. Et avec Starling vient son extension des effets de particules. Dans ce tutoriel, nous allons examiner les systèmes de particules de ce framework et voir ses applications appliquées à un jeu de shoot-'em-up.
Ignorez cette étape si vous utilisez FlashDevelop depuis un certain temps. Pour les débutants, voici comment installer un paquet de bibliothèque - dans ce cas, Starling et son extension de particule. Notez que ces deux éléments ne sont pas fournis dans un seul paquet, nous devrons donc les télécharger séparément..
Tout d’abord, téléchargez le framework Starling et son extension de particule à partir de leurs référentiels. Décompressez lors du téléchargement réussi. Analyser le premier répertoire décompressé pour src
dossier et collez la bibliothèque d'infrastructure Starling, mise en surbrillance dans l'image ci-dessous, dans le dossier source de votre projet.
Analysez le second dossier pour l’extension de particule et combinez-les. Vous pouvez tirer le dossier en surbrillance ci-dessous dans la Étourneau
dossier. L'image ci-dessous est le résultat final auquel vous devriez arriver.
Pour plus d'informations sur FlashDevelop et l'utilisation de bibliothèques externes, consultez les didacticiels suivants:
Si vous ne connaissez pas encore Starling et son extension de particule, j'encourage vivement la visite des tutoriels vidéo de Lee Brimelow sur Starling et les effets de particules, ainsi que du tutoriel de Matthew Chung sur la gestion des états d'animation avec Starling..
Nous allons simplement passer en revue les bases en deux étapes ici. Si vous connaissez déjà Starling et son extension de particules, n'hésitez pas à passer à l'étape 4.
Vous pouvez voir sur la deuxième image de l'étape précédente (la partie inférieure) que deux classes sont en cours de création: Main.as
et Test.as
. Le premier sert de lanceur pour ce dernier. Ainsi, la plupart de notre code Starling vit dans Test.as
. J'ai souligné le code important dans Main.as
ici:
fonction privée init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // point d'entrée var myStarling: Starling = new Starling (Testing, stage); myStarling.simulateMultitouch = true; myStarling.start (); // initiez Starling sur la scène // autorisez les événements souris / toucher dans Starling // tournez la clé et démarrez le moteur!
… et Test.as
devrait ressembler à ceci:
public class Testing étend Sprite fonction publique Testing () addEventListener (Event.ADDED_TO_STAGE, init); fonction privée init (e: Event): void removeEventListener (Event.ADDED_TO_STAGE, init); // le code va ici. stage.color = 0; // change la couleur de la scène en noir // Dessine un petit quad sur la scène, // juste pour m'assurer que tout est en place // Notez que le coin supérieur gauche de l'image-objet est aligné au milieu de la scène var q: Quad = new Quad (30, 30); addChild (q); q.color = 0xEEEEEE; q.x = stage.stageWidth >> 1; q.y = stage.stageHeight >> 1;
Et si tout est configuré correctement, vous devriez arriver au résultat comme indiqué ci-dessous. Rien beaucoup, juste un sprite sur la scène.
Remarque: Test.as
étend Sprite de Starling.display.Sprite
, ne pas flash.display.Sprite
. Les classes ont le même nom, mais ne sont pas les mêmes.
L'extension de particules de Starling contient trois classes importantes. Leurs fonctionnalités sont tabulées ci-dessous.
Nom de la classe | La fonctionnalité |
Particle.as | Une seule particule avec des attributs uniques. |
ParticleSystem.as | Contrôle le flux de particules: génération, animation et recyclage. |
ParticleDesignerPS.as | Une extension de ParticleSystem.as pour permettre une manipulation facile du système de particules. |
Nous allons créer une instance de ParticleDesignerPS.as
. Cela nécessite la saisie des arguments suivants dans le constructeur de la classe:
Pas de problème, onebyonedesign.com vous aidera avec cela. Visitez leur page de concepteur de particules et modifiez toutes ces valeurs d’initiation selon vos envies. Exportez ensuite toutes les données au format ZIP. Ce fichier ZIP contiendra le fichier XML et l'image de l'effet de particules que vous venez de concevoir via leur page Web.!
Décompressez et récupérez tous ces éléments dans votre dossier source dans FlashDevelop. Voir les éléments en surbrillance dans l'image ci-dessous.
Générez des instructions d’import pour importer ces deux éléments dans votre Essai
classe. Vous devrez également réécrire le init
méthode en Essai
. Ils sont tous ci-dessous.
[Embed (source = "particle.pex", mimeType = "application / octet-stream")] private var InitValues: Class [Embed (source = "texture.png")] private var Sample: Class
fonction privée init (e: Event): void removeEventListener (Event.ADDED_TO_STAGE, init); // le code va ici. stage.color = 0; // active la couleur de la scène en noir var flow1: ParticleDesignerPS = new ParticleDesignerPS (XML (new InitValues ()), Texture.fromBitmap (new Sample ())); addChild (flow1); flow1.emitterX = stage.stageWidth >> 1; flow1.emitterY = stage.stageHeight >> 1; flow1.start (); Starling.juggler.add (flow1);
Voici le résultat auquel vous devriez arriver. Plutôt simple, juste?
Notre prochaine étape consiste à activer l'interaction avec le système de particules (ce petit feu) au moment de l'exécution. Nous allons utiliser la souris pour contrôler les propriétés du feu. Cependant, avant cela, j'aimerais vous écarter un peu pour vous expliquer le concept des systèmes de particules..
Les particules ne sont que des images-objets émises par une coordonnée. Après la naissance, ils s'animent selon un certain schéma. Ce motif peut être unique pour chaque particule ou commun à toutes les particules. Mais rassurez-vous, leurs propriétés physiques changeront avec le temps. Par exemple:
En outre, leur vie sur scène est déterminée à la naissance. Si chaque particule est autorisée à vivre indéfiniment sur scène, il y aura surpopulation et les performances de l'application en souffriront du fait de la gestion de nombreux actifs graphiques. À un moment donné, la particule meurt sans être pellée. Elle est recyclée à la place, car elle est déplacée vers une coordonnée de naissance et assume le rôle d’une nouvelle particule. C'est une nouvelle particule car un nouvel ensemble de propriétés sera défini pour elle avant que son animation ne démarre et qu'un autre cycle continue.
(C'est mise en commun d'objets, et vous pouvez voir comment l’appliquer à vos propres projets Flash non Starling ici.)
Ok, alors comment cela se rapporte-t-il à notre feu? Nous pouvons utiliser des fonctions d'accélération pour animer les propriétés de cet incendie au fil du temps. Dans le cadre de Starling, ParticleDesignerPS
se positionne à la fin de cette hiérarchie:
ParticleDesignerPS
> Système de particules
> DisplayObject
> EventDispatcher
> Objet
Pour trouver un équilibre, nous allons simplement suivre les propriétés héritées de Système de particules
. Jetons un coup d'oeil à ceux-ci la prochaine étape…
Système de particules
et ParticleDesignerPS
Voici les propriétés de Système de particules
.
Propriété | La description |
capacité | Le maximum de particules que le système peut transporter à tout moment. Augmente par paliers de 500 lorsque le nombre de particules dépasse sa capacité actuelle. Lecture seulement. |
numParticules | Nombre de particules dans le système à un moment donné. Lecture seulement. |
emissionRate | Nombre de particules générées à partir de la naissance coordonnées chaque seconde. |
emitterX , émérite | Point de contrôle du conteneur dans lequel toutes les particules vivent. |
| Définition Context3DBlendFactor pour la source et la destination. La destination fait référence à la couleur de pixel du dernier rendu et la source à la nouvelle couleur de pixel pour dessiner sur la destination. |
texture | Image actuelle échantillonnée en tant que texture de particules. Lecture seulement. |
Ceux de ParticleDesignerPS
sont tabulées dans le tableau suivant. La plupart de ces propriétés peuvent être ajustées par leurs états de début et de fin. Par exemple, toutes les particules générées commenceront avec une taille de 1,0 et se termineront à 0,1. Cependant, le flux de particules sera ennuyeux si toutes les particules sont initiées et terminées à des états similaires ParticleDesignerPS
provisions pour variance de la valeur initiale, et parfois variance sur valeur de terminaison ainsi.
En citant leur exemple, si nous donnons une variance de 0,2 sur la taille initiale de la particule, les particules consécutives nées ou recyclées dans le système commenceront leur taille entre 0,8 et 1,2 et se termineront à 0,1..
Propriété | La description |
emitterXVariance , émetteurYVariance | Variation de la coordonnée de naissance. |
startSize , startSizeVariance | Taille initiale et variance |
endSize , endSizeVariance | Taille et variance des terminaisons |
emitAngle , emitAngleVariance | La direction initiale et la variance des particules |
la vitesse , speedVariance | Vitesse et variance initiales des particules |
gravityX | Accélération en abscisse sur la vitesse initiale de toutes les particules |
gravité | Accélération selon l'axe des y sur la vitesse initiale de toutes les particules |
accélération tangentielle , tangentialAccelerationVariation | Taux de rotation sur la vitesse de la particule et variance |
Il existe deux types de flux de particules prévus dans ParticleDesignerPS
: gravité et radial. Le tableau ci-dessus répertorie les propriétés que vous pouvez modifier si vous utilisez un écoulement par gravité. Pour la gravité, la coordonnée de naissance des particules est située à emitterX
et émérite
. Pour les radiales, la coordonnée de naissance pour les particules est située à un point emitterX
et émérite
, et ils bougent vers il. Le tableau ci-dessous montre les propriétés de l'écoulement radial.
Propriété | La description |
maxRadius , maxRadiusVariance | Rayon maximal à partir du centre et variance |
minradius | Rayon minimum du centre |
rotation par seconde , rotationParSecondVariance | Taux de rotation sur la vitesse de la particule |
startColor , startColorVariance | Couleur initiale et variance |
endColor , endColorVariance | Couleur de terminaison et variance |
Merci d'avoir organisé ce petit détour. Passons maintenant à du code ActionScript. dans le init
méthode, nous allons ajouter un auditeur sur la scène pour les événements tactiles.
stage.addEventListener (TouchEvent.TOUCH, piste);
Et l'auditeur comme ci-dessous.
piste de fonction privée (e: TouchEvent): void var touch: touch = = e.getTouch (stage); // mappage sur la grille de coordonnées de la scène // lorsque l'utilisateur appuie sur la souris et se déplace si (touch.phase == TouchPhase.MOVED) // calcule l'angle permettant de diriger le flux de particules vers var distX: Number = touch.globalX - flow1.emitterX; var distY: Number = touch.globalY - flow1.emitterY; angle var: Nombre = Math.atan2 (distY, distX); t = new Tween (flux1, 1.5, Transitions.EASE_OUT_BACK); t.animate ("emitAngle", angle); Starling.juggler.add (t);
Afin de réaliser l'animation, un Tween
l'instance est définie. Sa manipulation est similaire à celle du populaire Tween
moteurs à bien des égards. Ensuite, nous l’ajoutons au jongleur de l’instance actuelle de Starling. Cet objet jongleur aidera à mettre à jour progressivement la Tween
exemple au fil du temps.
Le résultat est ci-dessous. Cliquez et faites glisser votre souris autour de la scène.
Configurons notre vaisseau maintenant et mettons une trace dessus. Les actifs proviennent de opengameart.org et je les ai inclus dans le package de téléchargement. Consultez ce site pour d'autres jeux artistiques gratuits.
Nous allons recommencer avec une autre classe, TestingShip.as
. D'abord, importez l'image du vaisseau spatial "boss1.png".
[Embed (source = "boss1.png")] private var Navire: Classe
… Suivi d'un petit paramétrage pour l'initialiser dans le init
méthode:
// configure l'apparence graphique var shipBMP: Bitmap = new Ship () en tant que Bitmap; // importer une ressource dans un fichier bmp var shipTEX: Texture = Texture.fromBitmap (shipBMP); // exemple bmp comme texture pour image var shipIMG: Image = new Image (shipTEX); // image créée avec texture // configuration de l'orientation et de la position du navire shipIMG.rotation - = Math.PI * 0.5; // réoriente l'image shipIMG.x - = shipIMG.width >> 1; // parce que l'origine de l'image se trouve dans le coin supérieur gauche, shipIMG.y + = shipIMG.height >> 1; // on repositionne l'image theShip = new Sprite (); // et le mettre dans un sprite. Maintenant, le point d'enregistrement est centré. theShip.addChild (shipIMG); // image-objet placée sur la scène addChildAt (theShip, 0); // propriétés de navigation du navire loc = new Vector2D (stage.stageWidth >> 1, stage.stageHeight >> 1); lof = nouveau Vector2D (0, 10); updateShip ();
Mettre à jour sa position et son orientation en fonction de loc
(emplacement) et lof
(ligne de mire).
fonction privée updateShip (): void theShip.x = loc.x; theShip.y = loc.y; theShip.rotation = lof.getAngle ();
Encore une fois, cliquez et glissez dans la scène pour voir l'effet:
D'accord, l'échappement du vaisseau est au-dessus du vaisseau lui-même, et le vaisseau spatial ne répond pas à l'événement de la souris. Nous allons résoudre ce problème maintenant. Juste compenser le emitterX
et émérite
du flux de particules à une certaine distance du vaisseau spatial et mettre à jour la rotation du vaisseau spatial en utilisant lof
.
(Notez que lof
est mis à jour sur les événements de souris. Vous verrez le script à l'étape suivante.)
fonction privée updateShip (): void theShip.x = loc.x; theShip.y = loc.y; theShip.rotation = lof.getAngle (); // mettre à jour le chemin des particules offset = new Vector2D (60, 0); offset.setAngle (lof.getAngle ()); flow1.emitterX = loc.x - offset.x; flow1.emitterY = loc.y - offset.y;
Essayons de programmer la navigation du navire maintenant, lors de l'envoi d'un événement de souris. J'ai seulement commenté les lignes importantes:
piste de fonction privée (e: TouchEvent): void var touch: touch = = e.getTouch (stage); if (touch.phase == TouchPhase.MOVED) var distX: Number = touch.globalX - flow1.emitterX; var distY: Number = touch.globalY - flow1.emitterY; angle = Math.atan2 (distY, distX); t = new Tween (flux1, 1.5, Transitions.EASE_OUT_BACK); t.animate ("emitAngle", angle + Math.PI); t2 = new Tween (theShip, 1.5, Transitions.EASE_OUT); t2.moveTo (touch.globalX, touch.globalY); // déplace le navire t2.onUpdate = refresh // appelle cette fonction chaque fois que le moteur d'interpolation tourne Starling.juggler.add (t); Starling.juggler.add (t2); // ajouter au jongleur fonction privée refresh (): void loc.x = theShip.x; // actualise la localisation loc.y = theShip.y; lof.setAngle (angle); // actualise l'orientation updateShip (); // mettre à jour
Et voici un spectacle du résultat final. Faites glisser la souris autour de la scène et le vaisseau spatial y ira.
Réglons notre échappement. Lorsque le navire sera en mouvement, les gaz d'échappement souffleront certainement plus fort, n'est-ce pas? Nous pouvons intensifier la emissionRate
et la vitesse
lors du déplacement du navire, et descendez emissionRate
quand c'est arrêté. Voici l'événement, mis en évidence:
t2 = new Tween (theShip, 1.5, Transitions.EASE_OUT); t2.moveTo (touch.globalX, touch.globalY); // déplace le navire t2.onUpdate = refresh // appelle cette fonction chaque fois que le moteur d'interpolation s'exécute t2.onStart = beginState // lorsque le navire commence à se déplacer t2.onComplete = endState // lorsque l'animation du navire s'arrête
Et voici les appels de fonction sur ces événements.
fonction privée beginState (): void flow1.emissionRate = 250 flow1.speed = 100; fonction privée endState (): void flow1.emissionRate = 50 flow1.speed = 10;
Cliquez et faites glisser à nouveau, et faites attention à la longueur de l'échappement.
Les particules peuvent également exprimer la vitesse à laquelle le navire se déplace par rapport à son environnement. Découvrez la sortie ci-dessous. Cliquez et faites glisser votre souris autour. Observez la vitesse à laquelle les particules environnantes se déplacent. Ils augmentent lorsque vous interagissez avec le vaisseau et ralentissent lorsque vous arrêtez l'interaction. Ils orientent également leur rotation en conséquence.
La configuration de cet effet est relativement facile sur l’application présentée par onebyonedesign.com. Cependant, nous devrons coder du code ActionScript afin de le modifier au moment de l'exécution, ce qui nécessitera les étapes suivantes..
L'initiation des particules suit un format similaire à celui de l'exemple précédent. Vous pouvez choisir d’ajuster votre effet avec l’application de onebyonedesign.com et importer dans votre stade. Je code juste directement dans ActionScript pour plus de facilité.
envr = new ParticleDesignerPS (XML (new InitValues ()), Texture.fromBitmap (new Sample ())); addChildAt (envr, 0); envr.blendFactorSource = Context3DBlendFactor.ONE envr.blendFactorDestination = Context3DBlendFactor.ONE envr.speed = 10; envr.speedVariance = 20; envr.startSize = 15; envr.startSizeVariance = 0; envr.endSize = 20; envr.endSizeVariance = 20 envr.lifespan = 5.0; envr.lifespanVariance = 4,0; envr.emissionRate = 10 envr.start (); Starling.juggler.add (envr);
Nous devrons également placer l'émetteur de particules un peu en avant du navire..
envrLoc = nouveau Vector2D (100, 0); envrLoc.setAngle (angle);
Et mettre à jour ce vecteur au moment de l'exécution.
// met à jour l'environnement envr.gravityX = -40 * lof.x; // la particule accélère dans la direction opposée envr.gravityY = -40 * lof.y; // du vecteur ligne de visée envr.emitterX = loc.x + envrLoc.x; envr.emitterY = loc.y + envrLoc.y;
Vous voyez, le emitterXVariance
et émetteurYVariance
manipuler les axes séparément. Cela signifie que si nous faisons pivoter le vaisseau spatial, nous avons besoin d’un moyen de déterminer la longueur de la propagation le long de ces deux axes..
Maintenant, vérifiez le vecteur pour la ligne de mire. C'est toujours perpendiculaire à celui de la ligne d'étalement (la mince ligne sombre). Nous pouvons redimensionner ce vecteur en conséquence et balancer ses x et y avec ceux de la variance de l'émetteur au point de départ. Vérifiez la démo ci-dessous. Cliquez et faites glisser votre souris. Vous verrez les particules s'écouler plus vivement.
Enfin, augmentez l'ampleur de la dispersion et placez-la un peu plus loin devant le vaisseau pour que les joueurs ne voient pas leur point d'émission..
envrLoc = new Vector2D (200, 0); envrLoc.setAngle (angle);
// met à jour la propagation spread = envrLoc.clone (); spread.scale (0,5); envr.emitterXVariance = spread.y; envr.emitterYVariance = spread.x;
Enfin, alors que le navire accélère, augmentons l’ampleur de gravityX
et gravité
, plus l'échappement, en conséquence.
if (touch.phase == TouchPhase.MOVED) var distX: Number = touch.globalX - flow1.emitterX; var distY: Number = touch.globalY - flow1.emitterY; angle = Math.atan2 (distY, distX); // animer l'échappement t = new Tween (flow1, 1.5, Transitions.EASE_OUT_BACK); t.animate ("emitAngle", angle + Math.PI); Starling.juggler.add (t); // contrôle le débit d'échappement1.speed = 350; flow1.endSize = 70; // oriente l'angle du navire et de la parallaxe lof.setAngle (angle); lof.setMagnitude (10); // ajuste l'amplitude de l'accélération envrLoc.setAngle (angle); if (touch.phase == TouchPhase.ENDED) // contrôle le débit d'échappement1.speed = 100; flow1.endSize = 10; lof.setMagnitude (5); // ajuste l'amplitude de l'accélération
Au fur et à mesure que vous avancez dans le jeu, vous subirez des coups et subirez des dégâts. Au fur et à mesure que les dommages deviennent graves, votre navire va brûler Un tel effet peut être généré ici; nous pouvons utiliser le emissionXVariance
et émissionYVariance
définir la zone de brûlure. Je les ai surlignés dans le code ci-dessous.
envr = new ParticleDesignerPS (XML (new InitValues ()), Texture.fromBitmap (new Sample ())); addChildAt (envr, 2); envr.blendFactorSource = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA envr.blendFactorDestination = Context3DBlendFactor.ONE; envr.emitterXVariance = theShip.width >> 2; envr.emitterYVariance = theShip.height >> 2; envr.emitAngle = 0; envr.emitAngleVariance = Math.PI; envr.speed = 0; envr.startSize = 40; envr.startSizeVariance = 0; envr.endSize = 10; envr.endSizeVariance = 0 envr.lifespan = 5.0; envr.lifespanVariance = 3,0; envr.emissionRate = 10; envr.start (); Starling.juggler.add (envr);
La gravité des dommages est indiquée par la zone et l'intensité de la brûlure. Augmenter et diminuer emissionRate
simuler cela. J'ai ajouté des commandes sur le clavier "A" et "S" pour émuler cette.
fonction privée controlBurn (e: KeyboardEvent): void if (e.keyCode == Keyboard.A) if (envr.emissionRate < 150) envr.emissionRate += 10; if (envr.lifespan < 8) envr.lifespan += 0.5; if (e.keyCode == Keyboard.S) if(envr.emissionRate > 10) envr.emissionRate - = 10; si (durée de vie env> 5) envr durée de vie - = 0,5;
Notez que si vous augmentez la durée de vie des particules, le feu semble brûler plus intensément. Eh bien, il faut du temps pour interpoler les particules de leur taille initiale à leur taille finale. Par conséquent, si vous augmentez la durée de vie, il est plus long de passer du plus grand début à la plus petite. Comme plus de grosses particules restent au même endroit plus longtemps, elles se mélangent pour donner l'impression d'un feu plus intense..
Appuyez sur la touche "A" pour voir le feu brûler plus intensément et la touche "S" pour l'éteindre légèrement. La couleur de l'échappement a été changée, pour le différencier de la combustion:
Tous les bons jeux doivent se terminer à un moment donné. Peu importe qui est éliminé, une bonne explosion pour une finition ne doit pas être manquée. Alors, qu'en est-il d'un nuage de champignon nucléaire? Cliquez sur la démo ci-dessous pour en voir un.
Maintenant, codons.
Ce flux de particules est un peu différent de ceux que nous avons vus. Auparavant, nous utilisions le type de flux de particules 0 (gravité) et le type 1 (radial). Les particules se déplacent réellement vers le milieu à une vitesse constante.
J'ai réglé la variance d'angle d'émission à son maximum afin que vous puissiez voir toutes les particules générées former un cercle. Puis, en animant le rayon maximal et le rayon minimal dans lesquels ces particules devraient vivre dans le temps, en utilisant Tween
, nous obtenons ce résultat.
explosion = new ParticleDesignerPS (XML (new InitValues ()), Texture.fromBitmap (new Sample ())); addChild (explosion); explosion.emitterX = stage.stageWidth >> 1; explosion.emitterY = stage.stageHeight >> 1; explosion.emitterType = 1; explosion.emitAngle = 0; explosion.emitAngleVariance = Math.PI; explosion.maxRadius = 10; explosion.maxRadiusVariance = 0; explosion.minRadius = 0;
Voici le code pour effectuer l'animation.
piste de fonction privée (e: TouchEvent): void var touch: touch = = e.getTouch (stage); if (touch.phase == TouchPhase.BEGAN) explosion.emitterX = touch.globalX; explosion.emitterY = touch.globalY; explosion.start (); t = nouveau Tween (explosion, 1.0, Transitions.EASE_IN); t.animate ("maxRadius", 150); t.animate ("minRadius", 130); t.onStart = geler t.onComplete = reset; Starling.juggler.add (t); fonction privée freeze (): void stage.removeEventListener (TouchEvent.TOUCH, piste); fonction privée reset (): void stage.addEventListener (TouchEvent.TOUCH, piste); explosion.stop (); explosion.maxRadius = 10; explosion.minRadius = 0;
Donc, cela a été un long tutoriel. Faisons un petit récapitulatif ici. Nous avons traversé:
Nous avons couvert un peu ici. Cependant, un aspect important que je n’ai pas encore traversé est de Système de particules
. Cela vous donnera vraiment le pouvoir de coder vos propres traînées de particules au lieu de compter sur ParticleDesignerPS
. Je vais devoir reporter ceci à un autre tutoriel.
Merci de votre lecture et à bientôt dans le prochain tutoriel. Ne laissez pas de commentaires sur les erreurs et l'utilisation de ce moteur de particules dans votre projet si vous choisissez de l'adopter.