Penciptaan game "Seperti koin" di Godot Engine. Bagian 1

Godot Engine berkembang sangat cepat dan memenangkan hati pengembang game dari seluruh dunia. Mungkin ini adalah alat yang paling ramah dan mudah dipelajari untuk membuat game, dan untuk memastikan hal ini, cobalah untuk membuat game 2D kecil. Untuk pemahaman yang baik tentang proses pengembangan game, Anda harus mulai dengan game 2D - ini akan menurunkan ambang batas untuk memasuki sistem game yang lebih serius. Meskipun transisi ke 3D itu sendiri tidak sesulit kelihatannya, setelah semua, sebagian besar fungsi di Godot Engine dapat berhasil digunakan dalam 2D โ€‹โ€‹dan 3D.


Pendahuluan


Hal paling sederhana yang dapat Anda pikirkan adalah permainan di mana karakter utama kami akan mengumpulkan koin. Untuk sedikit memperumitnya, tambahkan hambatan dan waktu, sebagai faktor pembatas. Gim ini akan memiliki 3 adegan: Player , Coin , dan HUD (artikel ini tidak dipertimbangkan), yang akan digabungkan menjadi satu adegan Main .



Pengaturan proyek


Sebelum Anda mulai menulis skrip (skrip), yang kira-kira 80-90% dari total waktu yang dihabiskan untuk membuat gim, hal pertama yang harus dilakukan adalah menyiapkan proyek masa depan kami. Dalam proyek besar, akan berguna untuk membuat folder terpisah untuk menyimpan skrip, adegan, gambar dan suara, dan kita harus mempertimbangkan ini, karena siapa yang tahu apa hasil akhirnya.


Saya ingin membuat reservasi segera bahwa artikel ini mengasumsikan bahwa Anda sedikit terbiasa dengan Mesin Godot dan Anda memiliki beberapa pengetahuan dan keterampilan dalam menggunakan alat ini, meskipun saya akan fokus pada kenyataan bahwa Anda menemukan Mesin Godot untuk pertama kalinya, saya masih Saya menyarankan Anda terlebih dahulu membiasakan diri dengan komponen dasar mesin, mempelajari sintaks GDScript dan memahami terminologi yang digunakan (node, adegan, sinyal, dll.), Dan baru kemudian kembali ke sini dan melanjutkan kenalan Anda.

Di menu program, pergi ke Project -> Project Settings .


Penyimpangan kecil lainnya. Saya akan selalu memberikan contoh berdasarkan pada fakta bahwa pengguna akhir menggunakan antarmuka bahasa Inggris dari mesin, terlepas dari kenyataan bahwa "Mesin Godot" memiliki dukungan untuk bahasa Rusia. Hal ini dilakukan untuk menghilangkan kemungkinan kesalahpahaman atau rasa malu yang terkait dengan terjemahan elemen-elemen tertentu dari antarmuka program yang salah / tidak akurat.

Temukan bagian Display/Window dan atur lebar ke 800 dan tinggi ke 600 . Juga di bagian ini, atur Stretch/Mode ke 2D dan Aspect to Keep . Ini akan mencegah peregangan dan deformasi isi jendela saat mengubah ukurannya, tetapi untuk mencegah ukuran jendela, cukup hapus centang pada kotak Resizable . Saya menyarankan Anda untuk bermain-main dengan opsi ini.


Sekarang pergi ke bagian Rendering/Quality dan nyalakan Use Pixel Snap di panel kanan. Untuk apa ini? Koordinat vektor dalam Mesin Godot adalah angka floating point. Karena objek tidak dapat ditarik hanya setengah piksel, perbedaan ini dapat menyebabkan cacat visual untuk game yang menggunakan pixelart . Dan perlu dicatat bahwa dalam 3D opsi ini tidak berguna. Ingatlah ini.


Scene Pemain


Mari kita mulai membuat adegan pertama - Player .


