Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Зрабіце ўсплёск з дынамічнымі 2D-эфектамі вады

by
Difficulty:IntermediateLength:LongLanguages:

Belarusian (беларуская мова) translation by Jenyia (you can also view the original English article)

Sploosh! У гэтым уроку я пакажу вам, як вы можаце выкарыстоўваць простыя матэматычныя, фізічныя і эфекты часціц, каб імітаваць цудоўныя 2D хвалі і  кроплі вады.



Заўвага: Хоць гэты падручнік напісаны з выкарыстаннем C# і XNA, вы павінны выкарыстоўваць адны і тыя ж метады і канцэпцыі практычна ў любой гульнявой асяроддзі распрацоўкі.


Папярэдні прагляд вынікаў

Калі ў вас XNA, вы можаце загрузіць зыходныя файлы і скампіляваць дэма. У адваротным выпадку азнаёмцеся з дэма-відэа ніжэй:

У воднай сімуляцыі ёсць дзве ў асноўным незалежныя часткі. Па-першае, мы будзем выкарыстоўваць хвалі з выкарыстаннем спружыннай мадэлі. Па-другое, мы будзем выкарыстоўваць эфекты часціц для дадання воплескаў.


Стварэнне хваляў

Каб зрабіць хвалі, мы будзем мадэляваць паверхню вады як шэраг вертыкальных спружын, як паказана на гэтай дыяграме:

Гэта дазволіць хвалям падымацца і апускацца. Затым мы працягнем часціцы вады на суседнія часціцы, каб хвалі распаўсюдзіліся.

Спружыны і закон Гука

Адна з вялікіх асаблівасцяў спружын заключаецца ў тым, што іх лёгка імітаваць. Спружыны маюць пэўную натуральную даўжыню; калі вы расцягнецца або сціскаеце спружыну, ён паспрабуе вярнуцца да гэтай натуральнай даўжыні.

Сіла, якая забяспечваецца спружынай, дадзена Законам Гука:

\[
F = -kx
\]

F - сіла, якая ствараецца спружынай, k - пастаянная спружына, а x - зрушэнне спружын ад яе натуральнай даўжыні. Адмоўны знак паказвае на тое, што сіла знаходзіцца ў процілеглым кірунку, да якога спружына зрушаная; калі вы націснеце спружыну ўніз, яна будзе адціскацца, і наадварот.

Пастаянная спружына, k, вызначае жорсткасць спружыны.

Каб імітаваць спружыны, мы павінны высветліць, як перамяшчаць часціцы вакол па закону Гука. Для гэтага нам трэба яшчэ некалькі формул з фізікі. Па-першае, другі закон руху Ньютана:

\[
F = ma
\]

Тут F - сіла, m - маса, a - паскарэнне. Гэта азначае, што сіла мацней насоўваецца на аб'ект, і чым лягчэй аб'ект, тым больш ён паскараецца.

Аб'яднанне гэтых двух формул і пераўпарадвачэнне дае нам:

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

Гэта дае нам паскарэнне для нашых часціц. Будзем лічыць, што ўсе нашы часціцы будуць мець аднолькавую масу, таму мы можам аб'яднаць k/m ў адну канстанту.

Каб вызначыць становішча ад паскарэння, нам трэба правесці колькаснае інтэграванне. Мы збіраемся выкарыстоўваць найпростую форму колькаснага інтэгравання - з кожным кадрам мы проста робім наступнае:

Гэта называецца метадам Эйлера. Гэта не самы дакладны тып лікавай інтэграцыі, але ён хуткі, просты і адэкватны для нашых мэтаў.

Злучаючы ўсё гэта разам, нашы часціцы на паверхні вады будуць рабіць наступныя кадры:

Тут TargetHeight з'яўляецца натуральным становішчам верхняй частцы спружыны, калі ён не расцягваецца і не сціскаецца. Вы павінны ўсталяваць гэта значэнне там, дзе вы хочаце, каб была паверхня вады. Вы павінны ўсталяваць гэта значэнне там, дзе вы хочаце, каб была паверхня вады.

