2 puan yazan GN⁺ 2024-10-19 | 1 yorum | WhatsApp'ta paylaş
  • Common Lisp oyun geliştirme ortamı üzerinde ECS mimarisini ve metadilsel programlama tekniklerini gerçek bir dungeon crawler örneğiyle genişleten bir öğreticidir
  • Tiled XML haritasını cl-tiled ile okuduktan sonra CLOS nesnelerini doğrudan kullanmak yerine ECS bileşenlerine aktararak render, çarpışma ve bellek yönetimini ayırır
  • Tile prefab’ları, görüntü işaretçileri, ebeveyn-çocuk indeksleri ve finalizer’ları birleştirerek yinelenen yükleme ve double free sorunlarından kaçınır; Tiled özel özelliklerini veri gibi kullanır
  • Oyuncu ve düşmanlar ECS sistemleriyle hareket, animasyon geçişi ve çarpışma işlemlerini yürütür; düşmanlar cl-astar tabanlı A* yol bulma ile duvarlardan kaçınarak takip eder
  • Nuklear tabanlı UI, anlatı nesneleri, duraklatma ve kazanma koşulları da eklenerek yaklaşık 500 satırlık küçük bir dungeon crawler örneği tamamlanır

Projeye başlama ve temel çalıştırma

  • Part 1’de ele alınan Entity-Component-System mimarisi ve metadilsel programlama teknikleri kullanılarak UI’ı olan küçük bir dungeon crawler yapılır
  • Çalıştırılabilir demo ikili dosyası ve kaynak kodu ecs-tutorial-2 GitHub deposunda bulunur
  • Geliştirme ortamı, Part 1’deki Common Lisp oyun geliştirme ortamını varsayar; SBCL REPL’de Quicklisp dağıtımı güncellenir
    • (ql-util:without-prompting (ql:update-all-dists))
  • cookiecutter-lisp-game şablonuyla yeni ecs-tutorial-2 projesi oluşturulur; örnekte backend olarak liballegro seçilir
  • Proje dizini Quicklisp local-projects içine bağlandıktan sonra src/main.lisp içindeki pencere boyutu 1280×800 olarak değiştirilir
  • (ql:quickload :ecs-tutorial-2) ve (ecs-tutorial-2:main) çalıştırıldığında belirtilen çözünürlükte siyah bir pencere ve FPS sayacı görüntülenir

Tiled haritası ve ECS deposu

  • Dungeon haritası üretmek için açık kaynak harita editörü Tiled kullanılır
    • Tiled, çapraz platform ve çapraz motor bir araçtır; harita verilerini XML olarak kaydeder
    • Common Lisp’te cl-tiled, Tiled dosyalarını Lisp nesneleri olarak yükler
  • Örnek tileset olarak Dungeon Tileset II - Extended kullanılır
    • Orijinal 16×16 tile’lar küçük olduğundan ImageMagick ile %200 büyütülerek 32×32 tile olarak kullanılır
    • level1.tmx ve tileset dosyası, öğreticide sağlanan Resources.zip üzerinden alınabilir
  • ecs-tutorial-2.asd dosyasına cl-tiled bağımlılığı eklenir ve harita yükleme/görüntüleme kodunu ayırmak için yeni src/map.lisp oluşturulur
  • src/package.lisp içinde cl-tiled, tiled adlı yerel takma adla kaydedilir

CLOS nesnelerini ECS bileşenlerine taşımanın nedeni

  • cl-tiled, harita verilerini CLOS nesneleri olarak döndürdüğü için REPL’de keşfetmesi kolaydır
  • Oyun döngüsünde bu nesneleri doğrudan kullanmak runtime dispatch maliyetini artırabilir
    • 1280×800 pencereyi 32×32 tile’larla doldurmak için en az 40×25 = 1000 tile gerekir
    • Ayrı bir demoda, 12 çekirdekli Ryzen 5 3600’de harita render’ı açıldığında FPS 20.000’den 600’e düşer
    • Kare başına yaklaşık 1/600 - 1/20000 = 0.0016 saniye, yani 1,5 ms’den fazla ek yük oluşur
  • cl-tiled tarafından okunan veriler cl-fast-ecs deposuna taşındığında dispatch azaltılabilir ve CPU önbelleği kullanımı iyileştirilebilir
  • cl-fast-ecs bağımlılığı eklenir; init içinde ecs:make-storage, update içinde ecs:run-systems çağrılır

