2 पॉइंट द्वारा GN⁺ 2024-10-19 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Common Lisp गेम डेवलपमेंट environment पर ECS आर्किटेक्चर और meta-linguistic programming को एक वास्तविक dungeon crawler उदाहरण तक विस्तार देने वाला ट्यूटोरियल है
  • Tiled XML मैप को cl-tiled से पढ़ने के बाद CLOS objects को सीधे इस्तेमाल करने के बजाय उन्हें ECS components में बदलकर rendering, collision और memory management को अलग किया गया है
  • tile prefab, image pointer, parent-child index और finalizer को मिलाकर duplicate loading और double free से बचा गया है, और Tiled custom properties को data की तरह इस्तेमाल किया गया है
  • player और enemy, ECS systems के जरिए movement, animation switching और collision handling करते हैं, जबकि enemy cl-astar आधारित A* pathfinding से दीवारों से बचते हुए पीछा करता है
  • Nuklear आधारित UI, narrative objects, pause और victory condition तक जोड़कर लगभग 500 lines का एक छोटा dungeon crawler उदाहरण पूरा किया गया है

प्रोजेक्ट की शुरुआत और बेसिक रन

  • Part 1 में कवर किए गए Entity-Component-System आर्किटेक्चर और meta-linguistic programming तकनीकों का इस्तेमाल करके UI वाला एक छोटा dungeon crawler बनाया जाता है
  • executable demo binary और source code ecs-tutorial-2 GitHub repository में हैं
  • development environment, Part 1 के Common Lisp गेम डेवलपमेंट environment को मानकर चलता है, और SBCL REPL में Quicklisp distribution को अपडेट किया जाता है
    • (ql-util:without-prompting (ql:update-all-dists))
  • cookiecutter-lisp-game template से नया project ecs-tutorial-2 बनाया जाता है, और उदाहरण में backend के रूप में liballegro चुना गया है
  • project directory को Quicklisp local-projects से जोड़ने के बाद src/main.lisp की window size को 1280×800 में बदला जाता है
  • (ql:quickload :ecs-tutorial-2) और (ecs-tutorial-2:main) चलाने पर तय resolution वाली काली window और FPS counter दिखाई देता है

Tiled मैप और ECS storage

  • dungeon map बनाने के लिए open source map editor Tiled का उपयोग किया गया है
    • Tiled एक cross-platform·cross-engine tool है, और map data को XML में सेव करता है
    • Common Lisp में cl-tiled, Tiled files को Lisp objects के रूप में लोड करता है
  • उदाहरण tileset के लिए Dungeon Tileset II - Extended का उपयोग किया गया है
    • मूल 16×16 tiles छोटे होने की वजह से ImageMagick से 200% बड़ा करके उन्हें 32×32 tiles के रूप में इस्तेमाल किया गया है
    • level1.tmx और tileset files, ट्यूटोरियल में दिए गए Resources.zip से प्राप्त किए जा सकते हैं
  • ecs-tutorial-2.asd में cl-tiled dependency जोड़ी जाती है, और src/map.lisp नया बनाकर map loading और display code को अलग किया जाता है
  • src/package.lisp में cl-tiled को tiled नाम के local nickname के रूप में रजिस्टर किया जाता है

CLOS objects को ECS components में बदलने की वजह

  • cl-tiled, map data को CLOS objects के रूप में लौटाता है, इसलिए REPL में उन्हें देखना आसान होता है
  • अगर game loop में इन objects को सीधे इस्तेमाल किया जाए, तो runtime dispatch cost बढ़ सकती है
    • 1280×800 window को 32×32 tiles से भरने के लिए कम से कम 40×25 = 1000 tiles चाहिए
    • एक अलग demo में, 12-core Ryzen 5 3600 पर map rendering चालू करने पर FPS 20,000 से 600 तक गिर जाता है
    • यानी प्रति frame लगभग 1/600 - 1/20000 = 0.0016 सेकंड, यानी 1.5ms से अधिक अतिरिक्त लगता है
  • cl-tiled से पढ़े गए data को cl-fast-ecs storage में ले जाने से dispatch कम किया जा सकता है और CPU cache उपयोग बेहतर हो सकता है
  • cl-fast-ecs dependency जोड़ी जाती है, और init में ecs:make-storage, update में ecs:run-systems कॉल किया जाता है

