Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Maak een Plons Met Dynamische 2D Water Effecten

by
Difficulty:IntermediateLength:LongLanguages:

Dutch (Nederlands) translation by Adjatay Bashroh Aldad (you can also view the original English article)

Sploosh! In deze zelfstudie laat ik je zien hoe je eenvoudige wiskunde, natuurkunde en partikeleffecten kunt gebruiken om groot uitziende 2D-watergolven en -druppels te simuleren.



Opmerking: hoewel deze tutorial geschreven is met behulp van C en XNA, zou je in bijna elke game-ontwikkelomgeving dezelfde technieken en concepten moeten kunnen gebruiken.


Eindresultaat Voorbeeld

Als je XNA hebt, kun je de bronbestanden downloaden en de demo zelf samenstellen. Bekijk anders de demovideo hieronder:

Er zijn twee meestal onafhankelijke delen van de watersimulatie. Eerst, maken we de golven met behulp van een veermodel. Ten tweede zullen we deeltjeseffecten gebruiken om spatten toe te voegen.


De Golven Maken

Om de golven te maken, modelleren we het oppervlak van het water als een reeks verticale veren, zoals weergegeven in dit diagram:

Hierdoor kunnen de golven op en neer golven. We zullen dan waterdeeltjes trekken op hun naburige deeltjes om de golven te laten verspreiden.

Springs en Hooke's Law

Een groot voordeel van Springs is dat ze eenvoudig te simuleren zijn. Veren hebben een bepaalde natuurlijke lengte; als je een veer uitrekt of samendrukt, zal hij proberen terug te keren naar die natuurlijke lengte.

De kracht geleverd door een veer wordt gegeven door de Wet van Hooke:

\[
F = -kx
\]

F is de kracht die wordt geproduceerd door de veer, k is de veerconstante en x is de verplaatsing van de veer ten opzichte van zijn natuurlijke lengte. Het minteken geeft aan de kracht in de tegengestelde richting waarnaar de lente wordt verplaatst; Als u het voorjaar omlaag duwt, zal het duwen terug omhoog, en vice versa.

De veer constante, k, bepaalt de stijfheid van het voorjaar.

Om te simuleren springs, moeten we uitzoeken hoe te bewegen van deeltjes op basis van de wet van Hooke. Om dit te doen, moeten we een paar meer formules uit de natuurkunde. Ten eerste, de tweede wet van Newton van beweging:

\[
F = ma
\]

Hier, F is kracht, m is de massa en een versnelling. Dit betekent dat hoe sterker een kracht duwt op een object, en hoe lichter het object is, hoe meer het versnelt.

Het combineren van deze twee formules en herschikken geeft ons:

\[
a =-\frac{k}{m} x
\]

Dit geeft ons de versnelling voor onze deeltjes. We gaan ervan uit dat al onze deeltjes dezelfde massa hebben, dus we kunnen k/m combineren in een enkele constante.

Om de positie van versnelling te bepalen, moeten we numerieke integratie doen. We gaan de eenvoudigste vorm van numerieke integratie gebruiken - elk frame doen we eenvoudigweg het volgende:

Dit wordt de Euler methode genoemd. Het is niet het meest nauwkeurige type numerieke integratie, maar het is snel, eenvoudig en adequaat voor onze doeleinden.

Alles bij elkaar genomen, zullen onze wateroppervlakdeeltjes elk frame het volgende doen:

Hier is TargetHeight de natuurlijke positie van de bovenkant van de veer wanneer deze niet uitgerekt of samengedrukt is. U moet deze waarde instellen op de plaats waar u het wateroppervlak wilt hebben. Voor de demo, heb ik het halverwege het scherm ingesteld, op 240 pixels.

Spanning en Dempend

Ik zei eerder dat de veerconstante, k, de stijfheid van de veer regelt. U kunt deze waarde wijzigen van de eigenschappen van het water. Een lage veerconstante maakt de veren los. Dit betekent dat een kracht grote golven veroorzaakt die langzaam oscilleren. Omgekeerd, zal een hoge veerconstante de spanning in de veer verhogen. Krachten zullen kleine golven creëren die snel oscilleren. Een hoge veerconstante zorgt ervoor dat het water er meer uitziet als Jello.

Een woord van waarschuwing: stel de veer niet constant te hoog in. Zeer stijve veren hebben zeer sterke krachten die in een zeer korte tijd enorm veranderen. Dit speelt niet goed met numerieke integratie, die de veren simuleert als een reeks discrete sprongen op regelmatige tijdsintervallen. Een zeer stijve veer kan zelfs een oscillatieperiode hebben die korter is dan uw tijdstap. Erger nog, de Euler-integratiemethode heeft de neiging om energie te krijgen als de simulatie minder nauwkeurig wordt, waardoor stijve veren exploderen.