Harita, tile ve prefab bileşenleri

  • map, yüklenen harita entity’sini işaretleyen bir etiket bileşendir
  • map-tile, tekil tile’ı temsil eder ve duvar ya da kapalı kapı gibi engel durumları için obstacle Boolean slot’una sahiptir
  • parent bileşeni, tile ve harita ile ilgili nesnelerin hangi harita entity’sinin çocuğu olduğunu gösterir
    • entity slot’una :index children belirtilerek belirli bir ebeveynin çocuk entity’leri hızlıca bulunur
    • İndeks, open-address hash table tabanlı olduğundan ortalamada O(1) sorgu sağlar; ancak oluşturma ve silme sırasında güncelleme maliyeti vardır
  • ecs:*entity-deleting-hook* içine bir hook eklenerek ebeveyn entity silindiğinde children indeksiyle bulunan çocuk entity’ler de birlikte silinir
  • image bileşeni yalnızca ALLEGRO_BITMAP için bir C işaretçisi saklar
    • Tileset görüntüsü al_create_sub_bitmap ile 32×32 parçalara ayrılır ve işaretçi saklanır
  • map-tile-prefab, Tiled tile’ının global ID’si olan gid değerine sahip tile prefab’ıdır
    • gid için :index map-tile-prefab :unique t belirtilerek ID üzerinden tek bir prefab entity bulunur
    • Harita üzerindeki gerçek tile, prefab’ın image gibi bileşenlerini kopyalar; konumu ise ayrı bir position bileşeniyle tutulur
  • image finalizer’ı, yalnızca entity map-tile-prefab olduğunda al_destroy_bitmap çağırır
    • Bunun nedeni, aynı ALLEGRO_BITMAP işaretçisinin birden çok harita tile’ı tarafından paylaşılması nedeniyle double free durumundan kaçınmaktır
  • position ve size, ekran koordinatlarını ve boyutu single-float olarak saklar
    • liballegro, OpenGL uyumluluğu nedeniyle ekran koordinatlarını tek duyarlıklı kayan nokta olarak ele aldığından aynı yaklaşım izlenir

Görüntü render’ı ve harita yükleme

  • render-images sistemi, position ve image sahibi entity’leri render eder
    • al_hold_bitmap_drawing ile sprite batching açılıp kapatılır
    • al_draw_bitmap ile görüntü belirtilen koordinatlara çizilir
    • Prefab’ların position değeri olmadığından bu sistem tarafından işlenmezler
  • load-bitmap, al_load_bitmap çağrısını al:ensure-loaded ile saran bir görüntü yükleme işlevidir
  • tile->spec, tile prefab’ı oluşturmak için ECS nesne belirtimi üretir
    • Ebeveyn harita entity’si
    • Tile görüntü parçası
    • Tiled global tile ID’si
    • Tile boyutu
  • load-tile-prefab, map-tile-prefab indeksiyle prefab’ın zaten yüklenip yüklenmediğini kontrol eder; yoksa make-object ile oluşturur
  • load-tile, gerçek harita tile entity’sini oluştururken bileşenleri prefab’dan kopyalar ve position ekler
  • load-map, tiled:load-map ile okunan CLOS nesnesinden tileset’leri ve katmanları dolaşır
    • Tileset görüntüsünü yükler ve her tile’ı prefab olarak oluşturur
    • Tile katmanındaki her hücreyi entity’ye dönüştürür ve prefab verilerini kopyalar
  • Tiled’in katman sırası editördeki sırayla korunur; make-entity artan entity numaralarını garanti eder
    • Sistem eski entity’lerden başlayarak işlediği için üst katmandaki tile’lar daha sonra çizilir ve alt katmanları örter
  • Tüm tile’ları ayrı entity’ler olarak saklamak tek doğru yanıt değildir; statik haritayı önceden bir buffer’a render etmek de mümkündür

