Saf fonksiyonel programlama ve oyun durumu


12

İşlevsel bir programlama dilinde durumu (genel olarak) ele almak için ortak bir teknik var mı? Küresel durumu idare etmek için her (fonksiyonel) programlama dilinde çözümler var, ancak bundan olabildiğince kaçınmak istiyorum.

Tamamen işlevsel bir şekilde tüm durumlar fonksiyon parametreleridir. Bu yüzden, tüm oyun durumunu (dünya, oyuncular, pozisyonlar, puan, varlıklar, düşmanlar, ... ile devasa bir hashmap), belirli bir giriş veya tetikleyicide dünyayı manipüle etmek isteyen tüm işlevlere bir parametre olarak koymam gerekiyor . İşlevin kendisi, gamestate blobundan ilgili bilgileri alır, onunla bir şeyler yapar, gamestate'i manipüle eder ve gamestate'i iade eder. Ama bu sorun için kötü bir çözüm gibi görünüyor. Tüm oyun alanını tüm fonksiyonlara koyarsam, küresel değişkenlerin veya zorunlu yaklaşımın aksine benim için hiçbir faydası olmaz.

Sadece ilgili bilgileri fonksiyonlara koyabilir ve verilen girdi için yapılacak işlemleri geri gönderebilirim. Ve tek bir işlev tüm eylemleri oyun oyununa uygular. Ancak çoğu işlevin bir çok "ilgili" bilgiye ihtiyacı vardır. move()nesne pozisyonuna, hıza, çarpışma haritasına, tüm düşmanların pozisyonuna, mevcut sağlığa, ... yani bu yaklaşım da işe yaramıyor gibi görünüyor.

Öyleyse sorum şu: İşlevsel bir programlama dilinde büyük miktarda durumu nasıl ele alacağım - özellikle oyun geliştirme için?

EDIT: Clojure'da oyun oluşturmak için bazı oyun çerçeveleri var. Bu sorunu kısmen çözme yaklaşımı , oyundaki tüm nesneleri "varlıklar" olarak işleyip büyük bir torbaya koymaktır. Bir gigant ana işlevi ekranını düzenliyor ve kurum ve sap olaylar ( :on-key-down, :on-initbu varlıklar için, ...) ve ana ekran döngü çalıştırın. Ama bu aradığım temiz çözüm değil.


Bir süredir bu tür şeyleri düşünüyorum; Bana göre, işlevsel olmayan programlama işlevlerine aynı öğeleri beslemek (kabaca) zorunda olduğunuz için, bu benzersiz bir sorun olan girdi değildir . Hayır, sorun çıktı (ve sonraki ilgili güncellemeler). Giriş parametrelerinizden bazıları birleştirilmelidir; için move()muhtemelen en 'güncel' nesnesinde geçirerek edilmelidir (ya da bunun için bir tanımlayıcı) yanı sıra birinci sadece içinde hareket ve oluyor, türetmek anki konumunu ve hızını ... çıkış en azından daha sonra tüm fizik dünyası ya değiştirilen nesnelerin listesi.
Clockwork-Muse

saf işlevselliğin avantajı, fonksiyon prototiplerinin programınızın sahip olduğu tüm bağımlılıkları göstermesidir.
tp1

3
IMO, fonksiyonel diller oyun yazmak için çok uygun değildir. Bu, çözmeniz gereken birçok problemden biridir. Oyunlar, performansın çok hassas bir şekilde kontrol edilmesini gerektirir ve olayların doğal olarak gerçekleşmesi öngörülemeyen yol nedeniyle nadiren iyi eşzamanlılığa sahiptir. (Saf) işlevsel diller önemsiz bir şekilde paralelleştirilebilir ve optimize edilmesi zor olduğu için dikkate değerdir. Bir oyun yazmak ZORDUR ve ben de karmaşık (işlevsel programlama) bir şey üstlenmeden önce bunu tipik bir dilde yapmanızı öneririm.
Casey Kuball

Yanıtlar:


7

Fonksiyonel programlama dillerindeki yan etkiler ve durum, bilgisayar biliminde daha geniş bir sorundur. Onlarla daha önce karşılaşmadıysanız, belki bir göz atın monad'lara . Bununla birlikte, uyarılmalıdır: oldukça gelişmiş bir kavramdır ve tanıdığım çoğu insan (ben dahil) onları kavramak için mücadele ediyor. Farklı yaklaşımlar ve bilgi gereksinimleri ile çevrimiçi birçok, çok sayıda öğretici vardır . Şahsen, Eric Lippert'in en iyisini sevdim.

Ben hiçbir "fonksiyonel programlama" arka plana sahip olmayan bir C # programcısıyım. Duymaya devam ettiğim bu “monad” şey nedir ve benim için ne faydası var?

Monads üzerinde Eric Lippert

Dikkate alınması gereken bazı şeyler:

  • Tamamen işlevsel bir dil kullanmakta ısrar ediyor musunuz? Hem işlevsel programlamada hem de oyun geliştirmede uzmansanız, belki de onu çekebilirsiniz. (Her ne kadar faydaların çabaya değip değmeyeceğini bilmek istiyorum.)
  • İşlevsel yaklaşımı sadece gerektiğinde kullanmak daha iyi olmaz mıydı?Nesne yönelimli (veya büyük olasılıkla çok paradigma) bir dil kullanıyorsanız, bundan yararlanan bölümleri uygulamak için hiçbir şey işlevsel stili kullanmanıza engel olmaz. (MapReduce gibi, belki?)

