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

A * Pathfinding untuk Platformer Berbasis Grid 2D: Membuat Bot Ikut Laluan

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called How to Adapt A* Pathfinding to a 2D Grid-Based Platformer.
A* Pathfinding for 2D Grid-Based Platformers: Different Character Sizes
A* Pathfinding for 2D Grid-Based Platformers: Ledge Grabbing

Malay (Melayu) translation by Seurion (you can also view the original English article)

Dalam tutorial ini, kami akan menggunakan algoritma pathfinding platformer yang kami telah bina untuk menggerakkan bot yang boleh mengikuti laluan dengan sendirinya; hanya klik pada lokasi dan ia akan berjalan dan melompat ke sana. Ini sangat berguna untuk NPC!

Demo

Anda boleh memainkan demo Unity, atau versi WebGL (100MB), untuk melihat hasil akhir tindakan. Gunakan WASD untuk menggerakkan watak, klik-kiri di tempat untuk mencari laluan yang boleh anda ikuti untuk sampai ke sana, klik-kanan sel untuk bertukar-tukar tanah pada titik itu, klik-tengah untuk meletakkan platform sehala, dan klik -dan seret slider untuk menukar nilai mereka.

Memperbarui Engine

Penanganan Negara Bot

Bot ini mempunyai dua keadaan yang ditentukan: yang pertama adalah untuk tidak melakukan apa-apa, dan yang kedua adalah untuk mengendalikan gerakan. Dalam permainan anda, bagaimanapun, anda mungkin memerlukan lebih banyak lagi untuk menukar tingkah laku bot mengikut keadaan.

Gelung kemas kini bot akan melakukan perkara yang berbeza bergantung pada keadaan yang sedang diberikan kepada mCurrentBotState:

Fungsi CharacterUpdate mengendalikan semua input dan fizik kemas kini untuk bot.

Untuk menukar keadaan, kami akan menggunakan fungsi ChangeState yang hanya memberikan nilai baru kepada mCurrentBotState:

Mengawal Bot

Kami akan mengawal bot dengan mensimulasikan input, yang akan kami berikan kepada pelbagai Booleans:

Arahan ini diindeks oleh enum KeyInput:

Contohnya, jika kita mahu mensimulasikan butang tekan kiri, kita akan melakukannya seperti ini:

Logik watak kemudian akan mengendalikan input buatan ini dengan cara yang sama bahawa ia akan mengendalikan input sebenar.

Kami juga memerlukan fungsi pembantu tambahan atau jadual carian untuk mendapatkan bilangan bingkai yang kami perlukan untuk menekan butang lompat untuk melompat sebilangan blok:

Ambil perhatian bahawa ini hanya akan berfungsi secara konsisten jika permainan kami dikemas kini dengan kekerapan tetap dan kelajuan melompat bermula watak adalah sama. Idealnya, kita akan mengira nilai-nilai ini secara berasingan untuk setiap watak bergantung pada kelajuan lompat watak itu, tetapi di atas akan berfungsi dengan baik dalam kes kita.

Menyediakan dan Mendapatkan Laluan untuk Ikut

Menghadiri Lokasi Matlamat

Sebelum kita benar-benar menggunakan penunjuk laluan itu, ia adalah idea yang baik untuk memaksa tujuan matlamat berada di tanah. Ini kerana pemain itu mungkin akan mengklik tempat yang sedikit di atas tanah, di mana laluan bot akan berakhir dengan melompat janggal ke udara. Dengan menurunkan titik akhir tepat pada permukaan tanah, kita boleh dengan mudah mengelakkan ini.

Pertama, mari kita lihat fungsi TappedOnTile. Fungsi ini akan dipanggil apabila pemain mengklik mana-mana sahaja dalam permainan; parameter mapPos adalah kedudukan jubin yang dimainkan oleh pemain:

Kita perlu menurunkan kedudukan jubin yang diklik sehingga ia berada di atas tanah:

Akhirnya, sebaik sahaja kami tiba di jubin tanah, kita tahu di mana kita hendak memindahkan watak itu kepada:

Menentukan Lokasi Permulaan