Er is een probleem met onze veer model tot nu toe. Zodra een veer begint te oscilleren, zal deze nooit stoppen. Om dit op te lossen, moeten we enige demping toepassen. Het idee is om een ​​kracht in de tegenovergestelde richting toe te passen die onze veer beweegt om hem te vertragen. Dit vereist een kleine aanpassing aan onze voorjaarsformule:

\[
a =-\frac{k}{m} x - dv
\]

Hier is v de snelheid en d is de dempings factor - nog een constante die je kunt aanpassen om het gevoel van het water aan te passen. Het moet vrij klein zijn als je wilt dat je golven oscilleren. De demo gebruikt een dempingsfactor van 0,025. Een hoge dempingsfactor maakt het water er dik uitzien als melasse, terwijl een lage waarde ervoor zorgt dat de golven gedurende lange tijd kunnen oscilleren.

De Golven Laten Propageren

Nu dat we een veer maken kunt, laten we ze te gebruiken om model water. Zoals in het eerste diagram wordt getoond, modelleren we het water met behulp van een reeks parallelle, verticale veren. Natuurlijk, als de veren allemaal onafhankelijk zijn, zullen de golven zich nooit verspreiden zoals echte golven doen.

Ik zal eerst de code laten zien en er dan overheen gaan:

Deze code wordt elk frame uit uw methode Update() genoemd. Hier, veren is een reeks van veren, aangelegd van links naar rechts. leftDeltas is een reeks drijvers die het hoogteverschil tussen elke veer en de linkerbuur opslaat. rightDeltas is het equivalent voor de juiste buren. We slaan al deze hoogteverschillen op in arrays omdat de laatste twee if statements de hoogten van de veren wijzigen. We moeten de hoogteverschillen meten voordat een van de hoogten wordt gewijzigd.

De code begint met het uitvoeren van Hooke's Law op elke veer zoals eerder beschreven. Vervolgens wordt gekeken naar het hoogteverschil tussen elke veer en zijn buren, en elke veer trekt de aangrenzende veren naar zich toe door de posities en snelheden van de buren te wijzigen. De buurtrekkingsstap wordt acht keer herhaald om de golven sneller te laten voortplanten.

Er is hier nog een meer tweakbare waarde genaamd Spread. Het bepaalt hoe snel de golven zich verspreiden. Het kan waarden tussen 0 en 0,5 aannemen, met grotere waarden waardoor de golven sneller worden verspreid.

Om de bewegingen van de golven te starten, gaan we een eenvoudige methode toevoegen, Splash() genaamd.

Elke keer dat u golven wilt maken, belt u Splash(). De index parameter bepaalt op welke veer de splash zou moeten ontstaan ​​en de parameter speed bepaalt hoe groot de golven zullen zijn.

Renderen

We zullen de XNA PrimitiveBatch klasse gebruiken van de XNA Primitives Sample. Met de klasse PrimitiveBatch kunnen we lijnen en driehoeken rechtstreeks met de GPU tekenen. Je gebruikt het als volgt:

Een ding om op te merken is dat u standaard de hoekpunten in de richting van de wijzers van de klok moet opgeven. Als je ze in een tegengestelde volgorde toevoegt, wordt de driehoek geselecteerd en zie je deze niet meer.

Het is niet nodig om een ​​veer te hebben voor elke pixel met breedte. In de demo gebruikte ik 201 veren verspreid over een raam met 800 pixels breed. Dat geeft precies 4 pixels tussen elke veer, met de eerste veer op 0 en de laatste op 800 pixels. Je kunt waarschijnlijk nog minder veren gebruiken en het water er nog steeds glad uit laten zien.

Wat we willen doen is dunne, hoge trapezoïden tekenen die zich van de onderkant van het scherm naar het wateroppervlak uitstrekken en de veren verbinden, zoals weergegeven in dit diagram:

Omdat grafische kaarten geen trapezoïden rechtstreeks tekenen, moeten we elke trapezium als twee driehoeken tekenen. Om het er iets leuker uit te laten zien, maken we het water ook donkerder naarmate het dieper wordt door de onderste hoekpunten donkerblauw in te kleuren. De GPU interpoleert automatisch kleuren tussen de hoekpunten.

Hier is het resultaat:


Spatten Maken

De golven zien er goed uit, maar ik zou graag een plons zien als de rots het water raakt. Effecten met deeltjes zijn hier perfect voor.

Effecten van Deeltjes

Een deeltjeseffect gebruikt een groot aantal kleine deeltjes om een ​​visueel effect te produceren. Ze worden soms gebruikt voor zaken als rook of vonken. We gaan deeltjes gebruiken voor de waterdruppels in de spatten.