मैप, टाइल और prefab components

  • map, लोड किए गए map entity को दर्शाने वाला एक tag component है
  • map-tile, अलग-अलग tiles को दर्शाता है, और दीवार या बंद दरवाज़े जैसी बाधा होने या न होने के लिए obstacle Boolean slot रखता है
  • parent component यह दिखाता है कि tile और map से जुड़े objects किस map entity के child हैं
    • entity slot में :index children देकर किसी खास parent के child entities को जल्दी खोजा जाता है
    • index, open-address hash table पर आधारित है, इसलिए औसतन O(1) lookup देता है, लेकिन create/delete के समय update cost होती है
  • ecs:*entity-deleting-hook* में hook जोड़कर यह सुनिश्चित किया जाता है कि parent entity delete होने पर children index से मिले child entities भी साथ में delete हो जाएँ
  • image component, ALLEGRO_BITMAP के लिए केवल C pointer स्टोर करता है
    • tileset image के 32×32 टुकड़े al_create_sub_bitmap से बनाए जाते हैं और उनके pointers स्टोर किए जाते हैं
  • map-tile-prefab, Tiled tile की global ID gid रखने वाला tile prefab है
    • gid पर :index map-tile-prefab :unique t देकर ID से एक single prefab entity खोजी जाती है
    • map पर मौजूद असली tiles, prefab से image जैसे components कॉपी करते हैं, लेकिन position अलग position component में रखते हैं
  • image finalizer केवल तब al_destroy_bitmap कॉल करता है जब entity map-tile-prefab हो
    • क्योंकि कई map tiles एक ही ALLEGRO_BITMAP pointer साझा करते हैं, इसलिए double free से बचना ज़रूरी है
  • position और size, screen coordinates और आकार को single-float के रूप में स्टोर करते हैं
    • liballegro, OpenGL compatibility की वजह से screen coordinates को single-precision floating point में संभालता है, इसलिए वही तरीका अपनाया गया है

image rendering और map loading

  • render-images system, position और image वाले entities को render करता है
    • al_hold_bitmap_drawing से sprite batching चालू और बंद किया जाता है
    • al_draw_bitmap से तय coordinates पर image draw की जाती है
    • prefab में position नहीं होता, इसलिए इस system में उसे प्रोसेस नहीं किया जाता
  • load-bitmap, al_load_bitmap को al:ensure-loaded से wrap करने वाला image loading function है
  • tile->spec, tile prefab बनाने के लिए ECS object specification तैयार करता है
    • parent map entity
    • tile image slice
    • Tiled global tile ID
    • tile size
  • load-tile-prefab, map-tile-prefab index से जाँचता है कि prefab पहले से लोड है या नहीं, और न होने पर make-object से बनाता है
  • load-tile, असली map tile entity बनाते समय prefab से components कॉपी करता है और position जोड़ता है
  • load-map, tiled:load-map से पढ़े गए CLOS objects में tilesets और layers पर iterate करता है
    • tileset images लोड करके हर tile के लिए prefab बनाया जाता है
    • tile layer की हर cell को entity बनाकर prefab data कॉपी किया जाता है
  • Tiled में layer order editor के order के अनुसार बना रहता है, और make-entity बढ़ते हुए entity numbers की गारंटी देता है
    • system पुराने entities को पहले प्रोसेस करता है, इसलिए ऊपर वाली layer के tiles बाद में draw होकर नीचे वाली layer को ढक लेते हैं
  • हर tile को अलग entity के रूप में स्टोर करना ही एकमात्र तरीका नहीं है; static map को buffer में पहले से render करने का तरीका भी संभव है