Tile animasyonları

  • Tiled animasyonlu tile’ları desteklediği için meşale veya sihirli çeşme gibi öğeler temsil edilebilir
  • Ortak bileşenleri ve animasyonla ilgili bileşen/sistemleri ayırmak için common.lisp ve animation.lisp eklendi
  • animation-frame bileşeni animasyonun tek bir karesini temsil eder
    • sequence animasyon adıdır ve keyword türünde saklanır
    • sequence-frames indeksiyle belirli bir animasyonun kareleri bulunur
    • duration saniye cinsinden kare süresidir
  • animation-state gerçek harita üzerindeki animasyonlu tile’ın mevcut durumunu saklar
    • mevcut sequence
    • mevcut frame
    • mevcut karenin duration değeri
    • mevcut karenin gösterildiği elapsed süre
  • Kare geçiş kodunu daha kısa yazmak için let-plus bağımlılığı eklendi
  • update-animations sistemi elapsed değerini dt kadar artırır ve süre aşılırsa sonraki kareye geçer
    • Kare süresi büyük bir dt değerinden küçük olabileceği için kaç karenin atlanması gerektiğini floor ile hesaplar
    • Kare numarası liste uzunluğunu aşarsa başa sarması için truncate kullanır
    • image içindeki bitmap işaretçisini sonraki kare prefab’ının bitmap’iyle değiştirir
  • Animasyon süresi Tiled’da milisaniye olarak saklandığından animation->spec içinde saniyeye dönüştürülür
  • instantiate-animation, gerçek tile entity’sinde animation-state oluşturur ve aynı animasyonların tamamen senkronize olmaması için elapsed değerini 0 ile duration arasında rastgele bir sayıyla başlatır
  • Animasyonlu tile’lar Tiled özelliği "sequence" değerine sahip olmalıdır
    • Bu özellik yoksa NIL adıyla yüklenir, beklenen animasyon adıyla bulunamaz ve tür hatasına yol açabilir

Oyuncu karakteri ve kontroller

  • character.lisp eklendi ve hareket edebilen karakterler için character bileşeni tanımlandı
    • speed saniye başına piksel cinsinden hızdır
    • target-x, target-y hareket hedef koordinatlarıdır
    • İlk hedef değerleri single-float-nan olarak ayarlanır; böylece yeni karakterler sebepsiz yere sol üste hareket etmez
  • player etiket bileşeni bit slotu ve :index player-entity :unique t kullanır
    • Bu, (player-entity 1) ile oyuncu entity’sini O(1) sürede bulmaya yönelik bir yapıdır
    • Oyuncu entity’si global değişkende saklanmaz
  • İlk uygulamada tileset’ten ork görseli kesilip player.png yapıldı ve load-player ile oyuncu hardcoded olarak oluşturuldu
    • Konum (64.0, 64.0)
    • Boyut 32×32
    • Hız 100.0
  • move-characters sistemi karakteri hedef noktaya kadar hareket ettirir
    • NaN hedef koordinatı varsa mevcut konumla başlatır
    • Kayan noktalı sayıları doğrudan karşılaştırmak yerine approx-equal kullanır
    • Yeni koordinatları atan, cos, sin, hız ve dt ile hesaplar
  • control-player sistemi W, A, S, D tuş girişlerini okuyarak hedef koordinatları günceller
    • al:with-current-keyboard-state ve al:key-down kullanır
    • Ekran sınırlarının dışına çıkılmaması için clamp kullanır
    • NaN başlatma sorununu önlemek için :after (move-characters) ile hareket sisteminden sonra çalışır