Sebelum kita benar-benar memanggil fungsi FindPath, kita perlu memastikan bahawa kita lulus sel mula yang betul.

Pertama, mari kita asumsikan bahawa jubin permulaan adalah sel bawah kiri watak:

Jubin ini mungkin bukan yang kita mahu lulus ke algoritma sebagai nod pertama, kerana jika watak kita berdiri di tepi platform, startTile dikira dengan cara ini mungkin tidak mempunyai alasan, seperti dalam keadaan berikut:

Dalam kes ini, kami ingin menetapkan nod awal ke jubin yang berada di sebelah kiri watak, bukan di tengahnya.

Mari kita mulakan dengan mewujudkan satu fungsi yang akan memberitahu kita jika watak itu akan sesuai dengan kedudukan yang berbeza, dan jika ia berlaku, sama ada di tempat itu:

Pertama, mari kita lihat jika watak sesuai dengan tempatnya. Sekiranya tidak, kami segera boleh kembali palsu:

Sekarang kita dapat melihat sama ada mana-mana jubin di bawah watak adalah jubin tanah:

Mari kita kembali ke fungsi MoveTo, dan lihat sama ada kita perlu menukar jubin permulaan. Kita perlu melakukan itu jika watak itu berada di atas tanah tetapi jubin permulaan tidak:

Kita tahu bahawa, dalam kes ini, watak itu berdiri sama ada di tepi kiri atau tepi kanan platform.

Mari kita periksa tepi yang betul; jika watak sesuai di sana dan jubin di atas tanah, maka kita perlu memindahkan jubin permulaan satu ruang ke kanan. Sekiranya tidak, maka kita perlu bergerak ke kiri.

Sekarang kita harus mempunyai semua data yang kita perlukan untuk memanggil penanda laluan:

Hujah pertama ialah jubin permulaan.

Yang kedua adalah destinasi; kita boleh lulus seperti ini.

Argumen ketiga dan keempat ialah lebar dan ketinggian yang perlu dihampiri oleh saiz jubin. Perhatikan bahawa di sini kita mahu menggunakan siling ketinggian dalam jubin?—jika, contohnya, jika ketinggian sebenar watak ialah 2.3 jubin, kita mahu algoritma untuk berfikir bahawa watak itu sebenarnya 3 jubin tinggi. (Lebih baik jika ketinggian sebenar watak itu sebenarnya kurang daripada saiznya dalam jubin, untuk membolehkan sedikit lebih banyak ruang untuk kesilapan dari laluan berikut AI.)

Akhirnya, hujah kelima adalah ketinggian lompat maksimum watak.

Backing Up the Node List

Selepas menjalankan algoritma, kita harus memeriksa sama ada hasilnya baik—iaitu, jika mana-mana jalan telah dijumpai:

Jika ya, kita perlu menyalin nod ke penampan yang berasingan, kerana jika ada objek lain yang memanggil fungsi FindPath pathfinder sekarang, hasil yang lama akan ditimpa. Menyalin keputusan untuk senarai berasingan akan menghalangnya.

Seperti yang anda dapat lihat, kami menyalin hasilnya dalam urutan terbalik; ini kerana hasil itu sendiri dibalikkan. Melakukan ini bermakna nod dalam senarai mPath akan berada dalam urutan pertama sekali.

Sekarang mari kita tetapkan nod gol semasa. Kerana nod pertama dalam senarai adalah titik permulaan, kita sebenarnya boleh melangkauinya dan meneruskan dari nod kedua seterusnya:

Selepas menetapkan nod matlamat semasa, kami menetapkan keadaan bot ke MoveTo, jadi keadaan yang sesuai akan diaktifkan.

Mendapatkan Konteks

Sebelum kita mula menulis peraturan untuk pergerakan AI, kita perlu dapat mengetahui keadaan apa yang ada dalam watak pada mana-mana titik tertentu.

Kita perlu tahu:

  • kedudukan destinasi sebelum ini, semasa dan seterusnya
  • sama ada destinasi semasa berada di tanah atau di udara
  • apakah karakter telah mencapai tujuan saat ini pada sumbu-x
  • sama ada watak itu telah mencapai destinasi semasa pada sumbu-y