टाइल एनीमेशन

  • Tiled एनीमेटेड टाइल्स को सपोर्ट करता है, इसलिए मशाल या जादुई फव्वारे जैसे एलिमेंट्स दिखाए जा सकते हैं
  • common.lisp और animation.lisp जोड़कर common components और animation-संबंधित components·systems को अलग किया गया है
  • animation-frame component एनीमेशन के एक फ्रेम को दर्शाता है
    • sequence एनीमेशन का नाम है और इसे keyword type में स्टोर किया जाता है
    • sequence-frames index से किसी खास एनीमेशन के फ्रेम्स खोजे जाते हैं
    • duration सेकंड में फ्रेम की अवधि है
  • animation-state मैप पर मौजूद एनीमेटेड टाइल की वर्तमान स्थिति स्टोर करता है
    • वर्तमान sequence
    • वर्तमान frame
    • वर्तमान फ्रेम duration
    • वर्तमान फ्रेम के दिखाए जाने का elapsed समय
  • let-plus dependency जोड़कर फ्रेम बदलने वाला कोड अधिक संक्षिप्त लिखा गया है
  • update-animations system dt जितना elapsed बढ़ाता है, और अवधि पार होने पर अगले फ्रेम पर स्विच करता है
    • क्योंकि फ्रेम समय बड़े dt से छोटा हो सकता है, इसलिए floor से यह निकाला जाता है कि कितने फ्रेम्स स्किप करने हैं
    • truncate से फ्रेम नंबर लिस्ट की लंबाई से आगे निकलने पर फिर शुरुआत पर घुमाया जाता है
    • image का bitmap pointer अगले फ्रेम prefab के bitmap से बदल दिया जाता है
  • एनीमेशन अवधि Tiled में milliseconds में स्टोर होती है, इसलिए animation->spec में इसे सेकंड में बदला जाता है
  • instantiate-animation असली टाइल entity पर animation-state बनाता है, और ताकि वही एनीमेशन पूरी तरह sync न हों, elapsed को 0 और duration के बीच एक random value से initialize किया जाता है
  • एनीमेशन टाइल्स में Tiled property "sequence" होना चाहिए
    • यह property न हो तो वह NIL नाम से लोड होगी, अपेक्षित एनीमेशन नाम से नहीं मिलेगी, और type error हो सकता है

प्लेयर कैरेक्टर और नियंत्रण

  • character.lisp जोड़ा गया है, और चल सकने वाले कैरेक्टर्स के लिए character component परिभाषित किया गया है
    • speed प्रति सेकंड pixels की गति है
    • target-x, target-y चलने के लक्ष्य coordinates हैं
    • शुरुआती target values को single-float-nan रखा गया है ताकि नया कैरेक्टर बिना वजह ऊपर-बाएँ कोने की ओर न चल पड़े
  • player tag component bit slot और :index player-entity :unique t का उपयोग करता है
    • यह (player-entity 1) से प्लेयर entity को O(1) में खोजने की संरचना है
    • प्लेयर entity को global variable में स्टोर नहीं किया जाता
  • शुरुआती implementation में tileset से orc image काटकर player.png बनाया गया और load-player से प्लेयर को hardcode करके बनाया गया
    • स्थान (64.0, 64.0)
    • आकार 32×32
    • गति 100.0
  • move-characters system कैरेक्टर्स को लक्ष्य बिंदु तक चलाता है
    • यदि लक्ष्य coordinates NaN हों तो उन्हें वर्तमान स्थान से initialize किया जाता है
    • floating-point की direct comparison के बजाय approx-equal का उपयोग किया जाता है
    • atan, cos, sin, speed, और dt से नए coordinates निकाले जाते हैं
  • control-player system W, A, S, D key input पढ़कर लक्ष्य coordinates अपडेट करता है
    • al:with-current-keyboard-state और al:key-down का उपयोग करता है
    • clamp से स्क्रीन सीमा के बाहर जाने से रोका जाता है
    • :after (move-characters) के साथ इसे movement system के बाद चलाया जाता है ताकि NaN initialization समस्या से बचा जा सके