Keuntungan dari setiap adegan adalah bahwa pada awalnya mereka tidak tergantung pada bagian lain dari permainan dan ini memungkinkan untuk secara bebas menguji mereka dan mendapatkan hasil yang semula diletakkan di dalamnya. Secara umum, membagi objek game menjadi adegan adalah alat yang berguna dalam membuat game yang kompleks - lebih mudah untuk menangkap kesalahan, membuat perubahan pada adegan itu sendiri, sementara bagian lain dari game tidak akan terpengaruh, mereka juga dapat berfungsi sebagai template untuk game lain dan mereka pasti akan berfungsi dengan baik. karena mereka bekerja sebelum transfer.

Membuat pemandangan adalah tindakan yang sangat mudah - pada tab Scene , klik + (Tambah / Buat) dan pilih simpul Area2D dan segera ubah namanya agar tidak menjadi bingung. Ini adalah simpul induk kami, dan untuk memperluas fungsionalitas Anda perlu menambahkan simpul anak. Dalam kasus kami, ini adalah AnimatedSprite dan CollisionShape2D , tapi jangan terburu-buru, tapi mari kita mulai secara berurutan. Selanjutnya, segera "kunci" simpul root:



Jika bentuk tumbukan tubuh (CollisionShape2D) atau sprite (AnimatedSprite) digeser, direntangkan relatif ke node induk, ini pasti akan menyebabkan kesalahan yang tidak terduga dan kemudian akan sulit untuk memperbaikinya. Dengan opsi ini diaktifkan, "orang tua" dan semua "anak-anaknya" akan selalu bergerak bersama. Kedengarannya lucu, tetapi menggunakan fitur ini sangat berguna.


AnimatedSprite


Area2D simpul yang sangat berguna jika Anda perlu tahu tentang acara tumpang tindih dengan objek lain atau tentang tabrakan mereka, tetapi dengan sendirinya itu tidak terlihat oleh mata dan untuk membuat objek Player terlihat tambah AnimatedSprite . Nama simpul memberitahu kita bahwa kita akan berurusan dengan animasi dan sprite. Di jendela Inspector , buka parameter Frames dan buat SpriteFrames baru. Bekerja dengan panel SpriteFrames adalah membuat animasi yang diperlukan dan memuat sprite yang sesuai dengannya. Kami tidak akan menganalisis secara rinci semua tahap pembuatan animasi, meninggalkan ini untuk studi independen, saya hanya akan mengatakan bahwa kita harus memiliki tiga animasi: walk (berjalan animasi), idle (keadaan istirahat) dan die (kematian atau kegagalan animasi). Jangan lupa nilai SPEED (FPS) harus 8 (walaupun Anda bisa memilih nilai yang berbeda - cocok).



Collisionshape2d


Untuk Area2D untuk mendeteksi tabrakan, Anda harus menyediakannya dengan bentuk objek. Bentuk ditentukan oleh parameter Shape2D dan termasuk persegi panjang, lingkaran, poligon, dan jenis bentuk yang lebih kompleks lainnya, dan ukurannya sudah diedit di editor itu sendiri, tetapi Anda selalu dapat menggunakan Inspector untuk Inspector lebih baik.


Skenario


Sekarang, untuk "menghidupkan kembali" objek game kami, Anda perlu mengatur skrip untuk itu, yang menurutnya tindakan yang kami lakukan, yang ditentukan dalam skenario ini, akan dilakukan. Di tab Scene , buat skrip, tinggalkan pengaturan default, hapus semua komentar (baris dimulai dengan tanda '#') dan lanjutkan untuk mendeklarasikan variabel:


 export (int) var speed var velocity = Vector2() var window_size = Vector2(800, 600) 

Menggunakan kata kunci export memungkinkan Anda untuk mengatur nilai variabel speed di jendela panel Inspector . Ini adalah metode yang sangat berguna jika kita ingin mendapatkan nilai khusus yang nyaman untuk diedit di jendela Inspector . Setel Speed ke 350 . Nilai velocity akan menentukan arah gerakan, dan window_size adalah area yang membatasi pergerakan pemain.