Nota: destinasi di sini tidak semestinya destinasi matlamat akhir; mereka adalah nod dalam senarai dari bahagian sebelumnya.

Maklumat ini akan memberitahu kami dengan tepat menentukan apa bot harus dilakukan dalam apa jua keadaan.

Mari kita mulakan dengan mengisytiharkan fungsi untuk mendapatkan konteks ini:

Mengira Kedudukan Dunia Nod Destinasi

Perkara pertama yang perlu kita lakukan dalam fungsi ini adalah mengira kedudukan dunia nod destinasi.

Mari kita mulakan dengan mengira ini untuk tujuan sebelumnya. Operasi ini bergantung kepada bagaimana dunia permainan anda ditubuhkan; dalam kes saya, koordinat peta tidak sepadan dengan koordinat dunia, jadi kita perlu menterjemahkannya.

Menterjemahkannya benar-benar mudah: kita hanya perlu mengalikan posisi nod dengan saiz jubin, dan kemudian mengimbangi vektor yang dikira oleh kedudukan peta:

Perhatikan bahawa kita bermula dengan mCurrentNodeId sama dengan 1, jadi kita tidak perlu bimbang tentang secara tidak sengaja cuba mengakses nod dengan indeks -1.

Kami akan mengira kedudukan destinasi semasa dengan cara yang sama:

Dan sekarang untuk kedudukan destinasi seterusnya. Di sini kita perlu menyemak sama ada terdapat sebarang nod yang ditinggalkan untuk diikuti selepas mencapai matlamat masa kini, jadi terlebih dahulu kita mengandaikan bahawa destinasi seterusnya adalah sama dengan yang saat ini:

Sekarang, jika disna ada terdapat sebarang nod yang tersisa, kita akan mengira destinasi seterusnya dengan cara yang sama seperti yang kita buat dua sebelumnya:

Memeriksa Sama ada Node berada di Ground

Langkah seterusnya adalah menentukan sama ada destinasi semasa berada di lapangan.

Ingat bahawa tidak cukup untuk hanya memeriksa jubin secara langsung di bawah matlamat; kita perlu mempertimbangkan kes-kes di mana watak lebih daripada satu blok lebar:

Mari kita mulakan dengan mengandaikan bahawa kedudukan destinasi tidak berdasarkan:

Sekarang kita akan melihat jubin di bawah destinasi untuk melihat sama ada terdapat blok padu di sana. Jika ada, kita boleh menetapkan destOnGround kepada benar:

Memeriksa Sama ada Node Telah Datang pada X-Paksi

Sebelum kita dapat melihat apakah watak telah mencapai matlamat, kita perlu tahu kedudukannya di jalan. Kedudukan ini pada dasarnya adalah pusat sel sebelah kiri bawah watak kita. Oleh kerana watak kita tidak benar-benar dibina dari sel, kita hanya akan menggunakan kedudukan kiri bawah kotak sempadan karakter ditambah setengah sel:

Inilah kedudukan yang perlu kita sepadan dengan nod gol.

Bagaimanakah kita dapat menentukan sama ada watak itu telah mencapai matlamat pada paksi-x? Ia akan selamat untuk mengandaikan bahawa, jika watak itu bergerak dengan betul dan mempunyai kedudukan x lebih besar atau sama dengan tujuan, maka matlamat telah dicapai.

Untuk melihat sama ada watak bergerak dengan betul, kami akan menggunakan destinasi sebelumnya, yang dalam kes ini mestilah di sebelah kiri saat ini:

Begitu juga dengan sebaliknya; jika destinasi sebelumnya berada di sebelah kanan semasa dan kedudukan x watak kurang daripada atau sama dengan posisi matlamat, maka kita boleh yakin bahawa watak itu telah mencapai matlamat pada paksi-x:

Potong Posisi Karakter

Kadang-kadang, kerana kelajuan watak, ia menyerang destinasi, yang mungkin menyebabkan ia tidak mendarat di nod sasaran. Lihat contoh berikut:

Untuk membetulkannya, kita akan menjejaskan kedudukan watak supaya ia berada di nod gol.

Syarat-syarat bagi kami untuk menangkap watak ialah:

  • Matlamat telah dicapai pada paksi-x.
  • Jarak antara kedudukan bot dan destinasi semasa lebih besar daripada cBotMaxPositionError.
  • Jarak antara kedudukan bot dan destinasi semasa tidak jauh, jadi kami tidak merakam watak dari jauh.
  • Watak tidak bergerak ke kiri atau ke kanan giliran terakhir, jadi kita merangkak watak itu hanya jika ia jatuh lurus.

cBotMaxPositionError dalam tutorial ini sama dengan 1 piksel; ini adalah sejauh mana kita membiarkan watak itu dari destinasi sementara masih membenarkannya pergi ke matlamat seterusnya.

Memeriksa Sama ada Node Telah Datang pada Y-Paksi

Mari kita fikirkan apabila kita dapat yakin bahawa watak itu telah mencapai kedudukan Y sasarannya. Pertama sekali, jika destinasi terdahulu adalah di bawah semasa, dan watak kita melompat ke ketinggian matlamat semasa, maka kita dapat mengandaikan bahawa matlamat telah dicapai.

Begitu juga, jika destinasi semasa berada di bawah yang sebelumnya dan watak itu telah mencapai kedudukan-y dari nod semasa, kita boleh menetapkan mencapaiY ke benar juga.

Tidak kira sama ada watak itu perlu melompat atau jatuh untuk mencapai posisi nod nod destinasi, jika ia benar-benar dekat, maka kita harus menetapkan mencapaiY ke benar juga:

Sekiranya destinasi di atas tanah tetapi wataknya tidak, maka kita boleh mengandaikan bahawa kedudukan Y sekarang tujuan belum dicapai:

Itu sahaja—itu semua data asas yang perlu kita ketahui untuk mempertimbangkan jenis pergerakan yang perlu dilakukan oleh AI.

Mengendalikan Pergerakan Bot

Perkara pertama yang perlu dilakukan dalam fungsi kemas kini kami ialah mendapatkan konteks yang baru kami dilaksanakan:

Sekarang mari kita dapatkan kedudukan semasa watak di sepanjang jalan. Kami mengira ini dengan cara yang sama seperti yang kita lakukan dalam fungsi GetContext:

Pada permulaan bingkai kita perlu menetapkan semula input palsu, dan tentukan mereka hanya jika keadaan untuk berbuat demikian timbul. Kami akan menggunakan hanya empat input: dua untuk pergerakan kiri dan kanan, satu untuk melompat, dan satu untuk menjatuhkan platform satu arah.

Keadaan yang pertama untuk pergerakan akan menjadi ini: jika destinasi semasa lebih rendah daripada kedudukan watak dan watak itu berdiri di atas satu arah platform, kemudian tekan butang bawah, yang akan mengakibatkan watak melompat dari platform ke bawah :

Pengendalian Melompat

Mari letakkan bagaimana lompatan kita harus berfungsi. Mula-mula, kami tidak mahu mengekalkan butang melompat yang ditekan jika mFramesOfJumping adalah 0.

Syarat kedua untuk diperiksa adalah bahawa watak itu tidak di atas tanah.

Dalam pelaksanaan fizik platformer ini, watak itu dibenarkan untuk melompat jika ia hanya melangkah dari tepi platform dan tidak lagi di atas tanah. Ini adalah kaedah yang popular untuk mengurangkan ilusi bahawa pemain telah menekan butang melompat tetapi watak tidak melompat, yang mungkin muncul disebabkan oleh ketinggalan input atau pemain menekan butang melompat sejurus selepas watak telah berpindah dari platform.

Keadaan ini akan berfungsi jika wataknya perlu melompat dari tebing, kerana bingkai melompat akan ditetapkan pada jumlah yang sesuai, watak itu secara semula jadi akan berjalan di langkan, dan pada ketika itu ia juga akan memulakan lompatan.