Het eerste dat we nodig hebben is onze deeltjesklasse:

Deze klasse bevat alleen de eigenschappen die een deeltje kan hebben. Vervolgens maken we een lijst met deeltjes.

Voor elk frame, moeten we de deeltjes bijwerken en tekenen.

We werken de deeltjes bij om onder de zwaartekracht te vallen en de oriëntatie van het deeltje in te stellen zodat het overeenkomt met de richting waarin het gaat. We ontdoen zich dan van deeltjes die buiten het scherm of onder water zijn door alle deeltjes die we willen bewaren te kopiëren naar een nieuwe lijst en deze toe te wijzen aan deeltjes. Daarna tekenen we de deeltjes.

Hieronder is de textuur die ik voor de deeltjes heb gebruikt.

Als we nu een plons maken, maken we een hoop deeltjes.

U kunt deze methode aanroepen vanuit de Splash() methode die we gebruiken om golven te maken. De parametersnelheid is hoe snel de rots het water raakt. We zullen grotere spatten maken als de steen sneller beweegt.

GetRandomVector2(40) geeft een vector met een willekeurige richting en een willekeurige lengte tussen 0 en 40. We willen een beetje willekeur toevoegen aan de posities, zodat de deeltjes niet allemaal op één punt verschijnen. FromPolar() retourneert een Vector2 met een gegeven richting en lengte.

Hier is het resultaat:

Metaballs Gebruiken als Deeltjes

Onze spatten zien er redelijk uit, en sommige geweldige games, zoals World of Goo, hebben spatten met deeltjeseffect die veel op de onze lijken. Ik ga je echter een techniek laten zien om de spatten er vloeibaarder uit te laten zien. De techniek gebruikt metaballs, organisch uitziende blobs waarvan ik eerder een tutorial heb geschreven. Als u geïnteresseerd bent in de details over metaballs en hoe ze werken, leest u die zelfstudie. Als je gewoon wilt weten hoe je ze op onze spatten kunt toepassen, blijf dan lezen.

Metaballs zien er vloeibaar uit in de manier waarop ze samensmelten, waardoor ze een goede match zijn voor onze vloeibare spatten. Om de metaballs te maken, moeten we nieuwe klassenvariabelen toevoegen:

Die we zo initialiseren:

We trekken dan de metaballs:

Het metaball effect hangt af van het hebben van een deeltjestextuur die vervaagt naarmate je verder uit het centrum komt. Dit is wat ik heb gebruikt, ingesteld op een zwarte achtergrond om het zichtbaar te maken:

Hier is hoe het eruit ziet:

De waterdruppeltjes smelten nu samen wanneer ze dichtbij zijn. Ze smelten echter niet samen met het oppervlak van het water. We kunnen dit oplossen door een verloop toe te voegen aan het wateroppervlak waardoor het geleidelijk vervaagt en het weergeeft aan ons metaball renderdoel.

Voeg de volgende code toe aan de bovenstaande methode vóór de regel GraphicsDevice.SetRendertarget (null):

Nu zullen de deeltjes samensmelten met het wateroppervlak.

Het Afschuiningseffect Toevoegen

De waterdeeltjes zien er een beetje plat uit, en het zou leuk zijn om ze wat schaduw te geven. Idealiter, zou je dit in een arcering doen. Om deze handleiding eenvoudig te houden, gebruiken we echter een snelle en eenvoudige truc: we gaan de deeltjes eenvoudig drie keer tekenen met verschillende kleuren en verschuivingen, zoals geïllustreerd in het onderstaande schema.

Om dit te doen, willen we de metaball-deeltjes vastleggen in een nieuw renderdoel. Vervolgens tekenen we dat renderdoel één keer voor elke tint.

Verklaar eerst een nieuwe RenderTarget2D, net als bij de metaballs:

Vervolgens, in plaats van metaballsTarget rechtstreeks naar de backbuffer te tekenen, willen we het op particlesTarget tekenen. Ga hiervoor naar de methode waarbij we de metaballs tekenen en deze regels eenvoudig wijzigen:

... naar:

Gebruik vervolgens de volgende code om de deeltjes drie keer te tekenen met verschillende tinten en verschuivingen:


Conclusie

Dat is het voor standaard 2D water. Voor de demo heb ik een steen toegevoegd die je in het water kunt laten vallen. Ik teken het water met wat transparantie bovenop de rots om het er uit te laten zien alsof het onder water is, en laat het vertragen als het onder water staat vanwege de waterbestendigheid.

Om de demo een beetje leuker te laten lijken, ging ik naar opengameart.org en vond een afbeelding voor de achtergrond van rock en hemel. Je kunt de rots en de lucht vinden op http://opengameart.org/content/rocks en opengameart.org/content/sky-backdrop respectievelijk.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.