Urutan tindakan kami selanjutnya adalah sebagai berikut: kami menggunakan fungsi get_input() untuk memeriksa apakah input keyboard sedang dibuat. Kemudian kita akan memindahkan objek, sesuai dengan tombol yang ditekan, dan kemudian memainkan animasi. Pemain akan bergerak dalam empat arah. Secara default, Mesin Godot memiliki acara yang ditetapkan untuk tombol panah ( Project -> Project Settings -> Input Map ), sehingga kami dapat menerapkannya pada proyek kami. Untuk mengetahui apakah tombol telah ditekan, Anda harus menggunakan Input.is_action_pressed() dengan menyelipkannya nama acara yang ingin Anda lacak.


 func get_input(): velocity = Vector2() if Input.is_action_pressed("ui_left"): velocity.x -= 1 if Input.is_action_pressed("ui_right"): velocity.x += 1 if Input.is_action_pressed("ui_up"): velocity.y -= 1 if Input.is_action_pressed("ui_down"): velocity.y += 1 if velocity.length() > 0: velocity = velocity.normalized() * speed 

Sepintas, semuanya terlihat bagus, tetapi ada satu nuansa kecil. Kombinasi beberapa tombol yang ditekan (misalnya, bawah dan kiri) akan menyebabkan penambahan vektor dan dalam hal ini pemain akan bergerak lebih cepat daripada jika ia hanya bergerak ke bawah. Untuk menghindari ini, kita akan menggunakan metode normalized() - ini akan mengembalikan panjang vektor ke 1 .


Jadi, peristiwa penekanan tombol dilacak, sekarang Anda harus memindahkan objek Player . Fungsi _process() akan membantu kita dengan ini, yang disebut setiap kali perubahan bingkai terjadi, jadi disarankan untuk menggunakannya untuk objek-objek yang sering berubah.


 func _process(delta): get_input() position += velocity * delta position.x = clamp(position.x, 0, window_size.x) position.y = clamp(position.y, 0, window_size.y) 

Saya harap Anda memperhatikan parameter delta , yang pada gilirannya dikalikan dengan kecepatan. Perlu untuk menjelaskan apa itu. Mesin game pada awalnya dikonfigurasikan untuk beroperasi pada kecepatan 60 frame per detik. Namun demikian, mungkin ada situasi di mana komputer atau Mesin Godot itu sendiri melambat. Jika frame rate tidak konsisten (waktu yang dibutuhkan untuk frame berubah), ini akan mempengaruhi "kelancaran" pergerakan objek game (sebagai akibatnya, pergerakannya adalah "dendeng"). "Mesin Godot" memecahkan masalah ini (seperti kebanyakan mesin serupa) dengan memperkenalkan variabel delta - ini memberikan nilai perubahan frame. Berkat nilai-nilai ini, Anda dapat "menyelaraskan" gerakan. Perhatikan satu lagi fungsi yang luar biasa - clamp (mengembalikan nilai dalam dua parameter yang ditentukan), berkat itu kami dapat membatasi area yang dapat dipindahkan oleh Player dengan hanya mengatur nilai minimum dan maksimum dari area tersebut.


Jangan lupa untuk menghidupkan objek kita. Harap dicatat bahwa ketika objek bergerak ke kanan, Anda perlu membalik AnimatedSprite (menggunakan flip_h ) dan pahlawan kami akan melihat ke arah di mana dia bergerak langsung saat bergerak. Pastikan bahwa dalam AnimatedSprite parameter Playing diaktifkan sehingga animasi mulai diputar.


 if velocity.length() > 0: $AnimatedSprite.animation = "walk" $AnimatedSprite.flip_h = velocity.x < 0 else: $AnimatedSprite.animation = "idle" 

Kelahiran dan kematian


Saat meluncurkan game, adegan utama harus diberitahu tentang adegan utama tentang kesiapannya untuk memulai permainan baru, dalam kasus kami, Anda harus memberi tahu objek Player tentang permulaan game dan mengatur parameter awal untuknya: posisi tampilan, animasi default, jalankan set_process .


 func start(pos): set_process(true) #     Vector2(x, y) position = pos $AnimatedSprite.animation = "idle" 

Kami juga menyediakan acara kematian pemain saat waktu habis atau pemain mengalami hambatan, dan pengaturan set_process (false) akan menyebabkan fungsi _process () tidak lagi dieksekusi untuk adegan ini.


 func die(): $AnimatedSprite.animation = "die" set_process(false) 

Menambahkan Tabrakan


