Apa tantangan dan manfaat dari menulis game dengan bahasa fungsional?


81

Meskipun saya tahu bahwa bahasa fungsional bukan yang paling umum digunakan untuk menulis game, ada banyak manfaat yang dikaitkan dengan mereka yang sepertinya akan menarik dalam konteks pemrograman apa pun. Terutama kemudahan paralelisasi yang saya pikir bisa sangat berguna karena fokus bergerak ke arah lebih banyak prosesor.

Juga, dengan F # sebagai anggota baru dari keluarga .NET, ini dapat digunakan secara langsung dengan XNA, misalnya, yang menurunkan ambang sedikit, dibandingkan dengan menggunakan LISP, Haskell, Erlang, dll.

Jika ada yang punya pengalaman menulis game dengan kode fungsional, apa yang ternyata positif dan negatif? Apa yang cocok untuk itu, apa yang tidak?

Sunting: Sulit untuk memutuskan bahwa ada satu jawaban yang bagus untuk ini, jadi mungkin lebih cocok sebagai pos wiki komunitas.


3
dengan salah satu game favorit saya (Rogue) ditulis dalam LISP, pertanyaan ini (dan potensi jawabannya) sangat menarik bagi saya.
Justin L.

Tidak tahu Rogue ditulis dalam LISP, tetapi menganggapnya menarik. Game klasik. :)
McMuttons

2
Tidak yakin apa yang Anda bicarakan. Rogue ditulis dalam C. roguebasin.roguelikedevelopment.org/index.php?title=Rogue
Mason Wheeler

2
Saya yakin Anda benar tentang Rogue asli yang ada di C, karena ditulis di Unix, tetapi pasti ada beberapa klon Rogue di Lisp: cl-user.net/asp/root-dir (bukan tautan Game langsung , itu punya begitu banyak karakter khusus yang tampaknya telah merusak hubungan).
Cyclops

Jawaban:


57

Saat ini saya sedang mengerjakan game di Haskell. Saya tidak dapat berbicara untuk pemrograman fungsional secara umum, tetapi untuk Haskell secara khusus:

Yang baik

Ini adalah hal-hal luar biasa yang membuat Haskell sangat menonjol.

  • Kemurnian berarti bahwa alasan tentang kode Anda jauh lebih mudah. Anda tidak perlu khawatir tentang nilai "saat ini" dari suatu variabel atau apakah menggunakan fungsi yang diberikan akan bertentangan dengan keadaan global Anda dalam beberapa cara. Ini juga berarti bahwa paralelisme dan konkurensi jauh lebih mudah untuk dikerjakan (dan dalam banyak kasus, sepele). Hal-hal ini bisa menjadi berkah bagi pengembang game.
  • Haskell membuatnya sangat mudah untuk menulis pada tingkat yang sangat tinggi menggunakan abstraksi ciptaan Anda sendiri. Sering kali lebih mudah untuk menulis kode yang sangat umum daripada kode khusus di Haskell, dan manfaat dari ini memanifestasikan diri mereka dalam waktu pengembangan yang lebih sedikit dan pemahaman kode yang lebih mudah. Ini lebih benar di Haskell daripada di bahasa lain yang saya tahu bahwa menggunakan antarmuka sama seperti menggunakan bahasa yang sama sekali baru (sambil tetap menjaga manfaat ekosistem Haskell lainnya). Apa yang disebut sebagian besar bahasa sebagai bahasa, Haskell menyebut perpustakaan, dan itu tidak terasa dipaksakan. Jika Anda menemukan diri Anda berpikir tentang permainan Anda di psuedocode, Anda mungkin bisa hanya menulis antarmuka sederhana dan menjadikannya kode nyata, dan biasanya layak untuk melakukannya.
  • Ini mungkin bertentangan dengan jawaban lain, tetapi Haskell lebih baik dalam menangani kode imperatif daripada bahasa lain yang saya tahu. Kendala kemurnian berarti bahwa Haskell memiliki pemisahan antara konsep "evaluasi" (mengurangi ekspresi) dan "eksekusi" (melakukan efek samping). Anda dapat mengontrol kapan dan bagaimana efek samping dilakukan dengan mudah yang tak tertandingi oleh apa yang disebut bahasa "imperatif". Terlepas dari apa yang saya katakan tentang kemurnian sebelumnya, beberapa binding C masih sangat penting (OpenGL, saya sedang melihat Anda), jadi kendali yang baik ini atas kode penting sangat diterima. Bahkan programmer C yang paling berpengalaman pun cenderung menghargainya begitu mereka terbiasa.
  • GHC menghasilkan binari yang cukup cepat. Mereka tidak secepat biner yang dihasilkan dari kompiler C umum, tetapi berada dalam urutan besarnya, dan jauh lebih cepat dari apa yang akan Anda capai dengan bahasa yang ditafsirkan. Bahkan jika Anda tidak dapat menulis gim Anda dalam bahasa tingkat tinggi lainnya seperti Python karena itu akan terlalu lambat, ada peluang bagus Anda bisa melakukannya di Haskell.
  • Meskipun tidak ada banyak perpustakaan yang berhubungan dengan game di Haskell, seperti yang disebutkan di bawah "The Bad" di bawah ini, antarmuka fungsi asing Haskell adalah yang termudah yang pernah saya gunakan. Anda dapat mengikat C dengan menulis hampir secara eksklusif di Haskell.

