Hərtərəfli Alov Təlimi (Və ya Çırpınmaqla Oyunlar etmək)

giriş

Hər kəsə salam! Mən Luanam və sizi bu ilk hərtərəfli Alov təliminə salamlayıram.

Flame, kətan əsaslı bir oyun yaratmaq üçün bir neçə modul təmin edən minimalist bir Flutter oyun motorudur.

Bu təlimatda qutuların düşdüyü çox sadə bir oyun yaradacağıq və məqsəd onları ekranın altına çatmadan məhv etməkdir.

Oyun belə görünəcək

Bu APK-nı quraşdıraraq və ya Play Store-dan quraşdıraraq nə etdiyimizi görmək üçün oyuna özünüz baxa bilərsiniz.

Beləliklə, çərçivə tərəfindən verilən bütün funksiyaları əhatə edə bilərik və ən əsas əməliyyatların necə göstəriləcəyini göstərə bilərik: göstərmə, spritlər, səs, mətn, animasiya və s.

Niyə bu oyunu seçdik? Çərçivəni araşdırmaq üçün çox sadə, lakin tamamlanmaqdan başqa, bunu etmək üçün resurslarımızın olması yaxşı bir amildir!

Bu oyun üçün aşağıdakı mənbələrdən istifadə edəcəyik: bir qutu sprite, bir partlayış sprite (animasiya ilə), bir partlayış səsi, bir miss səs (qutunun vurulmaması halında), fon musiqisi və hesabı göstərmək üçün gözəl şrift.

İnternetdə ticari olaraq mövcud olan yaxşı mənbələri tapmaq çətindir, amma bu əla veb saytında hər şeyi (şrift xaricində) tapdıq. Həqiqətən möhtəşəmdirlər, tamamilə tövsiyə olunur.

Sprite Sheets hazırda dəstəklənmədiyi üçün əvvəlcə bütün mənbələr uyğun formata çevrilməlidir. Bütün səsi MP3-ə çevirməliyik (OGG də dəstəklənir; WAV deyil). Bundan sonra, burada ehtiyac duyduğunuz bütün qaynaqlar ilə bir paket yükləyə bilərsiniz.

Burada izah edilən hər şeyin GitHub-da tam işləyən bir tam versiya kimi tutulduğunu da qeyd etmək lazımdır. Şübhə olduqda hər zaman bir nəzər yetirə bilərsiniz. Nümunə məhz bu addımların ardınca qurulmuşdur və tez-tez verilənləri anlıq görüntü kimi istifadə edir. Dərs müddətində anbarı sözügedən səviyyəyə çatdıracaq xüsusi öhdəlikləri əlaqələndirəcəyəm. Beləliklə, yoxlama nöqtələri yarada və aydın olmayan bir şey görmək üçün köhnə kodda axtarış apara bilərsiniz.

Son bir şey; Tam Alov sənədlərinə burada baxmaq olar. Hər hansı bir sualınız, təklifiniz və ya səhviniz varsa, xahiş edirəm mənimlə əlaqə saxlayın.

Çırpınma və dart quraşdırmalısınız. Sizə uyğun gəlirsə, IntelliJ IDEA-dan da istifadə edə bilərsiniz. Kodunuzu yazmağa başlamaq üçün çox yaxşı bir yerdir. Bu şeyləri quraşdırmaq üçün bu kimi müxtəlif dərsliklərə baxa bilərsiniz.

Əsaslar

Beləliklə, hələlik hər şeyin hazır olduğunu düşünürəm. Sadəcə çalışdırın və açın!

Etməli olduğunuz ilk şey alovdan asılılıq əlavə etməkdir. Pubspec.yaml dosyanıza gedin və asılılıq açar siyahılarının alovlandığından əmin olun:

Burada ən son 0.5.0 versiyasını istifadə edirik, ancaq mövcud olarsa yenisini seçə bilərsiniz.

İndi main.dart dosyanızda artıq çox şey var: saxlanılması lazım olan "əsas" metod; və runApp metoduna növbəti zəng. Bu metod tətbiq ekranları yaratmaq üçün istifadə olunan widget və digər Flutter komponentlərindən istifadə edir. Oyun hazırladığımız üçün hər şeyi kətan üzərinə çəkəcəyik və bu komponentlərdən istifadə etməyəcəyik. Buna görə hamısını soyun.