Ini tidak akan berfungsi jika lompat itu perlu dilakukan dari tanah; untuk mengendalikan ini kita perlu menyemak syarat-syarat ini:

  • Watak itu telah mencapai kedudukan-x nod destinasi, di mana ia akan mula melompat.
  • Node destinasi tidak di lapangan; jika kita hendak melompat, kita perlu melalui nod yang ada di udara terlebih dahulu.

Watak juga harus melompat jika ia berada di tanah dan destinasi juga berada di atas tanah. Ini biasanya berlaku jika watak perlu melompat satu jubin dan ke sisi untuk mencapai platform yang hanya satu blok lebih tinggi.

Kini mari kita mengaktifkan lompatan dan menurunkan bingkai melompat, supaya watak memegang lompatan untuk bilangan bingkai yang betul:

Perhatikan bahawa kami menurunkan mFramesOfJumping hanya jika watak itu tidak berada di atas tanah. Ini untuk mengelakkan kehilangan lompatan secara tidak sengaja sebelum memulakan lompatan.

Prosiding ke Node Destinasi Seterusnya

Mari kita fikirkan apa yang perlu berlaku apabila kita mencapai simpul—iaitu ketika keduanya mencapaiX dan mencapaiY adalah benar.

Pertama, kami akan menambah ID nod semasa:

Sekarang kita perlu menyemak sama ada ID ini lebih besar daripada bilangan nod dalam laluan kita. Jika demikian, itu bermakna watak telah mencapai matlamat:

Perkara seterusnya yang perlu kita lakukan adalah mengira lompatan untuk nod seterusnya. Oleh kerana kita perlu menggunakannya di lebih dari satu tempat, mari kita buat fungsi untuknya:

Kami hanya mahu melompat jika nod baru lebih tinggi daripada yang sebelumnya dan wataknya berada di atas tanah:

Untuk mengetahui berapa banyak jubin yang kita perlukan untuk melompat, kita akan berulang melalui nod selama mereka pergi lebih tinggi dan lebih tinggi. Apabila kita sampai kepada nod yang berada di ketinggian yang lebih rendah, atau nod yang mempunyai tanah di bawahnya, kita boleh berhenti, kerana kita tahu bahawa tidak perlu lebih tinggi daripada itu.

Pertama, mari kita menyatakan dan tetapkan pemboleh ubah yang akan memegang nilai lompat itu:

Sekarang mari kita lelapkan melalui nod, bermula pada nod semasa:

Jika nod seterusnya lebih tinggi daripada jumpHeight, dan ia tidak di atas tanah, maka mari kita tetapkan ketinggian lompat baru:

Sekiranya ketinggian nod baru lebih rendah daripada sebelumnya, atau ia berada di atas tanah, maka kita akan kembali bilangan bingkai lompat yang diperlukan untuk ketinggian yang dijumpai. (Dan jika tidak perlu melompat, mari kita kembali 0.)

Kita perlu memanggil fungsi ini dalam dua tempat.

Yang pertama adalah dalam kes di mana watak itu telah mencapai kedudukan x- dan y-:

Perhatikan bahawa kami menetapkan bingkai melompat untuk melompat keseluruhan, jadi apabila kami mencapai nod dalam udara, kami tidak mahu mengubah bilangan bingkai lompat yang ditentukan sebelum lompat berlaku.

Selepas kami mengemaskini matlamat, kami perlu memproses segala-galanya lagi, jadi bingkai pergerakan seterusnya dapat dihitung dengan serta-merta. Untuk ini, kami akan menggunakan arahan goto:

Tempat kedua yang kita perlukan untuk mengira lompat adalah fungsi MoveTo, kerana mungkin kes nod pertama laluan adalah nod melompat:

Mengendalikan Pergerakan untuk Mencapai Kedudukan Posisi-X

Sekarang mari kita mengendalikan pergerakan untuk kes di mana watak belum mencapai kedudukan-x sasaran nod itu.

Tiada apa-apa yang rumit di sini; jika destinasi adalah di sebelah kanan, kita perlu mensimulasikan butang tekan kanan. Jika destinasi di sebelah kiri, maka kita perlu mensimulasikan tekan butang kiri. Kami hanya perlu memindahkan watak jika perbezaan kedudukan lebih daripada cBotMaxPositionError constant:

Pergerakan Pengendalian Mencapai Posisi Y-Node

Sekiranya watak itu telah mencapai sasaran kedudukan x tetapi kita masih melompat lebih tinggi, kita masih boleh memindahkan watak kiri atau kanan bergantung di mana matlamat seterusnya. Ini hanya bermakna bahawa watak itu tidak melekat dengan tegas ke jalan yang dijumpai. Terima kasih kepada itu, ia akan menjadi lebih mudah untuk sampai ke destinasi seterusnya, kerana bukan hanya menunggu untuk mencapai sasaran y-kedudukan, watak itu akan secara semula jadi bergerak ke arah kedudukan-x nod seterusnya ketika ia melakukannya.

Kami hanya akan memindahkan watak ke destinasi seterusnya jika ia wujud sama sekali dan ia tidak di lapangan. (Sekiranya ia di atas tanah, maka kita tidak boleh melangkauinya kerana ia merupakan pemeriksaan penting—ia menetapkan semula kelajuan menegak aksara dan membolehkannya menggunakan lompatan itu semula.)

Tetapi sebelum kita sebenarnya bergerak ke arah matlamat seterusnya, kita perlu memastikan bahawa kita tidak akan memecahkan laluan dengan berbuat demikian.

Mengelakkan Memecahkan Kejatuhan Prematur

Pertimbangkan senario berikut:

Di sini, sebaik sahaja watak itu berjalan di langkan di mana ia bermula, ia mencapai kedudukan-x nod kedua, dan jatuh untuk mencapai kedudukan-y. Oleh kerana nod ketiga berada di sebelah kanan karakter, ia bergerak ke kanan-dan berakhir di terowong di atas yang kami mahu masuk.

Untuk membetulkannya, kita perlu menyemak sama ada terdapat sebarang halangan di antara watak dan destinasi seterusnya; jika tidak ada, maka kita bebas untuk memindahkan watak ke arah itu; jika ada, maka kita perlu menunggu.

Pertama, mari lihat jubin mana yang perlu kita periksa. Jika matlamat seterusnya adalah di sebelah kanan semasa, maka kita perlu menyemak jubin di sebelah kanan; jika ia ke kiri maka kita perlu menyemak jubin ke kiri. Sekiranya mereka berada pada kedudukan-x yang sama, tidak ada sebab untuk membuat sebarang pergerakan sebelum ini.

Seperti yang anda dapat lihat, koordinat-x nod ke kanan bergantung pada lebar watak.

Sekarang kita dapat memeriksa sama ada terdapat sebarang jubin di antara watak dan kedudukan nod seterusnya pada paksi y:

Fungsi AnySolidBlockInStripe memeriksa sama ada terdapat sebarang jubin pepejal di antara dua titik yang diberikan pada peta. Mata perlu mempunyai koordinat x yang sama. Koordinat x yang kami semak adalah jubin yang kami mahukan watak itu bergerak, tetapi kami tidak pasti sama seperti yang dijelaskan di atas.

Inilah pelaksanaan fungsi ini.

Seperti yang anda dapat lihat, fungsi itu sangat mudah; ia hanya melintang melalui jubin dalam lajur, bermula dari yang lebih rendah.

Sekarang kita tahu kita boleh bergerak ke arah destinasi seterusnya, mari kita berbuat demikian:

Membolehkan bot ke Skip Nodes

Itulah hampir—tetapi masih ada satu kes untuk menyelesaikannya. Contohnya:

Seperti yang dapat anda lihat, sebelum watak itu sampai ke kedudukan kedua nod, ia menumpuk kepalanya pada jubin terapung, kerana kami membuatnya bergerak ke arah destinasi seterusnya ke kanan. Akibatnya, watak itu tidak akan mencapai posisi-y nod kedua; sebaliknya ia bergerak terus ke nod ketiga. Oleh kerana dicapaiY adalah palsu dalam kes ini, ia tidak boleh meneruskan jalan.

Untuk mengelakkan kes sedemikian, kami akan semata-mata semak sama ada watak mencapai matlamat seterusnya sebelum mencapai sasaran semasa.