Keburukan

Ini adalah hal-hal yang tidak baik tetapi dapat diselesaikan tanpa terlalu banyak usaha.

  • Waktu dan upaya yang diperlukan untuk mempelajari Haskell bisa sangat tinggi jika Anda sangat terbiasa bekerja dengan bahasa non-fungsional. Bahasa itu sendiri tidak terlalu sulit, tetapi ketika Anda memfaktorkan ekstensi bahasa yang umum dan sejumlah besar perpustakaan (ingat, banyak hal yang mungkin Anda pertimbangkan fitur bahasa dalam bahasa lain adalah perpustakaan di Haskell), itu terlihat jauh lebih tidak menyenangkan. Menurut pendapat saya, itu sepadan, tetapi orang lain mungkin tidak setuju.
  • Beberapa orang sering mengeluh tentang kemalasan. Jika Anda tahu apa yang Anda lakukan, Anda tidak akan menyebabkan kebocoran ruang yang sulit dilacak (saya belum membuat kebocoran ruang dalam beberapa tahun sekarang), tetapi pemula memiliki lebih banyak masalah dengan ini. Akan bodoh bagi saya untuk menembak jatuh orang-orang ini dan mengklaim bahwa ini bukan masalah, tetapi saya akan menegaskan bahwa itu adalah masalah yang mudah diselesaikan dengan pengalaman.
  • Tidak banyak perpustakaan hebat untuk membuat game di Haskell, dan tidak banyak Haskeller menulis game di dalamnya, jadi sulit untuk menemukan sumber daya dan membantu dalam hal ini.

Jelek

Ini adalah hal-hal yang perlu upaya besar untuk diatasi.

  • Jika Anda menulis game yang intensif sumber daya, pemulung sampah GHC mungkin akan sangat menggigit Anda. Ini adalah generational, stop-the-world GC, jadi sesekali Anda mungkin menjatuhkan beberapa frame. Untuk beberapa gim ini tidak apa-apa, tetapi untuk gim lain itu adalah masalah besar. Saya dan beberapa pengembang game lain yang menggunakan Haskell ingin melihat soft-real-time GC diimplementasikan untuk GHC, tetapi belum ada upaya yang dilakukan untuk itu, setahu saya. Saat ini, saya tidak khawatir tentang mengatasi ini (dan belum melihat ada frame yang terjatuh dari itu), tetapi setidaknya satu tim lain telah menggunakan untuk menempatkan loop rendering utama mereka ke C.

2
Apa pendapat Anda tentang FRP?
Wei Hu

4
@Wei Hu: Saya penggemar ide FRP dan telah merisetnya sendiri secara ekstensif, termasuk membuat beberapa semantik berbeda dan menulis beberapa implementasi. Implementasi terbaik masih memiliki bug semantik dan / atau bug implementasi yang parah. Saya akan mengatakan bahwa mereka layak untuk pengembangan game, tetapi tidak dengan banyak keuntungan (belum) dari pendekatan tradisional.
Jake McArthur

1
Pengguna anonim mencoba mengedit jawaban ini dengan menghapus bagian "jelek". "Pengumpul sampah di Haskell sekarang bersamaan, paralel, dan generasional pada 2011 ( ghc.haskell.org/trac/ghc/blog/new-gc-preview )"
Jari Komppa

1
Sayangnya, itu tidak benar. GC bersamaan ternyata terlalu rumit untuk membenarkan perbaikan kecil secara keseluruhan, dan belum digabungkan.
Jake McArthur

1
@ Hai-Angel Ada backend GHC lama yang menghasilkan C, tetapi tidak berbeda dari generator kode asli atau backend LLVM. Itu masih membutuhkan runtime GHC. Juga, tidak ada yang istimewa tentang backend C yang akan membuatnya lebih mudah untuk menghindari pengumpul sampah. Jika itu sangat mudah dan murah untuk menghilangkan GC, backend lain mungkin akan melakukannya juga.
Jake McArthur