Нацяжэнне і Ўвільгатненне

Я згадаў раней, што пастаянная спружына k рэгулюе жорсткасць спружыны. Вы можаце адрэгуляваць гэтае значэнне, каб змяніць ўласцівасці вады. Нізкая пастаянная спружыны прымусіць спружыну вызваліцца. Гэта азначае, што сіла прымусіць вялікія хвалі вагацца павольна. І наадварот, высокая пастаянная спружына павялічыць нацяжэнне спружыны. Сілы створаць невялікія хвалі, якія хутка вагаюцца. Высокая пастаянная спружына прымусіць ваду пахадзіць на змешванне Джелло.

Папярэджанне: не ўстанаўлівайце занадта высокую пастаянную спружыну. Вельмі жорсткія спружыны ўжываюць вельмі моцныя сілы, якія моцна змяняюцца за вельмі малы прамежак часу. Гэта не вельмі добра спалучаецца з лікавым інтэграваннем, якое імітуе спружыны як серыю дыскрэтных скокаў з рэгулярнымі часовымі інтэрваламі. Вельмі жорсткая спружына можа нават мець перыяд ваганняў, які карацей вашага часовага кроку. Горш таго, метад інтэграцыі Эйлера мае тэндэнцыю да павелічэння энергіі, паколькі імітацыя становіцца менш дакладнай, што прыводзіць да выбуху жорсткіх спружын.

Да гэтага часу праблема з нашай спружыннай мадэллю. Як толькі спружына пачне вагацца, яна ніколі не спыніць. Каб вырашыць гэтую праблему, мы павінны ўжыць некаторы ўвільгатненне. Ідэя складаецца ў тым, каб прымяніць сілу ў процілеглым кірунку, каб наша спружына рухалася, каб запаволіць яе. Гэта патрабуе невялікі карэкціроўкі нашай вясновай формулы:

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

Тут v - хуткасць, d - каэфіцыент згасання - іншая канстанта, якую вы можаце наладзіць, каб наладзіць адчуванне вады. Гэта павінна быць даволі мала, калі вы хочаце, каб вашы хвалі вагаліся. Дэма выкарыстоўвае каэфіцыент згасання 0,025. Высокі каэфіцыент згасання прымусіць ваду выглядаць тоўстай, як меласы, у той час як нізкае значэнне дазволіць ваганняў хваляў на працягу доўгага часу.

Прасоўванне хваляў

Цяпер, калі мы можам зрабіць спружыну, давайце выкарыстоўваць іх для мадэлявання вады. Як паказана на першай дыяграме, мы мадэлюем ваду, выкарыстоўваючы шэраг паралельных вертыкальных спружын. Вядома, калі спружыны ўсе незалежныя, хвалі ніколі не будуць распаўсюджвацца, як гэта робяць сапраўдныя хвалі.

Спачатку я пакажу код, а потым перайду да яго:

Гэты код будзе выклікацца кожны кадр з вашага метаду Update(). Тут springs ўяўляюць сабой масіў спружын, размешчаных злева направа. leftDeltas - гэта масіў паплаўкоў, які захоўвае розніцу ў вышыні паміж кожнай спружынай і яе левым суседам. rightDeltas з'яўляецца эквівалентам для правых суседзяў. Мы захоўваем ўсе гэтыя рознасці вышынь у масівах, таму што апошнія два аператара if змяняюць вышыню спружын. Мы павінны вымяраць розніцу вышынь да таго, як якая-небудзь з вышынь будзе змененая.

Код пачынаецца з запуску закона Гука па кожнай спружыне, як апісана вышэй. Затым ён глядзіць на розніцу вышынь паміж кожнай спружынай і яе суседзямі, і кожная спружына цягне свае суседнія спружыны да сябе, змяняючы становішча і хуткасць суседзяў. Суседні-працягвальны крок паўтараецца восем разоў, каб хвалі распаўсюджваліся хутчэй.