Langkah pertama ke arah ini akan memisahkan pengiraan kami sebelumnya mencapaiX dan mencapaiY ke fungsi mereka sendiri:

Seterusnya, gantikan pengiraan dengan fungsi panggilan dalam fungsi GetContext:

Sekarang kita dapat melihat sama ada destinasi seterusnya telah dicapai. Sekiranya ia ada, kita hanya boleh menambah mCurrentNode dan segera membuat semula kemas kini negeri. Ini akan menjadikan destinasi seterusnya menjadi yang terkini, dan sejak watak telah mencapai itu, kita akan dapat bergerak:

Itu sahaja untuk pergerakan watak!

Mengendalikan Syarat Semula

Adalah baik untuk mempunyai pelan cadangan untuk situasi di mana bot tidak bergerak melalui jalan seperti yang sepatutnya. Ini boleh berlaku jika, sebagai contoh, peta akan berubah-menambah penghalang kepada laluan yang telah dikira boleh menyebabkan laluan menjadi tidak sah. Apa yang akan kami lakukan ialah menetapkan semula laluan jika wataknya tersekat lebih lama daripada bilangan bingkai tertentu.

Jadi, mari kita mengisytiharkan pembolehubah yang akan mengira berapa banyak bingkai watak itu telah terperangkap dan berapa banyak bingkai ia boleh terlekat paling banyak:

Kita perlu menetapkan semula ini apabila kita memanggil fungsi MoveTo:

Dan akhirnya, pada akhir BotState.MoveTo, mari kita periksa sama ada watak itu terperangkap. Di sini, kita hanya perlu menyemak sama ada kedudukannya sekarang sama dengan yang lama; jika ya, maka kita juga perlu menambah mStuckFrames dan periksa sama ada watak itu telah terikat untuk lebih banyak bingkai daripada cMaxStuckFrames—dan jika ia adalah, maka kita perlu memanggil fungsi MoveTo dengan nod terakhir laluan semasa sebagai parameter. Sudah tentu, jika kedudukannya berbeza, maka kita perlu menetapkan semula mStuckFrames kepada 0:

Kini watak itu harus mencari jalan alternatif jika ia tidak dapat menyelesaikan yang awal.

Kesimpulan

Itulah seluruh tutorial! Sudah banyak kerja, tapi saya harap anda akan mendapati kaedah ini berguna. Ia bukan satu penyelesaian yang sempurna untuk laluan laluan platformer; perkiraan lengkung lompat untuk watak yang perlu dibuat oleh algoritma sering sukar dilakukan dan boleh menyebabkan kelakuan yang salah. Algoritma ini masih boleh diperpanjang-tidak terlalu sukar untuk menambah kelebihan langkan dan lain-lain jenis fleksibiliti pergerakan lanjutan-tetapi kita telah menutupi mekanik platformer dasar. Ia juga mungkin untuk mengoptimumkan kod untuk menjadikannya lebih cepat serta menggunakan memori kurang; lelaran algoritma ini tidak sempurna sama sekali apabila ia berkaitan dengan aspek tersebut. Ia juga mengalami penghampiran kurva yang agak kurang apabila jatuh pada kelajuan yang besar.

Algoritma ini boleh digunakan dalam pelbagai cara, terutamanya untuk meningkatkan musuh musuh AI atau AI. Ia juga boleh digunakan sebagai skema kawalan untuk peranti sentuh—ini akan berfungsi pada dasarnya dengan cara yang sama seperti dalam demo tutorial, dengan pemain mengetik di mana sahaja mereka mahu watak bergerak. Ini menghilangkan cabaran pelaksanaan di mana banyak platformer telah dibina, jadi permainan harus dirancang dengan cara yang berbeza, untuk lebih mengenali kedudukan watak anda di tempat yang betul dan bukannya belajar mengawal watak dengan tepat.

Terima kasih untuk membaca! Pastikan anda meninggalkan beberapa maklum balas mengenai kaedah dan juga beritahu saya jika anda telah membuat apa-apa penambahbaikan kepadanya!

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.