19

Saya menghabiskan tahun lalu mengembangkan mesin permainan komersial di Haskell, dan bagi kami, pengalamannya sangat positif. Dunia permainan kami sangat kompleks, dan Haskell membuatnya mudah untuk memodelkan proses konversi dari format editor ke format mesin game. Saya tidak suka berpikir seperti apa kode itu dalam bahasa imperatif.

Kebocoran antariksa telah muncul pada beberapa kesempatan, dan sementara mereka telah menyebabkan sedikit masalah, dalam skema umum jumlahnya sedikit (misalnya dibandingkan dengan menemukan deadlock di proyek Jawa dengan ukuran yang sama), dan begitu mereka diperbaiki , mereka tetap diam.

Kami menggunakan FRP mirip dengan Yampa, dan tentu saja ada kurva belajar yang terkait dengannya, tapi begitu selesai, pengalamannya sangat positif. Perpustakaan tidak menjadi masalah bagi kami - semua yang kami butuhkan telah tersedia. Penundaan pengumpulan sampah adalah masalah khusus karena itu untuk platform yang disematkan. Kami telah menggunakan beberapa C ++ untuk mengelola animasi. Kinerja juga menjadi masalah dengan ini menjadi platform tertanam (= prosesor lambat). Kami telah melakukan beberapa C dan kami juga melihat teknologi Haskell yang muncul seperti akselerasi. Animator C ++ adalah keputusan desain sejak awal dan tempat-tempat di mana kode terlalu lambat hanya area yang sangat kecil. Dalam jangka panjang, kami ingin menerjemahkan semua C kami ke Haskell.

Haskell telah membuat pekerjaan yang sulit menjadi mudah, dan semua kesulitan yang baru saja saya sebutkan sangat kecil dibandingkan dengan sejumlah besar kode kompleks yang kami hasilkan yang bersih, dapat dipelihara dan cukup banyak yang tidak bisa dipecahkan. Paralelisme akan menjadi masalah dalam pengembangan game segera, dan kami sangat baik ditempatkan untuk menghadapinya. Beberapa dari apa yang saya katakan mungkin tidak berlaku untuk proyek-proyek kecil, karena kita berada di sini untuk jangka panjang, jadi biaya awal seperti kurva belajar, dukungan perpustakaan, dll, jauh lebih sedikit dari masalah.


7
Sudah mendekati 5 tahun sejak Anda memposting jawaban ini; apakah Anda bersedia memperbaruinya? Bagaimana cara kerja mesin permainan komersial? Potongan apa yang terbukti berharga? Apakah Anda dapat memanfaatkan paralelisme seperti yang Anda harapkan?
Levi Morrison

17

Dave menyebutkan beberapa poin bagus, meskipun saya harus menunjukkan bahwa Haskell telah menyelesaikan kedua masalahnya. Statelessness dapat di-bypass menggunakan State monad (EDIT: not really - lihat di bawah untuk detailnya) , dan sequencing dapat ditangani menggunakan IO monad (EDIT: atau monad lainnya, dalam hal ini ...) .