Існуе адно больш наладжвальных значэнне, тут называецца Spread. Ён кантралюе хуткасць распаўсюджвання хваль. Яно можа прымаць значэнні ад 0 да 0,5, пры гэтым вялікія значэння павялічваюць хуткасць распаўсюджвання хваль.

Каб пачаць рух хваляў, мы дададзім просты метад Splash().

Кожны раз, калі вы хочаце зрабіць хвалі, выклічце Splash(). Параметр index вызначае, на якой спружыне павінен з'явіцца ўсплёск, а параметр seed вызначае, наколькі вялікія будуць хвалі.

Рэндэрынг

Мы будзем выкарыстоўваць клас XNA PrimitiveBatch з XNA PrimitivesSample. Клас PrimitiveBatch дапамагае нам маляваць лініі і трыкутнікі непасрэдна з графічным працэсарам. Вы выкарыстоўваеце яго так:

Варта адзначыць, што па змаўчанні вы павінны ўказваць вяршыні трохвугольніка па гадзінны стрэлцы. Калі вы дададзіце іх па гадзіннікавай стрэлцы, трохкутнік будзе адбракаваны, і вы яго не ўбачыце.

Няма неабходнасці мець спружыну для кожнага пікселя шырыні. У дэма я выкарыстаў 201 крыніца, які распаўсюджваецца па акна шырынёй 800 пк. Гэта дае роўна 4 пк паміж кожнай спружынай, прычым першая спружына роўная 0, а апошняя - 800 пк. Вы, верагодна, маглі б выкарыстоўваць яшчэ менш спружын і ўсё яшчэ мець гладкую ваду.

Тое, што мы хочам зрабіць, гэта намаляваць тонкія высокія трапецыі, якія распасціраюцца ад ніжняй частцы экрана да паверхні вады і злучаюць спружыны, як паказана на гэтай дыяграме:

Паколькі графічныя карты ня малююць трапецоиды наўпрост, мы павінны намаляваць кожную трапецыю ў выглядзе двух трыкутнікаў. Каб гэта выглядала трохі лепш, мы таксама зробім ваду цямней, калі яна стане глыбей, афарбоўваючы ніжнія вяршыні сінім колерам. GPU аўтаматычна будзе интерполировать колеру паміж вяршынямі.

Вось вынік:


Стварэнне пырскі

Хвалі выглядаюць нядрэнна, але я хацеў бы ўбачыць ўсплёск, калі камень патрапіць у ваду. Эфекты часціц ідэальна падыходзяць для гэтага.

Частковыя эфекты

Эфект часціц выкарыстоўвае вялікая колькасць дробных часціц для атрымання некаторага візуальнага эфекту. Яны часам выкарыстоўваюцца для такіх рэчаў, як дым або іскры. Мы збіраемся выкарыстоўваць часціцы для кропель вады ў пырсках.

Першае, што нам трэба, гэта клас часціц:

Гэты клас проста захоўвае ўласцівасці, якія можа мець часціца. Затым мы створым спіс часціц.

Кожны кадр мы павінны абнаўляць і маляваць часціцы.

Мы абнаўляем часціцу каб яна падала пад дзеяннем сілы цяжару і ўсталявала арыентацыю часціцы ў адпаведнасці з напрамкам, з якім яна збіраецца. Мы тады пазбавімся ад любых часціц, якія знаходзяцца па-за экранаі або пад вадой, скапіяваўшы ўсе часціцы, якія мы хочам захаваць у новы спіс і прысвоіўшы яго часціцам. Далей мы малюем часціцы.

Затым мы малюем часціцы.

Цяпер, калі мы ствараем ўсплёск, мы ствараем кучу часціц.

Вы можаце выклікаць гэты метад з метаду Splash(), які мы выкарыстоўваем для стварэння хваль. Хуткасць параметру - гэта хуткасць, з якой камень трапляе ў ваду. Мы будзем рабіць вялікія воплескі, калі скала будзе рухацца хутчэй.