Əsas metodumuz artıq boşdur və iki şey əlavə edəcəyik; Əvvəlcə bəzi konfiqurasiya:

Flame.dart idxalı yalnız bir neçə digər faydalı sinfi ehtiva edən statik Alov sinfinə giriş imkanı verir. Bundan sonra daha çoxunu istifadə edəcəyik. Hal-hazırda bu alov sinifində iki üsul çağırırıq.

Son əmr özünü izah edir və səsyazma plaginindən qeydlərin bir hissəsini deaktiv edir. Qısa müddətdə oyuna səs əlavə edəcəyik. Bu işə yaramırsa, səhvləri düzəltmək üçün bu barədə şərh verməlisiniz. Ancaq bunu nə vaxtsa edəcəyik.

Birinci sətir daha mürəkkəbdir. Əsasən, runApp metodundan istifadə etmədiyimiz üçün Flutter-in bəzi vacib xüsusiyyətləri yoxdur. EnableEvents üçün edilən bu zəng, widget istifadə etmədən hər hansı bir tətbiq üçün tələb olunan problemi atlamağınıza imkan verir.

Nəhayət oyunumuza başlamalıyıq. Bunu etmək üçün idxal siyahısına başqa bir sinif, oyun sinfi əlavə edirik. Bu sinif bir oyun yaratmaq üçün lazım olan soyutlamanı təmin edir: oyun dövrü. Hər oyunun əsasını tətbiq etməlisiniz deyə alt siniflərə ayrılmalıdır: uyğun olduğu zaman çağırılan və son yeniləmədən bəri keçən vaxtı alan bir yeniləmə metodu və bunun necə olduğunu bilməli bir göstərmə metodu. çəkən oyunun cari vəziyyətidir. Döngünün daxili işlərini Oyun sinfi həll etməlidir (əlbətdə baxa bilərsiniz, çox sadədir) və etməyiniz lazım olan başlanğıcın başlanğıcıdır.

Yoxlama nöqtəsi: 599f809

Göstərmə hazırda heç bir hərəkət etmir. Beləliklə, işə başladığınız zaman işləməlidir, ancaq qara bir ekran alırsınız. Şirin! Beləliklə, widget və s. Olmayan bir işləyən tətbiqimiz və tətbiqimizi çəkməyə başlamaq üçün boş bir kətan var.

Formaları göstərin

Bəs necə çəkirsən? Fəaliyyətdə görmək üçün sadə bir düzbucaqlı çəkək. Göstərmə metodunuza aşağıdakıları əlavə edin:

Gördüyünüz kimi, burada ekran mövqelərinə əsasən düzbucaqlı tərif edirik. Aşağıdakı şəkil qaydaların necə hizalandığını göstərir. Əsasən mənşə yuxarı sol küncdədir və ox sağa və aşağıya qalxır.

Rəsm üsullarının çoxunun Paint istifadə etdiyini də unutmayın. Bir rəng yalnız bir rəng deyil, bir deqradasiya və ya başqa bir toxuma ola bilər. Tipik olaraq, ya düz bir rəng istəyəcəksiniz, ya da birbaşa bir spritə gedəcəksiniz. Beləliklə, rəngdəki rəngi Rəng nümunəsinə qoyaq.

Rəng tək bir ARGB rəngini ifadə edir. Bunu asan oxumaq üçün onaltılı skriptlə yaza biləcəyiniz bir tam ədədi ilə yaradırsınız. A formatındadır (alfa, şəffaflıq, ümumiyyətlə 0xFF) və sonra bu sırada R, G və B üçün iki rəqəm var.

Adı çəkilən rənglər kolleksiyası da var; bununla birlikdə maddi paketdədir. Material paketindən təsadüfən başqa bir şey istifadə etməmək üçün yalnız rənglər modulunu idxal etdiyinizdən əmin olun.

Yəni əla, indi bir meydanımız var!

Yoxlama nöqtəsi: 4eff3bf

Hökmdarların necə işlədiyini də bilirik, ancaq ekran ölçülərini bilmirik! Bu məlumat olmadan digər üç küncdə bir şey necə çəkirik? Qorxmayın, çünki Alovun ekranın həqiqi ölçüsünü əldə etmək üsulu var (buna görə sənədləşdirilmiş bir problem olduğu üçün).