Tiled properties से collision और object loading

  • शुरुआत में दीवारें फर्श टाइल्स जैसी सामान्य images थीं, इसलिए प्लेयर दीवारों के आर-पार चला जाता था
  • Tiled के custom type से map-tile class बनाई गई और obstacle Boolean member जोड़ा गया
    • दीवार टाइल की property में map-tile जोड़ा गया और obstacle को check किया गया
  • properties->spec function Tiled property hash table को ECS object spec में बदलता है
    • Tiled custom classes को components की तरह handle किया जाता है
    • class members को component slots की तरह handle किया जाता है
    • उदाहरण ((:map-tile :obstacle t)) के रूप में है
  • load-tile-prefab में properties->spec के परिणाम को prefab spec में शामिल किया जाता है
    • properties न हों तो spec-adjoin से default map-tile component जोड़ा जाता है और obstacle की default value nil रहती है
  • position component में tile-hash slot और tiles index जोड़े गए हैं
    • tile-hash x, y को integer में बदलने के बाद एक 64-bit integer में pack करता है
    • किसी खास टाइल के ऊपर-बाएँ coordinates पर मौजूद सभी entities को tiles index से खोजा जाता है
  • tile-start किसी भी coordinate के शामिल grid tile का ऊपर-बाएँ coordinate लौटाता है
  • tile-obstacle-p यह जांचता है कि उसी coordinate की entities में कोई map-tile है या नहीं, और उसका obstacle true है या नहीं
  • obstaclep किसी भी coordinate के लिए जांचता है कि संबंधित टाइल obstacle है या नहीं
  • control-player movement direction के अनुसार character rectangle के संबंधित corner tiles की जांच करता है, और obstacle होने पर लक्ष्य coordinate को वर्तमान स्थान पर वापस कर देता है
  • यह collision तरीका पूरी तरह परिपूर्ण नहीं है
    • अगर character center coordinate के आधार पर डिजाइन किया जाए तो math और code सरल हो सकते हैं, लेकिन उदाहरण जटिलता से बचने के लिए मौजूदा तरीका ही रखता है

मैप से प्लेयर और एनीमेटेड कैरेक्टर्स लोड करना

  • Tiled में character और player custom classes जोड़ी गई हैं
    • character में केवल speed float member है
    • target-x, target-y को default values इस्तेमाल करने के लिए छोड़ा गया है
    • player में default value 1 वाला player int member है
  • Tiled object layer में tile object के रूप में प्लेयर कैरेक्टर रखा जाता है, और उसे character तथा player properties दी जाती हैं
  • load-map को tiled:object-layer भी process करने के लिए विस्तारित किया गया है
    • object properties को properties->spec से ECS components में बदला जाता है
    • tiled:tile-object load-tile के जरिए tile data और animation कॉपी करता है और position सेट करता है
    • Tiled object coordinates नीचे-बाएँ आधार पर होते हैं, इसलिए y से object height घटाकर उसे ऊपर-बाएँ आधार के अनुसार मिलाया जाता है
  • hardcoded load-player call और function हटा दिए गए हैं
  • यह संरचना Tiled map data को सीधे ECS objects के रूप में पढ़ती है, और data-driven programming के अधिक करीब हो जाती है
  • character animation के लिए tileset में orc के orc-idle और orc-run sequences परिभाषित करके इस्तेमाल किए जाते हैं
  • change-animation-sequence entity की वर्तमान animation बदलता है
    • अगर sequence पहले से वही हो तो कोई काम नहीं करता
    • नई sequence का पहला frame sequence-frames index से खोजकर animation-state और image-bitmap अपडेट किया जाता है
  • move-characters कैरेक्टर रुकने पर :orc-idle, और चलने पर :orc-run में स्विच करता है