Tantangan yang akan Anda hadapi (dan bahwa saya sudah mencoba mempelajari pemrograman game dan Haskell), lebih sesuai. (Ini semua Haskell-spesifik, karena saya benar-benar belum mendalam dengan bahasa FP lainnya.)

  • FP Learning curve: FP membutuhkan pergeseran pola pikir yang lengkap dari pemrograman berulang. Belajar berpikir dalam bentuk peta dan lipatan daripada lup membutuhkan latihan mental jika Anda tidak terbiasa.
  • Kurva belajar matematika: Haskell diberkati dan dikutuk oleh kecanggihan matematika para perancangnya, karena setelah Anda mempelajari dasar-dasar FP, Anda terjebak dengan monad, morfisme, panah, dan sejumlah pertimbangan lain yang, meski tidak sulit dalam dan dari diri mereka sendiri, sangat abstrak.
  • Monads: anak-anak anjing ini tidak terlalu sulit untuk membungkus pikiran Anda, terutama jika Anda menerima pernyataan Eric Raymond bahwa mereka adalah "peretasan untuk mengubah komposisi fungsi menjadi cara untuk memaksa urutan panggilan fungsi." Sayangnya (walaupun ini semakin baik seiring dengan meningkatnya popularitas Haskell), banyak penjelasan tentang monad mengarah pada sebagian besar programmer ("mereka monoid dalam kategori endofunctors!"), Atau pada analogi yang sama sekali tidak membantu (misalnya, , Contoh akurat dari Brent Yorgey, " monad itu seperti burrito !" Anda pikir dia bercanda? Tidak ada yang bisa mengemukakan analogi konyol dalam tutorial? Pikirkan lagi .)
  • Ekosistem: Jika Anda telah berhasil melampaui semua gundukan lain di jalan, Anda akan berdebar melawan kenyataan praktis sehari-hari bekerja dengan bahasa yang sebagian besar masih eksperimental. Tuhan membantu Anda ketika Anda tiba di sini. Di sinilah saya mulai serius untuk Scala, atau F #, atau bahasa lain di mana ada setidaknya beberapa jaminan interoperabilitas dengan perpustakaan lain. Sekali waktu, saya mendapatkan Haskell untuk menautkan dan memuat pustaka OpenGL di Windows. Itu membuat saya merasa cukup baik. Kemudian binding OpenGL dirilis kembali, dan menghancurkan semua yang telah saya lakukan. Itulah kehidupan di tanah Haskell. Jujur saja, itu bisa menyebalkan. Anda ingin pembungkus untuk mesin Bullet? Ada di Hackage - sebagai abandonwaredari November tahun lalu. Anda suka Ogre3d? Hackage hanya memiliki binding untuk sebagian dari perpustakaan . Intinya adalah bahwa jika Anda tetap menggunakan bahasa yang tidak biasa untuk pengembangan game, Anda akan menghabiskan lebih banyak waktu mengerjakan plumbing dasar daripada jika Anda hanya mengikuti kawanan dan terjebak dengan C ++.

Sisi lain dari ini adalah bahwa segala sesuatunya membaik dengan cepat. Dan itu semua tergantung pada apa yang Anda inginkan dari pengalaman itu. Anda ingin membuat game dan menaruhnya di situs web Anda untuk mencari ketenaran dan kekayaan? Tetap dengan C ++ atau Python. Tetapi jika Anda ingin mempelajari sesuatu yang baru yang mengharuskan Anda berinovasi dalam proses Anda, cobalah bahasa fungsional. Hanya memiliki banyak kesabaran terhadap diri sendiri saat Anda belajar.

Antti Salonen memiliki blog yang menarik yang merinci perselingkuhannya dengan pemrograman Haskell. Itu layak dibaca.

Sunting (satu tahun kemudian): Sekarang saya telah mempelajari Monad negara lebih banyak, saya menyadari itu bukan solusi yang sangat baik bagi negara yang dimaksudkan untuk bertahan di luar fungsi tertentu. Solusi nyata untuk kewarganegaraan ditemukan di Haskell di IOVar, ST, MVar (untuk keamanan utas), atau melalui sesuatu seperti Yampa, yang menggunakan Arrows dan FRP untuk mengelola keadaan internal yang tetap tersembunyi dari pengembang. (Daftar ini dalam urutan kesulitan, meskipun tiga yang pertama tidak terlalu sulit setelah Anda memahami monad.)


1
Beberapa pemikiran bagus di sana, bahkan jika Haskell cukup spesifik, saya pikir itu adalah pemikiran yang berlaku untuk sebagian besar bahasa pinggiran. Seperti yang Anda sebutkan secara singkat, saya pikir ini adalah tempat bahasa seperti F # memiliki potensi untuk bersinar. Menangani keadaan / UI dengan C #, misalnya, dan kemudian memiliki modul logika dalam F # untuk algoritma seperti pencarian jalur yang berpotensi, AI, dll.
McMuttons

5

Caml objektif!

Menggunakan bahasa fungsional dapat menjadi keuntungan besar di sebagian besar jenis pengembangan perangkat lunak, terutama karena mereka sangat mengurangi waktu pengembangan. Saya bisa melihat potensi besar untuk menulis server backend ke permainan, atau lapisan AI dan logika pada klien, dalam bahasa fungsional. Dan seperti semua orang tahu, LISP telah digunakan untuk skrip NPC.