Əsasən asenkron metod

JavaScript-də olduğu kimi, gözlənilən açar sözün yalnız asinxron bir funksiyada istifadə edilə biləcəyini unutmayın. Buna görə əsas asenkronizasiyanı etdiyinizə əmin olun (çırpınmanın heç bir əhəmiyyəti yoxdur).

Növbəti yoxlama məntəqəsi ölçüləri əsas metodda bir dəfə alır və oyun sinifimizdə saxlayır, çünki onlara dəfələrlə ehtiyacımız olacaq.

Yoxlama nöqtəsi: a1f9df3

Sprites göstərin

Nəhayət, ekranda istədiyimiz şəkli çəkə bilərik. Ancaq biz sprites istəyirik! Növbəti yoxlama məntəqəsi müvafiq aktivlər qovluğunda istifadə etmək istədiyimiz bəzi əmlakları əlavə edir:

Yoxlama nöqtəsi: 92ebfd9

Və birincisi unutmamaq üçün vacib bir şey edir: hər şeyi pubsepc.yaml dosyanıza əlavə edin. Kodunuzun yaradılması zamanı Dart yalnız orada göstərilən mənbələri birləşdirir.

Yoxlama nöqtəsi cf5975f

Nəhayət sprite çəkə bilərik. Alovun təklif etdiyi əsas yol, yüklənmiş görüntü üçün vəd verən, daha sonra canvas.drawImage metodundan istifadə edərək çəkilə bilən bir Flame.images.load ('şəkillər qovluğundan yol') metodunu təmin etməkdir. .

Bununla birlikdə, bir qutu çəkərkən bu daha asandır, çünki SpriteComponent sinifini belə istifadə edə bilərik:

Abstrakt Komponent sinfi iki metodlu bir interfeysdir: oyununuz kimi göstərmə və yeniləmə. Fikir budur ki, oyun göstərmə və yeniləmə metodları oyun metodları daxilində adlandırılan komponentlərdən ibarət ola bilər. SpriteComponent adı və ölçüsü (kvadrat və ya düzbucaqlı), mövqeyi (x, y) və fırlanma bucağına əsasən bir sprite təmsil edən bir tətbiqdir. İstədiyiniz ölçüyə uyğun şəkildə şəkil uyğun şəkildə azaldılacaq və ya böyüdüləcəkdir.

Bu vəziyyətdə "varlıqlar / şəkillər" qovluğunda olması lazım olan "crate.png" faylını yükləyirik və 128 x 128 piksel və 0 dönmə bucağı olan çərçivələr çəkən bir sandıq sinfinə sahibik.

Sonra oyuna bir Crate xassəsi əlavə edirik, ekranın yuxarısında mərkəzləşdirilmiş şəkildə düzəldirik və oyun loopumuzda göstəririk:

Bu, qutumuzu göstərəcəkdir! Parlaq! Kod olduqca qısadır və oxunması da asandır.

Yoxlama nöqtəsi 7603ca4

Oyun döngəsindəki vəziyyəti yeniləyin

Qutumuz praktik olaraq havada dayandı. Biz onu köçürmək istəyirik! Hər qutu sabit bir sürətlə aşağı düşəcək. Bunu yeniləmə metodumuzda etməliyik; Sadəcə sahib olduğumuz hər qutunun Y mövqeyini dəyişdirin:

Bu metod son yeniləmədən bəri keçən vaxtı (saniyələrlə) alır. Ümumiyyətlə bu çox kiçik olacaq (10 ms əmri ilə). Bu səbəbdən HIZ bu vahidlərdə sabitdir. bizim vəziyyətimizdə SPEED = 100 piksel / saniyə.

Yoxlama nöqtəsi: 452dc40

Girişlərin idarə olunması

Uğur! Qutular yıxılıb yox olur, ancaq onlarla əlaqə qura bilməzsiniz. Toxunduğumuz qutuları məhv etmək üçün bir metod əlavə edək. Bunun üçün bir pəncərə hadisəsindən istifadə edəcəyik. Widget hər Flutter layihəsində qlobal səviyyədə mövcuddur və bəzi faydalı xüsusiyyətlərə malikdir. Əsas metod üçün, yəni istifadəçi ekranı vurduqda onPointerDataPacket hadisəsini qeyd edəcəyik:

Sadəcə vuruşun (x, y) koordinatını çıxarırıq və birbaşa oyunumuza ötürürük. Beləliklə, oyun hadisələrin təfərrüatları barədə narahat olmadan kliklə işləyə bilər.

Hər şeyi daha maraqlı etmək üçün oyun sinifini tək qutu əvəzinə qutuların siyahısına sahib etmək üçün yenidən düzəltməliyik. Axı biz istədiyimiz budur. Render və yeniləmə metodlarını forEach qutuları üzərində əvəz edirik və yeni giriş metodu:

Yoxlama nöqtəsi: 364a6c2

Birdən çox sprit göstərin

Burada bir vacib məqam var və bu, göstərmə metodu ilə bağlıdır. Bir qutu göstərdiyimiz zaman, kətanın vəziyyəti özbaşına dəyişdirilir və çəkilməsinə imkan vermək üçün dönər. Bir neçə qutu çəkmək istədiyimiz üçün ayrı qutular arasındakı kətanı sıfırlamalıyıq. Bu, mövcud vəziyyəti saxlayan və əvvəllər qeyd edilmiş vəziyyəti bərpa edən və silən bərpa edən metodlardan istifadə etməklə həyata keçirilir.

Bir çox qəribə böcəyin səbəbi olduğu üçün bu vacib bir qeyddir. Bəlkə hər göstərdiyimiz zaman bunu avtomatik olaraq etməliyik? Bilmirəm nə düşünürsən?

İndi daha çox qutu istəyirik! Bu necə işləyir? Yeniləmə metodu bizim zamanlayıcımız ola bilər. Buna görə siyahıya hər saniyə yeni bir qutu əlavə olunmasını istəyirik. Beləliklə, hər bir yeniləmə çağrısından (t) toplanmaq üçün Oyun sinifində başqa bir dəyişən yaratdıq. 1-dən yuxarıdırsa, yenidən quracaq və yeni bir qutu yaradacaq:

Qutuların düşməsini dayandırmaması üçün əvvəlki yeniləməni saxlamağı unutmayın. İşləri bir az daha maraqlı etmək üçün sürəti 250 piksel / saniyəyə dəyişdiririk.

Yoxlama nöqtəsi: 3932372

Animasiyalar göstərin

Bu bir GIF olmalıdır? Bu dərslik üçün daha yaxşı ekran görüntüləri və GIF-lər üçün quraşdırma üzərində işləyirik!

İndi sprite ilə işləmə və göstərmənin əsaslarını bilirik. Növbəti mərhələyə keçək: partlayışlar! Onsuz hansı oyun yaxşıdır? Partlama animasiya ehtiva etdiyi üçün fərqli bir heyvan növüdür. Alovdakı animasiyalar sadəcə mövcud elementə uyğun olaraq göstərildiyi üçün fərqli elementlər göstərərək yaradılır. Qutuları yumurtlamaq üçün əl istehsalı bir taymer əlavə etdiyimiz kimi, hər bir partlayış üçün ömür müddəti də əlavə edəcəyik. Ayrıca, Partlama SpriteComponent-dən miras almayacaq, çünki ikincisi yalnız bir Sprite ola bilər. Superclass PositionComponent-i genişləndirəcəyik və Flame.image.load ilə göstərməyi həyata keçirəcəyik.

Hər bir partlayışda bir çox çərçivə olduğu və bunların sürətlə çəkilməli olduğu üçün hər bir çərçivəni əvvəlcədən yükləyirik və partlayış sinifindəki statik dəyişkəndə saxlayırıq. Necə:

7 animasiya çərçivəmizin hər birini növbə ilə yüklədiyimizə diqqət yetirin. Sonra hansının çəkiləcəyinə qərar vermək üçün göstərmə metodunda sadə bir məntiq yaradırıq:

Qeyd edək ki, artıq izah olunduğu kimi drawImageRect ilə “əllə” rəsm edirik. Bu kod SpriteComponent-in başlıq altında etdiyinə bənzəyir. Həm də nəzərə alın ki, şəkil massivdə deyilsə, heç bir şey çəkilməyəcəkdir. TIME saniyəsindən sonra (0.75 və ya 750 ms olaraq təyin etdik) heç bir şey göstərilmədi.