दुश्मन, गेम ओवर, A* पाथफाइंडिंग

  • enemy कंपोनेंट में दुश्मन के व्यवहार के लिए दो स्लॉट होते हैं
    • vision-range: वह दूरी जहाँ से दुश्मन खिलाड़ी को देखकर प्रतिक्रिया शुरू करता है
    • attack-range: हमला करने की रेंज
  • गेम समाप्त करने के लिए *should-quit* global variable जोड़ा जाता है, और main loop यह मान सच होने पर समाप्त हो जाता है
  • handle-enemies सिस्टम खिलाड़ी के coordinates लेकर उन्हें दुश्मनों से तुलना करता है
    • अगर खिलाड़ी vision range में है, तो दुश्मन के target coordinates खिलाड़ी की position पर सेट किए जाते हैं
    • अगर खिलाड़ी attack range में है, तो *should-quit* को true सेट किया जाता है और You died native message box दिखाया जाता है
  • दुश्मन animation के लिए demon-idle, demon-run sequences का उपयोग होता है
    • move-characters has-player-p के परिणाम के आधार पर खिलाड़ी के लिए orc animation और दुश्मनों के लिए demon animation चुनता है
  • सीधे पीछा करने के तरीके में दुश्मन दीवारों के आर-पार भी चले जाते हैं, इसलिए A* पाथफाइंडिंग जोड़ी जाती है
  • cl-astar को dependency के रूप में जोड़ा जाता है
    • यह लाइब्रेरी समस्या के अनुसार optimized pathfinding functions को macro के रूप में generate करती है
  • path को component slot के अंदर array के रूप में रखने के बजाय, हर path point को अलग entity के रूप में दर्शाया जाता है
    • path-point में x, y, traveller होते हैं, और traveller में path-points index होता है
    • path अंतिम destination destination-x, destination-y को store करता है
    • character के target coordinates अगले path point को दर्शाते हैं, जबकि path अंतिम destination को दर्शाता है
  • follow-path सिस्टम पहला path point लेकर character को उस point तक move कराता है
    • point पर पहुँचने पर संबंधित path-point entity हटा दी जाती है
    • अगर आगे कोई point नहीं बचता, तो path component हटा दिया जाता है
  • find-path को a*:define-path-finder से define किया जाता है
    • world size की गणना window size को tile size से भाग देकर की जाती है
    • row-major indexer का उपयोग होता है
    • target तक पहुँचना tile coordinates के समान होने से तय किया जाता है
    • neighbors को 8 दिशाओं में enumerate किया जाता है
    • obstacles या obstacle को काटते हुए diagonal movement को most-positive-single-float cost देकर व्यावहारिक रूप से असंभव बना दिया जाता है
    • heuristic के लिए octile distance का उपयोग होता है
    • अगर पुराना path मौजूद है, तो उसके path points हटा दिए जाते हैं और नया path assign किया जाता है
    • result path के हर point के लिए path-point और parent वाले entities बनाए जाते हैं
  • handle-enemies में जब दुश्मन खिलाड़ी को देखता है और मौजूदा path destination खिलाड़ी की position से अलग होती है, तो find-path को call किया जाता है
  • बदलाव के बाद दुश्मन खिलाड़ी का पीछा करते हैं, लेकिन obstacles से बचते हुए चलते हैं

Nuklear-आधारित गेम UI

  • narrative elements के लिए GUI की जरूरत होती है, लेकिन Qt या GTK जैसी पारंपरिक GUI libraries liballegro graphics context पर draw होने वाले game UI के लिए उपयुक्त नहीं हैं
  • UI library के रूप में Nuklear का उपयोग किया जाता है
    • liballegro के साथ उपयोग के लिए Common Lisp binding cl-liballegro-nuklear उपलब्ध है
    • binding declarative interface के लिए DSL भी प्रदान करती है
  • cl-liballegro-nuklear/declarative dependency जोड़ी जाती है, और src/narrative.lisp को नई file के रूप में जोड़ा जाता है
  • package में ui local nickname register किया जाता है ताकि cl-liballegro-nuklear/declarative को छोटे रूप में refer किया जा सके
  • UI font के रूप में Google Fonts की Alegreya का उपयोग होता है, और filename को alegreya-sc.ttf में बदला जाता है
  • ui:defwindow narrative narrative window function define करता है
    • window position स्क्रीन के central area के रूप में calculate की जाती है
    • ui:label-wrap से automatic line wrapping वाला text दिखाया जाता है
    • ui:button-label "Ok" click होने पर true return करता है
  • Nuklear एक immediate mode UI library है
    • retained mode की तरह widget objects को memory में बनाए रखने के बजाय, यह हर frame rendering और processing करता है
    • button click को callback से नहीं, बल्कि हर frame के return value और conditions से handle किया जाता है
  • main.lisp UI font load करता है और nk:allegro-init से UI context initialize करता है
    • event loop में nk:input-begin, nk:allegro-handle-event, nk:input-end को call किया जाता है
    • rendering के समय nk:allegro-render को call किया जाता है
    • समाप्ति पर nk:allegro-shutdown, nk:allegro-font-del को call किया जाता है