Itu adalah giliran untuk membuat pemain mendeteksi tabrakan dengan koin dan rintangan. Ini paling mudah diimplementasikan menggunakan sinyal. Sinyal adalah cara yang bagus untuk mengirim pesan sehingga node lain dapat mendeteksi dan meresponsnya. Sebagian besar node sudah memiliki sinyal bawaan, tetapi dimungkinkan untuk mendefinisikan sinyal "pengguna" untuk keperluan mereka sendiri. Sinyal ditambahkan jika Anda menyatakannya di awal skrip:


 signal pickup signal die 

Jelajahi daftar sinyal di jendela Inspector (tab Node ), dan perhatikan sinyal kami, dan sinyal yang sudah ada. Sekarang kita tertarik pada area_entered () , itu mengasumsikan bahwa objek yang akan terjadi tabrakan juga bertipe Area2D . Kami menghubungkan sinyal area_entered () menggunakan tombol Connect , dan di jendela Connect Signal , pilih node yang disorot (Player), biarkan sisanya secara default.


 func _on_Player_area_entered( area ): if area.is_in_group("coins"): #  emit_signal("pickup") area.pickup() 

Agar objek dapat dengan mudah dideteksi dan berinteraksi, mereka perlu diidentifikasi dalam kelompok yang sesuai. Pembuatan grup itu sendiri sekarang dihilangkan, tetapi kami pasti akan kembali kepada mereka nanti. Fungsi pickup() menentukan perilaku koin (misalnya, dapat memainkan animasi atau suara, menghapus objek, dll.).


Adegan Koin


Saat membuat adegan dengan satu koin, Anda perlu melakukan semua yang kami lakukan dengan adegan "Player", kecuali bahwa hanya akan ada satu animasi (highlight) di AnimatedSprite . Speed (FPS) dapat ditingkatkan menjadi 14 . Kami juga akan mengubah skala AnimatedSprite - 0,5, 0,5 . Dan dimensi CollisionShape2D harus sesuai dengan gambar koin, hal utama adalah bukan untuk skala itu, yaitu mengubah ukuran menggunakan spidol yang sesuai pada formulir di editor 2D, yang
menyesuaikan jari-jari lingkaran.



Grup adalah semacam pelabelan node yang memungkinkan Anda mengidentifikasi node serupa. Agar objek Player bereaksi terhadap sentuhan dengan koin, koin harus menjadi milik grup, sebut saja coins . Pilih simpul Area2D (dengan nama "Coin") dan tetapkan tag di tab Node -> Groups , membuat grup yang sesuai.



Untuk simpul Coin , buat skrip. Fungsi pickup() akan dipanggil oleh skrip objek Player dan akan memberi tahu koin apa yang harus dilakukan ketika berfungsi. Metode queue_free() akan dengan aman menghapus simpul dari pohon dengan semua simpul turunannya dan mengosongkan memori, tetapi penghapusan tidak akan langsung bekerja, pertama-tama akan dipindahkan ke antrian untuk dihapus di akhir bingkai saat ini. Ini jauh lebih aman daripada menghapus sebuah node segera, karena "peserta" lain (node โ€‹โ€‹atau adegan) dalam game mungkin masih membutuhkan node ini untuk ada.


 func pickup (): queue_free () 

Kesimpulan


Sekarang kita dapat membuat adegan Main , seret kedua adegan: Player dan Coin mouse ke editor 2D, dan periksa bagaimana gerakan pemain dan kontaknya dengan koin bekerja dengan memulai adegan (F5). Yah, saya sedang terburu-buru mengatakan bahwa bagian pertama dari pembuatan game "Like Coins" selesai, biarkan saya mengambil cuti dan berterima kasih kepada semua orang atas perhatian mereka. Jika Anda memiliki sesuatu untuk dikatakan, melengkapi bahan atau Anda melihat kesalahan dalam artikel, pastikan untuk melaporkannya dengan menulis komentar di bawah ini. Jangan takut menjadi tangguh dan kritis. "Umpan balik" Anda akan memberi tahu Anda apakah saya bergerak ke arah yang benar dan apa yang bisa diperbaiki untuk membuat materi lebih menarik dan bermanfaat.

Source: https://habr.com/ru/post/id429234/


All Articles