Pemrograman fungsional dan kondisi permainan murni


12

Apakah ada teknik umum untuk menangani keadaan (secara umum) dalam bahasa pemrograman fungsional? Ada solusi dalam setiap bahasa pemrograman (fungsional) untuk menangani keadaan global, tetapi saya ingin menghindari ini sejauh yang saya bisa.

Semua status dengan cara fungsional murni adalah parameter fungsi. Jadi saya perlu menempatkan seluruh kondisi permainan (sebuah hashmap raksasa dengan dunia, pemain, posisi, skor, aset, musuh, ...)) sebagai parameter untuk semua fungsi yang ingin memanipulasi dunia pada input atau pemicu yang diberikan . Fungsi itu sendiri mengambil informasi yang relevan dari gumpalan gamestate, melakukan sesuatu dengannya, memanipulasi gamestate dan mengembalikan gamestate. Tapi ini sepertinya solusi yang buruk untuk masalah ini. Jika saya menempatkan keseluruhan gamestate ke semua fungsi, tidak ada manfaatnya bagi saya berbeda dengan variabel global atau pendekatan imperatif.

Saya bisa memasukkan informasi yang relevan ke dalam fungsi dan mengembalikan tindakan yang akan diambil untuk input yang diberikan. Dan satu fungsi tunggal menerapkan semua aksi ke gamestate. Tetapi sebagian besar fungsi membutuhkan banyak informasi "relevan". move()perlu posisi objek, kecepatan, peta untuk tabrakan, posisi semua musuh, kesehatan saat ini, ... Jadi pendekatan ini tampaknya tidak berhasil juga.

Jadi pertanyaan saya adalah bagaimana saya menangani sejumlah besar negara dalam bahasa pemrograman fungsional - terutama untuk pengembangan game?

EDIT: Ada beberapa kerangka kerja game untuk membangun game di Clojure. Ada pendekatan untuk memecahkan masalah ini sebagian adalah dengan memasukkan semua objek dalam game sebagai "entitas" dan memasukkannya ke dalam tas besar. Sebuah Fungsi utama gigant memegang layar dan entitas dan peristiwa menangani ( :on-key-down, :on-init, ...) untuk entitas ini dan menjalankan tampilan loop utama. Tapi ini bukan solusi bersih yang saya cari.


Saya sudah memikirkan hal semacam ini untuk sementara waktu; bagi saya, itu bukan input yang merupakan masalah unik, karena Anda masih harus memberi (kira-kira) elemen yang sama ke fungsi dalam pemrograman non-fungsional. Tidak, itu adalah output (dan pembaruan terkait berikutnya) yang menjadi masalah. Beberapa parameter input Anda harus digabungkan; karena move(), Anda mungkin harus melewati objek 'saat ini' (atau pengidentifikasi untuknya), ditambah dunia yang sedang dilaluinya, dan hanya mendapatkan posisi dan kecepatan saat ini ... output kemudian seluruh dunia fisika, atau setidaknya daftar benda yang diubah.
Clockwork-Muse

Keuntungan murni fungsional adalah prototipe fungsi menunjukkan semua dependensi yang dimiliki program Anda.
tp1

3
IMO, bahasa fungsional tidak cocok untuk menulis game. Ini adalah salah satu dari banyak masalah yang perlu Anda pecahkan. Permainan membutuhkan kontrol kinerja yang sangat tepat, dan jarang memiliki konkurensi yang baik, karena cara peristiwa yang tidak terduga dapat terjadi secara alami. Bahasa fungsional (Murni) terkenal karena dapat diparalelkan secara sepele, dan sulit untuk dioptimalkan. Sebuah permainan SULIT untuk menulis, dan saya sarankan hanya melakukannya dalam bahasa yang khas, sebelum mengambil sesuatu yang sama kompleksnya (pemrograman fungsional).
Casey Kuball

Jawaban:


7

Efek samping dan keadaan dalam bahasa pemrograman fungsional adalah masalah yang lebih luas dalam ilmu komputer. Jika Anda belum pernah menjumpai mereka sebelumnya, mungkin lihatlah monad . Namun berhati-hatilah: mereka adalah konsep yang cukup maju dan kebanyakan orang yang saya kenal (termasuk saya) berjuang untuk memahami mereka. Ada banyak, banyak tutorial online, dengan pendekatan dan persyaratan pengetahuan yang berbeda. Secara pribadi, saya suka yang terbaik dari Eric Lippert.

Saya seorang programmer C # tanpa latar belakang "pemrograman fungsional". Apa hal "monad" yang terus saya dengar, dan apa gunanya bagiku?

Eric Lippert di Monads

Beberapa hal yang perlu dipertimbangkan:

  • Apakah Anda bersikeras menggunakan bahasa yang murni fungsional? Jika Anda ahli dalam pemrograman fungsional dan pengembangan game, mungkin Anda bisa melakukannya. (Meskipun saya ingin tahu apakah manfaatnya sepadan dengan usaha.)
  • Bukankah lebih baik menggunakan pendekatan fungsional hanya jika diperlukan? Jika Anda menggunakan bahasa berorientasi objek (atau, lebih mungkin, multi-paradigma), tidak ada yang menghentikan Anda dari menggunakan gaya fungsional untuk mengimplementasikan bagian yang mendapat untung dari itu. (Agak suka MapReduce, mungkin?)