Tiled özellikleriyle çarpışma ve obje yükleme

  • Başta duvarlar zemin tile’larıyla aynı türden normal görseller olduğu için oyuncu duvarların içinden geçiyordu
  • Tiled’ın özel türleriyle map-tile sınıfı oluşturuldu ve obstacle Boolean üyesi eklendi
    • Duvar tile’larının özelliği olarak map-tile eklendi ve obstacle işaretlendi
  • properties->spec fonksiyonu Tiled özellik hash tablosunu ECS obje tanımına dönüştürür
    • Tiled özel sınıfları bileşen olarak işlenir
    • Sınıf üyeleri bileşen slotları olarak işlenir
    • Örnek biçim ((:map-tile :obstacle t)) şeklindedir
  • load-tile-prefab, properties->spec sonucunu prefab tanımına dahil eder
    • Özellik yoksa spec-adjoin ile varsayılan map-tile bileşeni eklenir ve obstacle varsayılan nil değerini alır
  • position bileşenine tile-hash slotu ve tiles indeksi eklendi
    • tile-hash, x ve y değerlerini tamsayıya çevirip tek bir 64 bit tamsayıya paketler
    • Belirli bir tile’ın sol üst koordinatındaki tüm entity’ler tiles indeksiyle bulunur
  • tile-start, herhangi bir koordinatın içinde bulunduğu grid tile’ının sol üst koordinatını döndürür
  • tile-obstacle-p, aynı koordinattaki entity’ler arasında map-tile olup obstacle değeri doğru olan bir tile bulunup bulunmadığını kontrol eder
  • obstaclep, herhangi bir koordinat için ilgili tile’ın engel olup olmadığını denetler
  • control-player, hareket yönüne göre karakter dikdörtgeninin ilgili köşe tile’larını kontrol eder ve engel varsa hedef koordinatları mevcut konuma geri alır
  • Bu çarpışma yöntemi kusursuz değildir
    • Karakter merkez koordinatını temel alan bir tasarım matematiği ve kodu basitleştirebilir; ancak örnek, karmaşıklıktan kaçınmak için mevcut yöntemi korur

Haritadan oyuncu ve animasyonlu karakter yükleme

  • Tiled’a character ve player özel sınıfları eklendi
    • character yalnızca speed float üyesine sahiptir
    • Varsayılan değerlerin kullanılması için target-x, target-y atlandı
    • player, varsayılan değeri 1 olan player int üyesine sahiptir
  • Tiled obje katmanına oyuncu karakteri tile objesi olarak yerleştirildi ve character ile player özellikleri verildi
  • load-map, tiled:object-layer işleyecek şekilde genişletildi
    • Obje özelliklerini properties->spec ile ECS bileşenlerine dönüştürür
    • tiled:tile-object, load-tile ile tile verisini ve animasyonu kopyalar, ardından konumu ayarlar
    • Tiled obje koordinatları sol altı temel aldığı için, sol üst temele uydurmak üzere y değerinden obje yüksekliği çıkarılır
  • Hardcoded load-player çağrısı ve fonksiyonu kaldırıldı
  • Bu yapı, Tiled harita verilerini doğrudan ECS objeleri olarak okuyan bir yaklaşımdır ve veri odaklı programlamaya yaklaşır
  • Karakter animasyonları, ork için orc-idle ve orc-run sekansları tileset’te tanımlanarak kullanılır
  • change-animation-sequence, entity’nin mevcut animasyonunu değiştirir
    • Zaten aynı sekanssa hiçbir şey yapmaz
    • Yeni sekansın ilk karesini sequence-frames indeksiyle bulup animation-state ve image-bitmap değerlerini günceller
  • move-characters, karakter duruyorsa :orc-idle, hareket ediyorsa :orc-run sekansına geçer

