Bash’te Raycaster Uygulaması
(github.com/izabera)- Bash ile uygulanmış bir raycaster; ok tuşlarıyla dönüp hareket edilen ve
qile çıkılan, terminal tabanlı bir pseudo-3D demodur - Uygulama büyük ölçüde Lode Vandevenne’in raycasting öğreticisinin port edilmiş hâlidir; tüm matematik, kayan nokta kullanılmadan 64K ölçekli tamsayı işlemleriyle ele alınır
- En büyük kısıt Bash performansıdır; her piksel için komut çalıştırmak ya da ekran durumunu dizi/dize olarak tutmak, kare süresi içinde çıktı vermeyi zorlaştırır
- Terminal gösteriminde Unicode half block ve ön plan/arka plan 24 bit renkleri kullanılarak dikey çözünürlük fiilen iki katına çıkarılır; ancak bunun, komşu piksel renklerini birlikte bilme zorunluluğu vardır
- Mevcut yol haritasında fluid movement, decent framerate, parallel rendering, kitty keyboard protocol ve sound için ilk prototip gibi işler tamamlanmış; textures, sprites, enemies, particles, multiplayer gibi işler ise tamamlanmamıştır
Bash ile yapılmış terminal raycaster
- Bu proje Bash’te çalışan bir raycaster olup terminal içinde pseudo-3D bir ekran render eder
- Kontrollerde ok tuşlarıyla dönme ve hareket etme,
qile çıkış yapılır - Daha fazla ekran görüntüsü ve video Imgur albümünde yer alıyor
- Uygulama büyük ölçüde Lode Vandevenne’in raycasting öğreticisinin port edilmiş hâlidir
Uygulamayı zorlaştıran kısıtlar
- En büyük sorun Bash’in yavaş olmasıdır
- Her piksel için yalnızca tek bir komut çalıştırmak gerekse bile acceptable frame rate elde etmenin zor olduğunu belirtiyor
- Ekran durumunu renk dizisi olarak tutmak da sorun yaratıyor; çünkü rastgele dizi öğesine erişim doğrusal zamanda gerçekleşiyor
- Ekran durumunu tek bir uzun dize olarak tutmak da,
LANG=Caltında bile n’inci karaktere erişim doğrusal zamanda olduğundan, sadece ekrana dökmek için okumak bile bir kareden uzun sürebiliyor
- Bash’te kayan nokta desteği ve matematik fonksiyonu kütüphanelerine erişim yok
- Tüm matematik tamsayılarla yapılıyor
- Tamsayı değerler 64K ölçeğine büyütülerek hesaplanıyor
- Terminalde bir karakteri bir piksel gibi kullanmak iyi görünmediğinden Unicode half block kullanılıyor
- Ön plan ve arka plan renkleri farklı atanarak dikey çözünürlük fiilen iki katına çıkarılıyor
- Tek bir hücrede iki renkten yalnızca birini güncellemenin yolu yok
- Mevcut hücrenin rengini sorgulamanın da yolu yok; Bash’te böyle bir sorgunun kendisi de fazla yavaş
- Bu yüzden her piksel yazıldığında komşu pikselin rengini bilmek gerekiyor
Terminal ve giriş/çıkış sorunları
- Bash gibi yavaş bir dille tüm terminali tek seferde güncellemek basit değil
- Çoğu terminal video oyunları için tasarlanmadığından, o anda basılı olan tuş durumunu test etmek mümkün değil
- Genellikle yalnızca basılı tutulan tek bir tuş girdisi alınabiliyor
- Girdi tekrarı yavaş debounce ediliyor ve ardışık giriş sınırı da düşük olduğundan saniyede yaklaşık 5-6 karakter alınan durumlar oluşabiliyor
- Modifier olmayan birden fazla tuşa aynı anda basılmasını almak da zor
- kitty keyboard protocol’un bu sorunu çözdüğünü belirtiyor
- Terminali renkle doldurmak çok veri gerektiriyor
- Yazarın normal font boyutunda saniyede yaklaşık 10MB I/O oluşuyor
- Bash, birden fazla satır sonu içeren dizeleri yazdırırken tek bir syscall kullanmıyor
- Bu proje
\nyazdırmıyor; imleci başka bir yöntemle hareket ettiriyor
- Bu proje
FAQ ve çalıştırma koşulları
- Pencere boyutu değiştirildiğinde bozulma olursa, aşırı titreme varsa ya da belirli bir terminalde iyi görünmüyorsa issue açılması isteniyor
- CPU çok ısınıyorsa veya eski bir bilgisayar yavaşlıyorsa çözünürlüğün düşürülmesi ya da
FPSortam değişkeninin 30’dan küçük ayarlanması öneriliyor- Microsoft Defender’ın performansı ciddi biçimde düşürdüğü bilindiği için devre dışı bırakılması öneriliyor
- Bash 5.2 altındaki sürümlerde çalışmadığı yanıtı verilmiş
- Kod tamamen saf Bash’ten oluşmuyor
- Başlangıçta echo’yu kapatmak için bir kez
sttyçağrılıyor - Çıkışta echo’yu tekrar açmak için bir kez
sttyçağrılıyor - Çıkış sonrasında bazı istatistikler başka araçlarla toplanıyor
- Başlangıçta echo’yu kapatmak için bir kez
Yol haritası durumu
- Tamamlanan öğeler
-
semi-accurate pseudo 3d
- fluid movement
- decent framerate
- parallel rendering
- 24 bit colours
- kitty keyboard protocol
- framerate-independent speed
- sound, ancak çok erken bir prototip
- dynamic wall colours
- dynamic map; şu anda olaylar tarafından değiştirilmese de teknik olarak dinamik olduğu söyleniyor
- basic animations effects for walls
- basic on-screen minimap
- Tamamlanmamış öğeler
-
mouse support
- textures
- sprites
- objects/enemies
- particles
- better perf
- multiplayer
-
1 yorum
Hacker News yorumları
echoçalıştırmadan resmi nasıl çizdiğini merak etmiştim; yöntem çok zekice.Oyun “gerçek” 3D olmadığı için her sütun için yalnızca bir kez ışın izleme çalıştırmak ve gökyüzü, çim ve gerçek nesneye karşılık gelen birkaç satırı çizmek yeterli.
Gerekli sayı kadar “bu pikseli çiz ve bir satır aşağı in” dizgesini string tekrarı ile terminale yazdırıyor.
Bash için değil ama hesaplama kaynaklarının sınırlı olduğu başka ortamlarda bir voxel render motoru yapmayı düşünüyordum; burada kesinlikle işime yarayacak bir şey bulabilirim gibi.
VoxelCanvas.jsdosyası da ilginç olabilir. Bir JavaScript dosyası ve aynı ışın yansıtma fikrini kullanıyor: https://github.com/EngineersNeedArt/Mooncraft2000stty’nin fork gerektirmesi üzücü. Bir sonraki proje belki de Bash ve rowhammer ile gerekliioctl’u çağırıp fork’suz halletmek olur.Uygulamayı anlayacak kadar matematiğim yok ama sadece izlemek bile keyifli.
Bazı uygulamaların
vt100’ün türlü garip davranışlarına ihtiyaç duymasını anlayabiliyorum ama muhtemelen uygulamaların %90’ı sadece standart çıktıya ve standart hataya yazıyor.Metni ekrana biraz daha hızlı basabilmeli ve kalan %10’u uyumluluk moduna alabilmeliyiz diye düşünüyorum.
350 sütunluk bir terminalde bile animasyon render edebilirsiniz ve kısıtlar düşünüldüğünde gayet akıcı görünür.
Üstelik bu yazının öncülü zaten Bash’in ışın yansıtma için uygun bir dil olmadığı. CSS ile bubble sort yazmaya benziyor.
“Kalan %10’u uyumluluk moduna alalım” fikrini engelleyen bir şey yok. Dizgenin yalnızca normal karakterler içerip içermediğini kontrol edip hızlı yolu kullanabilirsiniz.
Sorun şu ki yazılım tabanlı metin render etmede aslında hızlı bir yol yok. Hâlâ ligature gibi işlemleri yapmanız gerekiyor.
Bu yüzden script yazmak için Bash kullanmamamın nedenlerinden biri de bu. Etkileşimli olarak da kullanmıyorum.
Bazı popüler Linux dağıtımları da Bash’i script shell’i olarak kullanmaktan kaçınıyor.
psuygulamasıyla birleştirip neredeyse fork’suz psDoom uygulaması yapmak güzel olurdu.Şakayı bir kenara bırakırsak, gerçekten harika.
awkışın yansıtıcıdan da onurla bahsetmek gerek: https://github.com/TheMozg/awk-raycaster/tree/master