UI skin और narrative objects

  • default UI साधारण लगती है, इसलिए Kenney के fantasy-ui-borders image assets का उपयोग करके उसे style किया जाता है
  • *window-background*, *button-normal-background*, *button-hover-background*, *button-active-background* global variables में UI images store की जाती हैं
  • load-ui nk:allegro-create-image से images load करता है, और unload-ui nk:allegro-del-image से C side image resources release करता है
  • init में load-ui को call किया जाता है, और main loop समाप्त होने पर unload-ui को call किया जाता है
  • ui:defwindow के :styles argument से background, button state के अनुसार images, और text color specify किए जाते हैं
  • narrative component environmental storytelling के objects को दर्शाता है
    • text: दिखाया जाने वाला text
    • shown: क्या यह पहले एक बार दिखाया जा चुका है
    • active: क्या अभी window सक्रिय है
    • active में active-narratives index होता है
  • show-narrative सिस्टम तब window दिखाता है जब खिलाड़ी narrative object के पास होता है
    • interaction distance की गणना +interact-distance-factor+ और खिलाड़ी के tile size से की जाती है
    • अगर window पहले से active हो, या अभी तक कभी न दिखाई गई हो, या E key दबाई गई हो, तो उसे दिखाया जाता है
    • Ok button, Esc, Space, Enter में से किसी एक से window बंद की जाती है
  • Tiled में narrative custom type बनाया जाता है और text string member जोड़ा जाता है
  • collision detection और alignment के लिए non-passable objects के coordinates को tile grid पर align होना चाहिए
  • narrative window खुली होने पर dungeon के चलते रहने की समस्या को system execution condition से रोका जाता है
    • move-characters और control-player में :when (null (active-narratives t)) जोड़ा जाता है
    • active narrative होने पर movement और control systems execute नहीं होते
  • victory condition को win tag component से जोड़ा जाता है
    • narrative के साथ लगे object में window बंद होने पर *should-quit* को true सेट किया जाता है और गेम समाप्त हो जाता है

समापन और दायरा

  • अंतिम example cl-fast-ecs, cl-tiled, cl-astar, cl-liballegro-nuklear का उपयोग करके environmental storytelling, enemy AI, और GUI वाला Souls-like dungeon crawler बनाता है
  • implementation का आकार लगभग 500 lines of code है
  • पूरा code GitHub repository में उपलब्ध है, और tutorial code के अलावा declaim का उपयोग करने वाली optional type declarations भी शामिल हैं
  • sound design, cutscenes, main menu, level transitions, और “door problem” जैसे विषय शामिल नहीं हैं
  • Autumn Lisp Game Jam 2024, 25 अक्टूबर 2024 को itch.io पर आयोजित होगा; यह एक ऐसा event है जिसमें Lisp dialects में 10 दिनों तक game बनाकर एक-दूसरे को rate, feedback और review दिया जाता है
  • यह भाग Spring Lisp Game Jam 2023 की entry Thoughtbound पर आधारित है
  • अगले भाग में स्केल बढ़ाकर और अधिक उन्नत AI जोड़कर real-time strategy game बनाने की चुनौती का संकेत दिया गया है