Düşmanlar, Oyun Bitti ve A* Yol Bulma

  • enemy bileşeni, düşman davranışı için gereken iki slota sahiptir
    • vision-range: oyuncuyu görüp tepki vermeye başladığı mesafe
    • attack-range: saldırı menzili
  • Oyunu sonlandırmak için *should-quit* global değişkeni eklenir; ana döngü bu değer doğruysa sona erer
  • handle-enemies sistemi, oyuncu koordinatlarını alıp düşmanlarla karşılaştırır
    • Oyuncu görüş menzilindeyse düşmanın hedef koordinatları oyuncunun konumuna ayarlanır
    • Oyuncu saldırı menzilindeyse *should-quit* doğru yapılır ve You died yerel mesaj kutusu gösterilir
  • Düşman animasyonları demon-idle, demon-run sekanslarını kullanır
    • move-characters, has-player-p sonucuna göre oyuncu için ork animasyonunu, düşman için demon animasyonunu seçer
  • Doğrudan takip yaklaşımında düşmanlar da duvarların içinden geçtiği için A* yol bulma eklenir
  • cl-astar bağımlılıklara eklenir
    • Bu kütüphane, probleme göre özelleştirilmiş en iyi yol bulma fonksiyonunu makro ile üretir
  • Yol, bileşen slotundaki bir dizi olarak saklanmaz; her yol noktası ayrı bir entity olarak temsil edilir
    • path-point, x, y, traveller alanlarına sahiptir; traveller üzerinde path-points indeksi vardır
    • path, nihai hedef olan destination-x, destination-y değerlerini saklar
    • character hedef koordinatları bir sonraki yol noktasını, path ise nihai hedefi ifade eder
  • follow-path sistemi ilk yol noktasını alıp karakteri o noktaya doğru hareket ettirir
    • Noktaya ulaşıldığında ilgili path-point entity'si silinir
    • Artık nokta kalmazsa path bileşeni silinir
  • find-path, a*:define-path-finder ile tanımlanır
    • Dünya boyutu, pencere boyutunun tile boyutuna bölünmesiyle hesaplanır
    • Row-major indeksleyici kullanılır
    • Hedefe ulaşılıp ulaşılmadığı, tile koordinatlarının aynı olup olmamasına göre belirlenir
    • Komşular 8 yönde listelenir
    • Engeller veya bir engelin üzerinden çapraz geçişler, most-positive-single-float maliyetiyle pratikte imkânsız hale getirilir
    • Heuristik olarak octile distance kullanılır
    • Mevcut bir yol varsa yol noktaları silinir ve yeni path atanır
    • Sonuç yolundaki her nokta, path-point ve parent içeren bir entity olarak oluşturulur
  • handle-enemies, düşman oyuncuyu gördüğünde mevcut yol hedefi oyuncunun konumundan farklıysa find-path çağırır
  • Değişiklikten sonra düşman, oyuncuyu kovalar ama engellerden kaçınarak hareket eder

Nuklear tabanlı oyun UI'ı

  • Anlatı öğeleri için GUI gerekir; ancak Qt veya GTK gibi geleneksel GUI kütüphaneleri, liballegro grafik bağlamına çizilen oyun UI'ları için uygun değildir
  • UI kütüphanesi olarak Nuklear kullanılır
    • liballegro ile birlikte kullanmak için Common Lisp binding'i cl-liballegro-nuklear vardır
    • Binding, deklaratif arayüz için bir DSL de sağlar
  • cl-liballegro-nuklear/declarative bağımlılığı eklenir ve yeni dosya olarak src/narrative.lisp eklenir
  • Pakete ui yerel takma adı kaydedilerek cl-liballegro-nuklear/declarative kısa şekilde referanslanır
  • UI fontu olarak Google Fonts'tan Alegreya kullanılır ve dosya adı alegreya-sc.ttf olarak değiştirilir
  • ui:defwindow narrative, anlatı penceresi fonksiyonunu tanımlar
    • Pencere konumu ekranın orta bölgesine göre hesaplanır
    • ui:label-wrap ile otomatik satır kaydırmalı metin gösterilir
    • ui:button-label "Ok", tıklandığında doğru değer döndürür
  • Nuklear bir immediate mode UI kütüphanesidir
    • Widget nesnelerini bellekte tutan retained mode yerine, her karede render ve işleme yapar
    • Buton tıklamaları callback ile değil, her karede dönüş değeri ve koşullarla işlenir
  • main.lisp, UI fontunu yükler ve nk:allegro-init ile UI context'ini başlatır
    • Event loop içinde nk:input-begin, nk:allegro-handle-event, nk:input-end çağrılır
    • Render sırasında nk:allegro-render çağrılır
    • Kapanışta nk:allegro-shutdown, nk:allegro-font-del çağrılır