Jika saya mencoba untuk menulis garis depan permainan dalam bahasa fungsional, saya pasti akan memilih Objective Caml , yang merupakan bahasa hybrid. Ini adalah keturunan ML, dan memungkinkan untuk mencampur gaya iteratif dan fungsional, memiliki sistem objektif dengan objek stateful. (Caml adalah bahasa tempat F # dimodelkan.)

Binding OpenGL tampaknya bekerja dengan sempurna dan orang-orang telah membuat game di OCaml untuk waktu yang lama. Bahasa dapat dikompilasi dan berpotensi sangat cepat (itu terkenal memenangkan C dalam beberapa tolok ukur di masa lalu, jangan bagaimana keadaan sekarang).

Ada juga banyak perpustakaan. Semuanya, mulai dari ilmu komputer hingga pengikatan ke semua jenis perpustakaan.



3

Adapun manfaatnya, periksa Clean Game Library (http://cleangl.sourceforge.net/) dan periksa game platformer. Setelah Anda memahami sintaks (saya mendorong Anda untuk mencoba) Anda akan melihat keanggunan semata-mata dari konstruk dan seberapa dekat sumber memetakan ke konsep yang mereka ekspresikan. Sebagai bonus tambahan, abstraksi negara, dan keharusan untuk secara eksplisit melewati keadaan, membuat kode Anda lebih ramah multicore.

Di sisi lain, ini membutuhkan perubahan paradigma besar. Banyak hal yang biasa Anda lakukan tanpa memikirkannya tiba-tiba tidak ada lagi dan Anda akan bingung bagaimana menyelesaikannya, hanya karena Anda berpikir dalam pola yang salah.


2

Dari sudut pandang saya, tantangan terbesar adalah:

  • Statelessness bahasa fungsional: Gagasan dalam permainan adalah bahwa setiap entitas memiliki keadaan dan keadaan ini sedang dimodifikasi dari bingkai ke bingkai. Ada mekanisme untuk meniru perilaku itu dalam beberapa bahasa (misalnya berfungsi dengan skema "!") Tetapi rasanya agak tidak wajar.
  • Urutan eksekusi : Dalam permainan beberapa bagian kode bergantung pada bagian kode lain yang harus diselesaikan sebelum dieksekusi. Bahasa fungsional umumnya tidak membuat jaminan tentang urutan eksekusi argumen fungsi. Ada cara untuk meniru perilaku ini (misalnya " (begin..." dalam skema PLT).

Jangan ragu untuk memperpanjang daftar ini (dan mungkin menambahkan beberapa poin positif ^^).


1
Urutan eksekusi dapat bervariasi dalam bahasa yang tidak ketat seperti Haskell tetapi tidak menyebabkan masalah bagi bagian kode yang bergantung pada bagian kode lainnya. Anda dapat menganggapnya sebagai evaluasi atas permintaan. Perhitungan tidak dilakukan sampai hasilnya diperlukan. Saya pikir satu-satunya cara yang mungkin menyebabkan Anda bersedih adalah dalam hal kinerja. Sebagai contoh, mungkin membuat sulit untuk mendapatkan caching yang baik dalam beberapa kasus karena Anda tidak akan memiliki kontrol atas pemesanan pada evaluasi selain menentukan dependensi antara perhitungan.
Jason Dagit

1

Anda dapat menulis kode dalam C / C ++ dan menggunakan bahasa yang disematkan seperti Embedded Common Lisp untuk skrip Anda. Meskipun mendapatkan ini untuk dikompilasi pada platform yang berbeda mungkin sulit. Anda mungkin melihat Lisp Dalam Potongan Kecil untuk mempelajari cara menulis bahasa skrip Anda sendiri. Ini benar-benar tidak sulit, jika Anda punya waktu.


0

Saya telah menulis game sederhana di LISP dan itu menyenangkan tetapi bukan sesuatu yang saya sarankan. Pemrograman fungsional adalah semua tentang hasil akhir. Jadi itu sangat berguna untuk memproses data dan membuat keputusan, tetapi saya merasa sulit untuk melakukan kode bersih sederhana seperti loop kontrol dasar.

Saya belum belajar F # jadi mungkin jauh lebih mudah untuk dikerjakan.


Pikiran awal saya mungkin menulis perancah dan penanganan negara dengan bahasa imperatif, dan kemudian melakukan logika permainan dan semacamnya dengan bit fungsional. Dengan .NET dan C # / F # ini akan sangat mudah, misalnya, karena mereka menggunakan perpustakaan yang sama dan dapat berbicara satu sama lain tanpa penalti nyata yang saya tahu.
McMuttons

-1

positif akan kinerja dan portabilitas dan negatif akan mengelola kompleksitas , permainan hari ini sangat kompleks dan membutuhkan alat atau bahasa pemrograman yang dapat mengelola kompleksitas lebih baik, seperti metodologi berorientasi objek atau pemrograman generik yang sulit diimplementasikan dalam pemrograman fungsional bahasa.


11
Apakah kamu bercanda? FP adalah pemrograman generik pada steroid. Mampu menyamaratakan tipe dan fungsi data memberi kekuatan serius pada FP untuk mengelola kompleksitas.
rtperson

Saya setuju, salah satu kekuatan terbesar FP adalah kemampuannya untuk melakukan kode umum.
McMuttons
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.