1 टिप्पणियां

 
GN⁺ 2024-10-19
Hacker News की राय
  • काश सभी tech tutorials ऐसे ही होते। लेख की संरचना अच्छी है, grammar errors भी लगभग नहीं हैं, हर नए विषय को पेश करते समय ठीक उतनी ही व्याख्या दी गई है जितनी चाहिए, और इसमें पूरा code example के साथ-साथ code असल में क्या कर रहा है, यह दिखाने वाले visuals भी हैं
    सामग्री को गहराई से कवर करने के लिए यह पर्याप्त लंबा है, लेकिन इतना standalone भी है कि अगर आपने Part 1 नहीं पढ़ा और कुछ साल पहले Common Lisp को बस कुछ महीनों तक छुआ था, तब भी साथ चल सकते हैं। मैंने Clojure और Emacs Lisp काफी किया है
    Bravo, awkravchuk/Andrew :^)
    (Crossposted from https://mxjn.me/2024/10/17/1)

    • सबसे बड़ी बात यह है कि यह video नहीं, text है। इसे copy-paste किया जा सकता है, साफ़ पढ़ा जा सकता है, अपनी speed से follow किया जा सकता है, और चुपचाप consume किया जा सकता है
      Offline इस्तेमाल या archive के लिए इसे आसानी से save और annotate किया जा सकता है, और search करना भी आसान है
  • Common Lisp पर कोई शानदार project या लेख जितना tech में दिल छूता है, वैसा बहुत कम होता है। यह सच में एक बड़ा तोहफ़ा जैसा लेख है
    Part 1 आने पर मैंने पढ़ा था, और इस part को पढ़ने के लिए भी बहुत उत्साहित हूँ। लेखक को सलाम

  • package.sh और कुल मिलाकर 3 operating systems के build management अपने आप में एक masterclass हैं। GitHub repository को बस सरसरी तौर पर देखने से ही बहुत कुछ सीखा
    आम तौर पर मैं SBCL या LispWorks से Common Lisp command-line apps build करता हूँ, लेकिन अगली बार ECL से भी कर सकता हूँ। macOS और Linux दोनों builds होना बढ़िया है, और कुछ नया try करने में भी मज़ा आएगा

    • वे कई सालों से CL infrastructure के ऊपर वह CI setup बना रहे हैं, लेकिन कहते हैं कि वह लगातार टूटता रहता है :D
  • बहुत अच्छा लेख है। मैं Lisp, यानी ठीक-ठीक कहें तो ClojureScript में multiplayer third-person spell-based shooter बना रहा हूँ। यह web-based 3D game है, और project के लिए बनाए गए tools और abstractions सहित पूरी journey पर blog लिखने की योजना है
    अगर रुचि हो तो demo यहाँ है: https://wizardmasters.io

    • Jon Blow ने भी काफी पहले ऐसा game बनाने की कोशिश की थी। यह देखना सीखने लायक हो सकता है कि वह कैसे और क्यों fail हुआ
  • लेख अपने आप में वाकई मजबूत है, लेकिन Part 1 की setup प्रक्रिया Common Lisp खुद, Python, C और कई चरणों से गुजरती है—इसे देखकर लगता है कि CL खासकर युवा programmers में इतना popular क्यों नहीं है
    यह अफ़सोस की बात है, और अच्छा होगा अगर कोई installation के लिहाज से language को ज्यादा approachable बनाने की मेहनत करे

    • ठीक उसी problem को target करता है, ऐसा कहना मुश्किल है, लेकिन https://ciel-lang.org/ कम से कम बहुत ज्यादा steps वाली problem के कुछ हिस्से को हल करने की कोशिश है
      मेरी समझ में यह बहुत सारे विकल्पों और पुराने defaults के outdated दिखने वाली problem पर अधिक focus करता है
  • event loop इस बात का बेहतरीन example है कि loop कितना गंभीर iteration के लिए domain-specific language है। पसंद करें या न करें ;)

    • loop की जगह https://iterate.common-lisp.dev/ इस्तेमाल नहीं कर सकते? न S-expression से अलग अजीब syntax है, न Lisp syntax में लौटने के लिए do की जरूरत
      बदसूरत else/end के बिना सामान्य if/when इस्तेमाल करता है, और कुल मिलाकर उपयोगी features भी जोड़े गए हैं
    • शुरुआत में मैंने इसका मज़ाक उड़ाया था, लेकिन कुछ साल Common Lisp में programming करने के बाद loop मेरे पसंदीदा CL constructs में से एक बन गया
  • यह लेख "Caves of Clojure" की याद दिलाता है: https://stevelosh.com/blog/2012/07/caves-of-clojure-01/

  • संयोग से इसी हफ्ते मैंने Python में roguelike develop करना शुरू किया है, लेकिन Lisp में करना भी बढ़िया रहेगा

  • मुझे तो ठगा हुआ महसूस हो रहा है। मैं एक simple game बनाना सीखने आया था, और computing overall के बारे में बहुत कुछ सीख गया
    वाकई बढ़िया