UI skini ve anlatı nesneleri

  • Varsayılan UI sade olduğu için Kenney'nin fantasy-ui-borders görsel asset'leri kullanılarak stil verilir
  • *window-background*, *button-normal-background*, *button-hover-background*, *button-active-background* global değişkenlerinde UI görselleri saklanır
  • load-ui, görselleri nk:allegro-create-image ile yükler; unload-ui ise C tarafındaki görsel kaynaklarını nk:allegro-del-image ile serbest bırakır
  • init içinde load-ui çağrılır; ana döngü sonlanırken unload-ui çağrılır
  • ui:defwindow'un :styles argümanıyla arka plan, buton durumlarına göre görseller ve metin rengi belirtilir
  • narrative bileşeni, çevresel hikâye anlatımı nesnesini temsil eder
    • text: gösterilecek metin
    • shown: daha önce bir kez gösterilip gösterilmediği
    • active: mevcut pencerenin aktif olup olmadığı
    • active üzerinde active-narratives indeksi bulunur
  • show-narrative sistemi, oyuncu anlatı nesnesinin yakınındaysa pencereyi gösterir
    • Etkileşim mesafesi +interact-distance-factor+ ve oyuncunun tile boyutuyla hesaplanır
    • Pencere zaten aktifse, henüz hiç gösterilmemişse veya E tuşuna basılırsa gösterilir
    • Pencere Ok butonu, Esc, Space, Enter seçeneklerinden biriyle kapatılır
  • Tiled'da narrative özel tipi oluşturulur ve text string üyesi eklenir
  • Çarpışma algılamasıyla uyumlu olması için içinden geçilemeyen nesnelerin koordinatları tile ızgarasına hizalanmalıdır
  • Anlatı penceresi açıkken zindanın hareket etmeye devam etmesi sorunu, sistem çalıştırma koşuluyla engellenir
    • move-characters ve control-player üzerine :when (null (active-narratives t)) eklenir
    • Aktif bir anlatı varsa hareket ve kontrol sistemleri çalıştırılmaz
  • Kazanma koşulu win tag bileşeni olarak eklenir
    • narrative ile birlikte eklenmiş bir nesnede pencere kapatıldığında *should-quit* doğru yapılır ve oyun biter

Kapanış ve kapsam

  • Nihai örnek, cl-fast-ecs, cl-tiled, cl-astar, cl-liballegro-nuklear kullanarak çevresel hikâye anlatımı, düşman yapay zekası ve GUI içeren Souls-like bir dungeon crawler oluşturur
  • Uygulama boyutu yaklaşık 500 satır koddur
  • Tüm kod GitHub deposunda bulunur; eğitim kodunun yanı sıra declaim kullanılan isteğe bağlı tip bildirimlerini de içerir
  • Ses tasarımı, ara sahneler, ana menü, seviye geçişleri, “door problem” gibi konular ele alınmaz
  • Autumn Lisp Game Jam 2024, 25 Ekim 2024'te itch.io'da düzenlenir; Lisp lehçeleriyle 10 gün boyunca oyun yapıp birbirini değerlendirme ve geri bildirim verme etkinliğidir
  • Bu bölüm, Spring Lisp Game Jam 2023 katılımı Thoughtbound temel alınarak hazırlanmıştır
  • Bir sonraki bölümde ölçeği büyütüp daha gelişmiş yapay zeka ekleyerek gerçek zamanlı strateji oyunu yapma mücadelesi duyurulur

