💾 Archived View for gemini.circumlunar.space › users › wakyct › crt › 23-06-2020.gmi captured on 2023-04-19 at 23:10:45. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2020-09-24)
-=-=-=-=-=-=-
link to the reference tutorial
This part of the tutorial sets up a couple of key elements, the entity and the map, and also develops the drawing routines to show those elements on the screen.
I'm going to call the entity a 'thing' instead (for some reason I dislike the term entity, you say tomato, etc.), and I think I'm going to diverge from the tutorial and not put the thing's glyph and glyph color in its game world data structure. As an exercise I want to separate the game and the view of it.
In rough order these are my tasks for part 2:
- create a mapping of game elements to view elements, so rendering updates based on game data ✓
- create a Move action that modifies a thing's game position ✓
- make a distinct 'player' thing ✓
- make another 'npc' thing, and put it in a collection with the player thing (TBD) ✓
- create a data structure to hold the game world ✓
- I'll also need a collection of screen rects i.e. console cells ✓
- create something to represent a world tile and basic attributes like dark, walkable and transparent ✓
- designate a few tiles of the world to be not walkable ✓
- and implement a test in the move function so the player can't walk there. ✓
- Also test if the player moves out of bounds. ✓
- render the current game world ✓
There are a few extra tasks I want to accomplish this week.
- get interactive development working with the REPL.
- more clearly separate SDL2 concerns from the game engine code; SDL2 input will raise game-events and UI-events. Game code reads game-events (e.g. the player moved), and UI code reads UI-events (e.g the player pressed escape to quit).
On the topic of interactive development, how does that work with respect to already instantiated records?
Up to now I've been using single glyphs rendered from a loaded ttf font. I went ahead and loaded a tilesheet from the Dwarf Fortress wiki (which are ordered like CP437 charsets), and with the help of a mapping of CP437 to unicode numbers I got from libtcod, made a hash-table of unicode number -> tile glyph. All the glyphs are white on the tilesheet, but you can set the surface-color-mod of the tile surface to color it. It seems like Chicken Scheme can handle character constants for the whole tilesheet, so it might be nice to create a mapping of char constant to unicode number for ease of use.
For now the world is just a 1D vector of tile records, rather than a 2D array like the reference tutorial uses. It's TBD whether I'll switch to a 2D array or something else, for now the vector is adequate with some functions defined to access the contents in relation to x,y.
I was mystified why changing tiles in a subvector of my world vector changed every tile in the world -- until I realized the `fill` parameter of make-vector used copies of its argument (in my case the record-creating make-tile).
I'm behind on week two, but moving on to part 3, dungeon generation. I'm deliberately not copying all the code design from the reference tutorial in an effort to keep things simple and flexible to possibly refactor to something later when I have a better idea of what I want to do.
I hit a major roadblock trying Emacs with either Geiser or run-scheme, where I couldn't get a simple interactive workflow with Chicken's green threads (SRFI 18). Incidentally this caused a bit of a detour so I'm way behind on the tutorial. My starting point was this video walkthrough,
Practical Chicken Scheme with Emacs: hello-world webserver
When I tried to replicate the example my srfi 18 thread would start, but not flush any output to the REPL until the main thread flushed output. Apparently there is some difficulty on Windows with interactive console applications because Windows doesn't have the same concept of pseudo ttys like Unix-based systems do. As a result Emacs communicates with its sub-processes (i.e. Scheme in this case) via pipes, rather than a pseudo tty, and issues with buffering arise. For reference see,
https://lists.gnu.org/archive/html/help-gnu-emacs/2006-04/msg00272.html
https://lists.gnu.org/archive/html/help-gnu-emacs/2006-04/msg00250.html
Searching for a solution I posted to chicken-users, and fortunately got a helpful response (from none other than the maker of the video walkthrough, pretty cool!).
https://lists.nongnu.org/archive/html/chicken-users/2020-07/msg00000.html
The result is that I was able to get things working by connecting to the Chicken process from Emacs via a 3rd party socket, rather than a built-in Emacs pipe. The Chicken process spawns a network repl with the nrepl egg, and the Windows utility ncat provides the socket. Ncat is similar to the unix program 'nc', which is what you'll see mentioned in the nrepl docs.
The workflow is:
- start csi in the working directory
- load the game's .scm file...
- which starts the SDL main loop and also an nrepl on localhost 1234
- run-scheme in Emacs with C-u M-x run-scheme, which allows you to specify the Scheme to connect to
- specify 'ncat localhost 1234'
- Emacs connects to the game. Now redefining top-level forms in Emacs should change the game.
Week 2 continues in....