Hər şey yaxşı və yaxşıdır, amma partlayış massivimizi partlamış partlayışlarla çirkləndirməyə davam etmək istəmirik. Buna görə də, lifeTime metoduna əsasən, partlama obyektini məhv edib etməməyimizi qaytaran bir dest () metodu əlavə edirik.

Nəhayət, oyunumuzu yeniləyəcəyik, partlayış siyahısı əlavə edəcəyik, göstərmə metodundan istifadə edərək göstərəcəyik və sonra yeniləmə metodundan istifadə edərək yeniləyəcəyik. Ömürlərini artırmaq üçün yenilənməlidirlər. Bundan əvvəl Game.update metoduna daxil olanları yenidən işləmək üçün vaxt ayırırıq, yəni. H. Sandıqlar Sandıqın yenilənməsi metoduna düşür, çünki sandıq məsuliyyət daşıyır. İndi oyun yeniləməsi yalnız başqalarına həvalə olunur. Nəhayət, yeniləmədə məhv olanları siyahıdan çıxarmaq lazımdır. Siyahı bunun üçün çox faydalı bir metod təklif edir, buradan çıxarın:

Bunu indidən serialın toxunduğu sahələri silmək üçün giriş metodu üçün istifadə etmişik. Orada da bir partlayışa səbəb olacağıq.

Daha ətraflı məlumat üçün nəzarət məntəqəsinə baxın.

Yoxlama nöqtəsi: d8c30ad

Səsi səsləndirin

Nəhayət növbəti öhdəlikdə bir az səs çalacağıq! Bunu etmək üçün faylı aktivlər / səs / tərkibindəki Aktivlər qovluğuna əlavə etməlisiniz. MP3 və ya OGG faylı olmalıdır. Sonra kodunuzun hər hansı bir yerində aşağıdakıları edin:

Filename.mp3 içərisində olduğu faylın adıdır. Bizim vəziyyətimizdə bir qutuya vurduğumuz zaman səs partlayışını oynayırıq .mp3

Punktuasiya ilə başlayaq. Cari bal sayını saxlamaq üçün bir nöqtə dəyişən əlavə edirik. Sıfırdan başlayır; Bir klik başına 10 bal alırıq və qutu yerə dəysə 20 itiririk.

Artıq qaçaq qutularla mübarizə borcumuz var. Partlayış sinifində etdiklərimizə əsasən, sandıq üçün ekranda göstərilmədiyi təqdirdə geri dönəcək bir məhv üsulu əlavə edirik. Bu bir model halına gəlməyə başlayır! Məhv olarsa, onu massivdən çıxarırıq və nöqtələri tənzimləyirik.

Qiymətləndirmə hazırda işləyir, amma heç yerdə göstərilmir. tezliklə gələcək.

Faylları əlavə edib pubspec.yaml faylına qoymağı unutduğum üçün səs bu növbəti nəzarət nöqtəsində işləməyəcəkdir. Bu, aşağıdakı öhdəlikdə baş verir.

Yoxlama nöqtəsi: 43a7570

İndi daha çox ton istəyirik! Alovun istifadə etdiyi səs pleyerləri (lərinə diqqət yetirin) bir dəfəyə birdən çox səsləri səsləndirməyə imkan verir, çünki dəli vurduğunuzu görmüsünüz, amma indi əlavə edərək bu imkandan istifadə edək. qutu yerə dəyəndə (qutunun məhv edilməsi üsulu) və arxa fon musiqisində bir miss oynayırıq.

Arxa fon musiqisini bir döngədə çalmaq üçün aşağıdakı şəkildə işləyən ilmə metodundan istifadə edin:

Bu öhdəlikdə əvvəlki öhdəlikdə qaçırdığımız qutuların məhv vəziyyətini də düzəldirik (bilmək üçün bir yol olmadığından, indi səs var).

Yoxlama nöqtəsi: f575150

Mətn göstərin

Artıq istədiyimiz bütün səs məlumatlarına (arxa plan, musiqi, səs effektləri, MP3, OGG, sonsuz döngə) eyni zamanda sahib olduğumuz üçün mətni səsləndirməyə başlaya bilərik. Bu hesabı görməliyik. Bu, bir paraqraf obyekti yaratmaqla və rəsm sahəsinin drawParagraphını istifadə edərək "əllə" həyata keçirilir. Çox konfiqurasiya tələb edir və olduqca qarışıq bir API-dir, ancaq bu şəkildə edilə bilər:

Yoxlama nöqtəsi: e09221e

Bu, standart şriftdə çəkilir və fərqli bir ümumi sistem şriftini təyin etmək üçün fontFamily xassəsindən istifadə edə bilərsiniz. Bununla birlikdə, ehtimal ki, oyununuza xüsusi bir əlavə etmək istəyəcəksiniz.

Beləliklə, 1001fonts.com saytına getdim və TTF olaraq bu səliqəli reklam pulsuz Halo şriftini aldım. Burada da faylın yalnız Aktivlər / Yazı tiplərində saxlanılması lazımdır. İndi pubspec.yaml faylında fərqli şəkildə idxal edilməlidir. Başqa bir aktiv əlavə etmək əvəzinə, şriftlərin necə əlavə ediləcəyi ilə bağlı tam təlimatlarla şərhi olan xüsusi bir yazı etiketi var. Buna görə ad verin və belə bir şey edin:

Bu əlavə abstraksiya təbəqəsi Flutter-in özündən gəlir və eyni şriftə bir çox fayl əlavə etməyə imkan verir (qalın, daha böyük ölçüləri və s. Müəyyənləşdirmək üçün). İndi abzasımıza qayıdaq, yalnız fontFamily: 'Halo' xassəsini TextStyle konstruktoruna əlavə edək.

Çalıştırın və olduqca Halo şriftini görəcəksiniz!

Yoxlama nöqtəsi: 3155bda

Təsvir edilən bu metod, məsələn, eyni paraqrafda bir çox üsluba sahib olmaq istəyirsinizsə, sizə daha çox nəzarət verir. Bununla birlikdə, bu vəziyyətdə olduğu kimi, üslublu tək bir sadə abzas istəyirsinizsə, onu yaratmaq üçün Flame.util.text köməkçisindən istifadə edə bilərsiniz:

Bu tək sətir əvvəlki 4-ü əvəz edir və ən vacib funksiyaları göstərir. Mətn (birinci arqument) tələb olunur və digərləri isteğe bağlıdır və ağlabatan standartdır.

Rəng üçün yenidən Colors.white köməkçisini istifadə edirik, ancaq müəyyən bir rəng istəsəniz yeni rəngdən də istifadə edə bilərik (0xFFFFFFFF).

Yoxlama nöqtəsi: 952a9df

Və orada səndə var! Sprite göstərmə, mətn göstərmə, səs, oyun dövrü, hadisələr və vəziyyət idarəçiliyi ilə tam bir oyun.

nəşr

Oyun başlamağa hazırdır?

Yalnız Flutter təlimindən bu sadə addımları izləyin.

Bir az baş ağrısı ola biləcək nişanlar hissəsi xaricində, bu son nəzarət nöqtəsində gördüyünüz kimi hamısı olduqca sadədir. İkonunuzun böyük bir versiyasını (512 və ya 1024 piksel) hazırlamağınızı və ehtiyac duyduğunuz hər şeylə (iOS və Android) bir zip faylı yaratmaq üçün App Icon veb saytından istifadə etməyinizi məsləhət görürəm.

Yoxlama nöqtəsi: 2974f29

Başqa?

Alov xoşunuza gəldi? Hər hansı bir təklifiniz, səhviniz, sualınız, funksiya istəkləriniz və ya oxşarlarınız varsa, xahiş edirəm mənimlə əlaqə qurun!

Oyununuzu yaxşılaşdırmaq və daha çox öyrənmək istərdinizmi? Firebase və Google Giriş olan bir server necə? Bir reklam yerləşdirməyə necə? Əsas menyu və birdən çox ekran qurmaq necədir?

Əlbəttə ki, yaxşılaşdırıla bilən bir çox şey var - bu yalnız nümunə oyun. Bununla birlikdə, Flutter oyun inkişafının (alovlu və ya olmayan) əsas konsepsiyalarına dair əsas bir fikrə sahib olmalıdır.

Ümid edirəm hamı bəyəndi!

Əvvəlcə GitHub-da yayımlandı.