1 yorum

 
GN⁺ 2024-10-19
Hacker News yorumları
  • Keşke tüm teknik eğitimler böyle olsa. Yazının kurgusu iyi, dilbilgisi hatası neredeyse yok ve her yeni konuyu tanıtırken tam kararında açıklıyor; ayrıca tam kod örnekleri ve kodun gerçekte ne yaptığını gösteren görseller de var
    Konuyu derinlemesine ele alacak kadar uzun, ama 1. bölümü okumamış ve birkaç yıl önce Common Lisp’i birkaç ay kurcalamış biri için bile takip edilebilecek kadar bağımsız. Clojure ve Emacs Lisp ile epey uğraştım
    Bravo, awkravchuk/Andrew :^)
    (https://mxjn.me/2024/10/17/1 üzerinden de paylaşılmış)

    • En önemlisi, bunun video değil yazı olması. Kopyalayıp yapıştırabiliyorsun, net biçimde okuyabiliyorsun, kendi hızında takip edebiliyorsun ve sessizce tüketebiliyorsun
      Çevrimdışı kullanım veya arşiv için kolayca kaydedilebilmesi, not alınabilmesi ve kolay aranabilmesi de ayrı avantaj
  • Common Lisp hakkında harika bir proje ya da yazı kadar teknik tarafta insanı duygulandıran çok az şey var. Gerçekten büyük bir hediye gibi bir yazı

    1. bölüm çıktığında okumuştum ve bu bölümü okumayı da gerçekten dört gözle bekliyorum. Yazarı tebrik ederim
  • Sadece package.sh ve genel olarak 3 işletim sisteminde derleme yönetimi bile başlı başına bir ustalık dersi. Sadece GitHub deposuna göz gezdirerek bile çok şey öğrendim
    Genelde SBCL ya da LispWorks ile Common Lisp komut satırı uygulamaları derliyorum ama bir sonrakinde ECL denemeyi düşünebilirim. Hem macOS hem Linux derlemelerine sahip olmak güzel ve yeni bir şey denemek de eğlenceli olabilir

    • Yıllardır CL altyapısının üstüne bu CI yapılandırmasını kuruyorum ama durmadan bozuluyor :D
  • Çok iyi bir yazı. Lisp, daha doğrusu ClojureScript ile çok oyunculu üçüncü şahıs büyü tabanlı bir shooter geliştiriyorum. Web tabanlı bir 3D oyun ve proje için yaptığım araçlar ile soyutlamalar da dahil olmak üzere bu yolculuğu blogda yazmayı planlıyorum
    İlgilenenler için demo burada: https://wizardmasters.io

    • Jon Blow da uzun zaman önce böyle bir oyun yapmaya çalışmıştı. Nasıl ve neden başarısız olduğuna bakmak öğretici olabilir
  • Yazı gerçekten sağlam ama 1. bölümdeki kurulum sürecinin Common Lisp’in kendisi, Python, C ve birden çok aşamaya yayılması, CL’nin neden özellikle genç programcılar arasında o kadar popüler olmadığını gösteriyor gibi
    Üzücü bir durum ve keşke biri kurulum açısından dili daha erişilebilir hale getirmek için uğraşsa

    • Tam olarak aynı sorunu hedeflediğini söyleyemem ama https://ciel-lang.org/ en azından fazla çok adım olma sorununun bir kısmını çözmeye yönelik bir girişim
      Anladığım kadarıyla daha çok çok fazla seçenek olması ve eski varsayılanların demode görünmesi sorununa odaklanıyor
  • Olay döngüsü, loopun ne kadar ciddi bir yineleme için alan-özel dil olduğunu gösteren harika bir örnek. Sevseniz de sevmeseniz de ;)

    • loop yerine https://iterate.common-lisp.dev/ kullanılamaz mı? S-ifadesi olmayan tuhaf bir sözdizimi yok ve Lisp sözdizimine geri dönmek için do da gerekmiyor
      Çirkin else/end olmadan normal if/when kullanıyorsun ve genel olarak kullanışlı özellikler de ekliyor
    • Başta onunla dalga geçiyordum ama birkaç yıl Common Lisp ile programladıktan sonra loop en sevdiğim CL bileşenlerinden biri oldu
  • Bu yazı bana "Caves of Clojure"u hatırlattı: https://stevelosh.com/blog/2012/07/caves-of-clojure-01/

  • Tam da bu hafta Python ile bir roguelike geliştirmeye başlamıştım; bunu Lisp ile yapmak da güzel olabilir

  • Kendimi kandırılmış hissediyorum. Basit bir oyun yapmayı öğrenmek için geldim ama bunun yerine genel olarak bilişim hakkında inanılmaz derecede çok şey öğrenmiş oldum
    Gerçekten harika