Beberapa pemikiran terakhir:

  • Paralelisme: Meskipun game memang sering menggunakannya, sebagian besar AFAIK sudah terjadi pada GPU.
  • Statelessness: Mutasi negara adalah bagian integral dari permainan. Mencoba untuk menyingkirkan mereka mungkin hanya memperumit masalah yang tidak perlu.
  • Mungkin lihat bagaimana bahasa fungsional F # bermain dengan ekosistem berorientasi objek. NET, jika Anda tertarik.

Secara keseluruhan, saya pikir bahkan jika itu bisa menarik secara akademis, saya ragu pendekatan ini praktis dan sepadan dengan usaha.


Mengapa memposting komentar tentang topik yang tidak Anda alami? Pendapat yang datang dari orang-orang yang terjebak dalam satu paradigma berpikir.
Anthony Raimondo

4

Saya telah menulis beberapa game menggunakan F # (multi-paradigma, tidak murni, bahasa fungsional-pertama), dengan pendekatan mulai dari OOP ke FRP . Ini adalah pertanyaan luas, tetapi saya akan melakukan yang terbaik.

Apakah ada teknik umum untuk menangani keadaan (secara umum) dalam bahasa pemrograman fungsional?

Cara pilihan saya adalah memiliki jenis yang tidak dapat diubah yang mewakili seluruh permainan State. Saya kemudian memiliki referensi yang bisa berubah ke arus Stateyang diperbarui setiap centang. Ini tidak sepenuhnya murni, tetapi menjaga mutabilitas terbatas pada satu tempat.

Jika saya menempatkan keseluruhan gamestate ke semua fungsi, tidak ada manfaatnya bagi saya berbeda dengan variabel global atau pendekatan imperatif.

Tidak benar. Karena Statetipe ini tidak dapat diubah, Anda tidak dapat memiliki komponen lama yang mengubah dunia dengan cara yang tidak jelas. Ini memperbaiki masalah terbesar dengan GameObjectpendekatan (dipopulerkan oleh Unity): sulit untuk mengontrol urutan Updatepanggilan.

Dan tidak seperti menggunakan global, ia mudah diuji unit dan diparalelkan,

Anda juga harus menulis fungsi pembantu yang menerima sub-properti negara untuk memecah masalah.

Sebagai contoh:

let updateSpaceShip ship = 
  {
    ship with 
      Position = ship.Position + ship.Velocity
  }

let update state = 
  { 
    state with 
      SpaceShips = state.SpaceShips |> map updateSpaceShip 
  }

Di sini updatebertindak pada seluruh negara, tetapi updateSpaceShiphanya bertindak pada individu SpaceShipsecara terpisah.

Saya bisa memasukkan informasi yang relevan ke dalam fungsi dan mengembalikan tindakan yang akan diambil untuk input yang diberikan.

Saran saya adalah membuat Inputjenis yang memegang papan ketik, mouse, game-pad, dll. Anda kemudian dapat menulis fungsi yang mengambil Statedan Inputmengembalikan yang berikutnya State:

let applyInput input state = 
  // Something

Untuk memberi Anda gambaran tentang bagaimana hal ini cocok, keseluruhan permainan mungkin terlihat seperti ini:

let mutable state = initialState ()

// Game loop
while true do
  // Apply user input to the world
  let input = collectInput ()

  state <- applyInput input state

  // Game logic
  let dt = computeDeltaTime ()

  state <- update dt state

  // Draw
  render state

Jadi pertanyaan saya adalah bagaimana saya menangani sejumlah besar negara dalam bahasa pemrograman fungsional - terutama untuk pengembangan game?

Untuk gim sederhana, Anda dapat menggunakan pendekatan di atas (fungsi pembantu). Untuk sesuatu yang lebih rumit, Anda mungkin ingin mencoba " lensa ".

Berlawanan dengan beberapa komentar di sini, saya sangat menyarankan untuk menulis game dalam bahasa pemrograman fungsional (tidak murni), atau setidaknya mencobanya! Saya menemukan ini membuat iterasi lebih cepat, basis kode lebih kecil dan bug lebih jarang.

Saya juga tidak berpikir Anda perlu belajar monad untuk menulis game dalam bahasa FP (tidak murni). Ini karena kode Anda kemungkinan besar akan memblokir dan berulir tunggal.

Ini terutama benar jika Anda menulis game multi-pemain. Maka hal-hal akan menjadi lebih mudah dengan pendekatan ini karena memungkinkan Anda untuk membuat serialisasi keadaan gim secara sepele dan mengirimkannya ke seluruh jaringan.

Adapun mengapa lebih banyak game tidak ditulis dengan cara ini ... Saya tidak bisa bilang. Namun, ini berlaku di semua domain pemrograman (kecuali mungkin keuangan), jadi saya tidak akan menggunakan ini sebagai argumen bahwa bahasa fungsional tidak cocok untuk pemrograman game.

Juga layak dibaca adalah Purg Fungsional Retrogames .


1

Apa yang Anda cari adalah pengembangan game FRP.

Beberapa Perkenalan Video:

Ini 100% mungkin dan lebih baik untuk membuat logika permainan inti dengan cara yang sepenuhnya fungsional, industri secara keseluruhan hanya tertinggal, terjebak dalam satu paradigma pemikiran.

Mungkin untuk melakukannya di Unity juga.

Untuk menjawab pertanyaan, status permainan baru akan diperbarui / dibuat setiap kali sesuatu bergerak, seperti yang dikatakan carmack dalam ceramahnya, itu bukan masalah. Pengurangan drastis dalam overhead kognitif yang berasal dari arsitektur fungsional murni, sangat dapat dipelihara, jauh cara kinerja hit, jika ada sama sekali.

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.