GetRandomVector2(40) вяртае вектар са выпадковым кірункам і выпадковую даўжыню паміж 0 і 40. Мы хочам дадаць трохі выпадковасці да пазіцый, каб часціцы не ўсе адлюстроўваліся ў адным пункце. FromPolar() вяртае Vector2 з зададзеным кірункам і даўжынёй.

Вось вынік:

Выкарыстанне метабаллов ў якасці часціц

Нашы пырскі выглядаюць даволі прыстойна, а некаторыя выдатныя гульні, такія як World of Goo, маюць воплескі эфектаў часціц, якія выглядаюць так жа, як нашы. Аднак я пакажу вам тэхніку, каб пырскі выглядалі больш вадкімі. У тэхніцы выкарыстоўваюцца метабалы, арганічныя бурбалкі, пра якія я ўжо пісаў падручнік. Калі вас цікавяць падрабязнасці аб метабаллах і як яны працуюць, прачытайце гэты падручнік. Калі вы проста хочаце ведаць, як прымяняць іх да нашых усплёскаў, працягвайце чытаць.

Метабаллы выглядаюць падобнымі на вадкасць, так як яны зліваюцца адзін з адным, што робіць іх прыдатнымі для нашых вадкіх пырскаў. Каб зрабіць метабаллы, нам трэба будзе дадаць новыя зменныя класа:

Што мы ініцыялізуем так:

Затым мы малюем метабаллы:

Эфект метабалла залежыць ад наяўнасці тэкстуры часціц, якая знікае, калі вы рухаецеся далей ад цэнтра. Вось што я выкарыстаў, устанавіў на чорным фоне, каб зрабіць яго бачным:

Вось як гэта выглядае:

Зараз кроплі вады зліваюцца, калі яны блізкія. Аднак яны не зліваюцца з паверхняй вады. Мы можам выправіць гэта, дадаўшы градыент да паверхні вады, што робіць яго паступова знікаць і ператварае яго ў нашу мэта рэндэрынгу метабалла.

Дадайце наступны код у метад вышэй да лініі GraphicsDevice.SetRendertarget (null):

Цяпер часціцы будуць злівацца з паверхняй вады

Даданне эфекту скосу

Часціцы вады выглядаюць трохі плоскімі, і было б нядрэнна даць ім некаторы зацяненне. У ідэале вы б зрабілі гэта ў шэйдараў. Аднак, дзеля таго, каб гэты падручнік быў просты, мы збіраемся выкарыстоўваць хуткі і просты трук: мы проста збіраемся маляваць часціцы тры разы з рознымі адценнямі і зрушэннямі, як паказана на дыяграме ніжэй.

Для гэтага мы хочам захапіць часціцы метабалла ў новай мэты рэндэрынгу. Затым мы намалюем гэтую мэту рэндэрынгу адзін раз для кожнага адцення.

Па-першае, абвясціце новы RenderTarget2D гэтак жа, як і для метабаков:

Затым, замест таго, каб маляваць metaballsTarget непасрэдна ў буферны буфер, мы хочам намаляваць яго на particleTarget. Для гэтага перайдзіце да метаду, дзе мы малюем метабаллы і проста мяняем гэтыя радкі:

... каб:

Затым выкарыстоўвайце наступны код, каб маляваць часціцы тры разы з рознымі адценнямі і зрушэннямі:


Выснова

Гэта для базавай 2D вады. Для дэманстрацыі я дадаў камень, які вы можаце скінуць у ваду.  Я малюю ваду з некаторай празрыстасцю на вяршыні скалы, каб яна выглядала так, быццам яна пад вадой, і запавольвае яе, калі яна пад вадой з-за супраціву вады.

Каб зрабіць дэманстрацыйны прыклад трохі прыемней, я пайшоў на opengameart.org і знайшоў малюнак для скалы і фону неба. Вы можаце знайсці скалу і неба па адрасе http://opengameart.org/content/rocks і opengameart.org/content/sky-backdrop адпаведна.

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.