Bazı son düşünceler:

  • Paralellik: Oyunlar do ağır kullanmak, bunun çoğu AFAIK zaten zaten GPU olur.
  • Vatansızlık: Devlet mutasyonları oyunların ayrılmaz bir parçasıdır. Onlardan kurtulmaya çalışmak meseleleri gereksiz yere karmaşıklaştırabilir.
  • Belki de ilgileniyorsanız F # işlevsel dilinin .NET nesneye yönelik ekosistemiyle nasıl oynadığına bakın.

Sonuçta, bence akademik olarak ilginç olsa bile, bu yaklaşımın pratik ve çabaya değdiğinden şüpheliyim.


Deneyiminiz olmayan bir konu hakkında neden yorum yapmalısınız? İnsanlardan gelen bir düşünce bir düşünce paradigmasında sıkışıp kalır.
Anthony Raimondo

4

Ben OOP diziyor yaklaşımlarıyla, F # (çoklu paradigma, saf olmayan, fonksiyonel birinci dil) kullanarak birkaç oyun yazdım FRP . Bu geniş bir soru, ama elimden geleni yapacağım.

İşlevsel bir programlama dilinde durumu (genel olarak) ele almak için ortak bir teknik var mı?

Tercih ettiğim yol, tüm oyunu temsil eden değişmez bir türe sahip olmak State. Sonra Stateher kene güncellenen akım için değiştirilebilir bir referans var . Bu kesinlikle saf değildir , ancak değişebilirliği tek bir yerle sınırlı tutar.

Tüm oyun alanını tüm fonksiyonlara koyarsam, küresel değişkenlerin veya zorunlu yaklaşımın aksine benim için hiçbir faydası olmaz.

Doğru değil. StateTür değiştirilemez olduğundan, dünyayı kötü tanımlanmış şekillerde mutasyona uğratan eski bir bileşene sahip olamazsınız. Bu GameObjectyaklaşım (Birlik tarafından popülerleştirilen) yaklaşımla ilgili en büyük sorunu giderir :Update çağrıların .

Globalleri kullanmanın aksine, kolayca birim test edilebilir ve paralelleştirilebilir,

Sorunu çözmek için durumun alt özelliklerini alan yardımcı işlevleri de yazmalısınız.

Örneğin:

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

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

Burada updatebütün devlet üzerinde hareket eder, ancak updateSpaceShipyalnız bir bireye SpaceShiptecrit eder.

Sadece ilgili bilgileri fonksiyonlara koyabilir ve verilen girdi için yapılacak işlemleri geri gönderebilirim.

Benim önerim Inputklavye, fare, oyun tablası vb. Durumları tutan bir tür oluşturmak olacaktır . Daha sonra, bir Stateve bir Inputsonrakini döndüren bir işlev yazabilirsiniz State:

let applyInput input state = 
  // Something

Bunun nasıl bir araya geldiğine dair bir fikir vermek için, genel oyun şöyle görünebilir:

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

Öyleyse sorum şu: İşlevsel bir programlama dilinde büyük miktarda durumu nasıl ele alacağım - özellikle oyun geliştirme için?

Basit oyunlar için yukarıdaki yaklaşımı kullanabilirsiniz (yardımcı fonksiyonlar). Daha karmaşık bir şey için, " lensleri " denemek isteyebilirsiniz .

Buradaki yorumların aksine, oyunları (saf olmayan) işlevsel bir programlama dilinde yazmayı veya en azından denemeyi şiddetle tavsiye ederim! Yineleme daha hızlı, kod tabanları daha küçük ve daha az hata yapar bulduk.

Ben de yok , bir (saf olmayan) FP dilinde yazma oyunlara monads öğrenmek gerek. Bunun nedeni, kodunuzun büyük olasılıkla engellemesi ve tek iş parçacıklı olmasıdır.

Bu çok oyunculu bir oyun yazıyorsanız özellikle doğrudur. O zaman bu yaklaşımla işler çok daha kolay hale gelecek çünkü oyun durumunu önemsiz bir şekilde seri hale getirmenize ve ağ üzerinden göndermenize izin veriyor.

Neden daha fazla oyunun bu şekilde yazılmadığına gelince ... söyleyemem. Bununla birlikte, bu tüm programlama alanlarında (belki de finans hariç) doğrudur, bu yüzden bunu fonksiyonel dillerin oyun programlamaya uygun olmadığı bir argüman olarak kullanmam.

Ayrıca iyi okumaya değer Tamamen Fonksiyonel Retrogames olduğunu .


1

Aradığın şey FRP oyun geliştirme.

Bazı Video Tanıtımları:

Çekirdek oyun mantığını tamamen işlevsel bir şekilde yapmak% 100 mümkün ve tercih edilebilir, bir bütün olarak endüstri sadece bir düşünce paradigmasına sıkışmış durumda.

Bunu Birlik içinde de yapmak mümkün.

Soruyu cevaplamak için, bir şey her hareket ettiğinde yeni bir oyun durumu güncellenecek / oluşturulacak, carmack konuşmasında söylediği gibi, bu bir sorun değil. Tamamen işlevsel, son derece bakımı kolay, esnek bir mimariden gelen bilişsel yükteki sert azalma, performansın, varsa, vurulmasını engeller.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.