Next Broadcast

RoverGame Prototype (Part 1): Terminal Matters

Haatveit GameDev DK30 Fall 2023 0 0

Description

This is Part 1 (January 2024) of my ongoing project to prototype/develop one of my game ideas. To maintain focus and avoid overwhelming myself, I hope to work on one aspect at a time. Trying to do all of it at once breaks my brain! I am using Godot for the first time, so I am also learning the tools and GDScript as I go. I hope to alternate between code– and design-focused work.

The first part to get working is a sort of fake terminal emulator thing, as this is a core part of the game; it is through this terminal that you interact with the world around you. I am essentially starting from scratch, with <100 lines of experimental code, and <10 hours in Godot.

Recent Updates

Haatveit 2 years ago

It’s MON-… Well, it’s Tuesday. But whatever! I’ve completed this months milestones.

A Tribute

I decided to implement the display (actually called show now) command, kind of as a pathfinder, since I knew it could be complicated. Unbeknownst to me, it revealed a serious flaw with the way I had set up the CommandRegistry and basically the whole command system. I don’t want to talk about it, but it’s fixed now!

Right now the command just shows a preloaded image. The idea is that, in the future, this command will let you show an image generated by the game. Or, actually, visualize all sorts of things, not just images!

Spent some time trying to understand the built-in GUI container nodes in Godot, had an aneurysm, and then finally just did all the window positioning and sizing by hand, via code. Worked just fine!

This marks the end of this months project (subproject?), I hope to do another stint soon, maybe next month, maybe not!

I will write another update to close it all out, a bit later.

Here’s a little clip showing the final result: https://i.imgur.com/BZuN7Tq.mp4

Haatveit 2 years ago

Taking some time to think about my Week 3 goals. When I wrote them, it seemed sensible, but I now see that there are some major design decisions to be made on the topic. My hope was to implement a display <thing> type command that would display, for example, an image on the screen. This is something the player will definitely do in the game, so that’s all good. But I’m now realizing that implementing this requires answering quite a few difficult questions first.

So, that’s what I’m doing! Sitting down and thinking, visualizing, discussing with ChatGPT (I love this thing; great for bouncing ideas with). I’m not convinced I’ll have answers before the end of the month.

I might still make the most basic version of it on a separate branch, even if it’s a really stupid implementation, just to get a better feel for how I’d really like it to work, and what sort of back-end needs to exist to facilitate it.

Haatveit 2 years ago

It’s MONDAY AGAIN! Well, it’s really late Sunday night, but whatever.

I did not get to working on my week 3 goals, but I did finally tackle:

  • visuals pass (really happy with the result)
  • command history implemented
  • input positioned where I wanted it, under the most recent output!
  • some QoL enhancements, and unexpected design decisions

Screenshot

For the visual pass, I changed fonts, updated the background (to black), and added a shader! The shader is loosely based on this lovely CRT shader by user pend00. I stripped away all the glitchy & distortion type effects, kept the rest, and played around with the parameters. The result is somewhat subtle, but it makes the terminal look soft and glowy, and there’s a slight noise to the screen. Makes it look “real” and physical, somehow. I’m super happy with it for now!

Next I made an attempt at positioning the input text box to follow the “new line” just below the output. Using an extremely naive method for now, but it actually worked just off the bat. There are some problems when you get to the bottom of the screen, but it’s okay for now.

Next I tackled command history. I had some skeleton functions and structure in place for this already, I just needed to actually implement them. After a little bit of expected off-by-one bug hunting I had it working. I realized there are some interesting design decisions to be made, when implementing this otherwise innocuous functionality:

  • What happens if you repeat a command from history? Do you add a duplicate to the history? Do you move the repeated command from its old place in history to the front? Or do you “move” a sort of pointer to a past point in time?
  • What happens if the user has already entered something into the input, and then begins browsing history?

I decided to do some testing, and in a hilarious coincidence, all 3 terminals I tested approached this differently, exactly matching my 3 suggested ideas. The default Windows command line (cmd.exe) does the history-pointer thing, so after repeating a previous command, going up keeps going further back in history, moving down moves forward in history. Git Bash (MINGW64) simply adds a duplicate to history, so it uses the most simplistic approach. And finally PowerShell does the move version, where it moves the repeated command to the front, erasing its doppelganger from history.

Ultimately I went with the PowerShell flavor, so the duplicate of a command is removed and inserted again to the front of history. This kinda breaks the timeline aspect of the command history, but it makes more sense than adding duplicates of a command string, and is less complex than doing the pointer-into-history method.

As for the case where the user is already typing something, I decided to store it in a temporary buffer when they begin browsing history. If they ever browse all the way “back” to present-time OR hit Escape while browsing history, I restore their input.

Finally I added Home & End key navigation, and made one small but important tweak to the blinking cursor: Whenever the user navigates (left, right), erases or types a character, I force the cursor to appear for one interval, no matter where it is in the blink cycle. It was annoying to navigate while the cursor kept disappearing every 0.5 seconds. And, as I am typing this very update, I realize that this is how other applications do text entry as well - the cursor is “forced” to be visible while typing or navigating.

Here’s a demo of what things currently look like: https://i.imgur.com/hA5LKMX.mp4

Haatveit 2 years ago

It’s MONDAY! But I did get some more work done today, so let’s make up for yesterdays missing update.

Basically, I implemented Left/Right arrow key navigation, as well as Delete/Backspace erasing, on the “command line”. This was way, way, way, super, mega, extremely less easy than I anticipated. But it works, and I’m actually very happy with the resulting code, it’s well organized and uncharacteristically un-hacky!

This would all work out of the box if I had used one of Godot’s LineEdit elements, but trying to use that lead to other issues that I concluded unsolvable without massive hacking. So, that’s why I decided to use Label which is just a plain text display element, and just implementing the text input behaviors and visuals by hand. This could end up hacky, by so far it’s all quite nice and comprehensible code.

Demo: https://i.imgur.com/fmb24PS.mp4

Next on my list is history navigation ⬆️⬇️, and CTRL key modifier to work on whole words, for both navigating and erasing. Actually it’d be cool if the Ctrl modified actions were aware of word parts, so that Ctrl modified actions navigate/erase on transition boundaries between parts of a word that use different case, symbols, or numbers. For example if I Ctrl+Backspace on camelCase|, I think it should only erase Case. Or, for snake_case|, Ctrl+Backspace should only erase case. And finally blah123 should only erase 123.

Too ambitious? Certainly!

Haatveit 2 years ago

It’s 03:00 on Sunday, and I have just about managed to get everything done for Week 1!

Right now the project looks like this: https://i.imgur.com/KBNmbKD.mp4

I’m happy with the overall function of everything. Commands are loaded from .gd scripts in a dedicated project folder, they register themselves with a CommandRegistry, and are (naively) matched with entered commands, receives arguments, and returns results. Wohoo!

What I’m not happy with is the separation of the input & output on the screen. I spent a lot of time and energy trying to coerce the Godot RichTextLabel node to do both input and output at the same time - but ultimately I gave up, and just created a dedicated Label box to serves as the input entry box.

I think I can probably move the input box around on the screen so that it “looks” right, but we’ll see.

Lessons learned:

Godot Engine:

  • Much more complex than I expected. It’s more or less in line with Unity. It’s not as fast of a way to prototype as using my favorite framework, Love2D. Sadly, Love2D would have been a massive hurdle since I want to do some 3D stuff in this project.
  • Documentation is very good for the most part.
  • The built-in script editor is really quite good, especially in unison with the integrated debugger. Though, I will be sticking to VSCode for most code work, my hands just know what to do there, shortcut & navigation wise. But feature-wise the built-in script editor is really more than good enough!

GDScript:

  • Syntactically significant indentation. Meh. I can live with it. Same goes for the snake_case convention; on ISO keyboards this _ just isn’t ergonomic to type over and over.
  • The amount of alternate syntaxes for various things artificially inflates the complexity of the language quite a bit, in my opinion. Though some of it is very nice, especially the support for Lua-style dictionaries (my favorite data structure of all time? You get a table, YOU get a table, everyone gets a table!).

Summary

This week was 95% distractions and 5% working on the project, but it worked out in the end.

I tried working with a pomodoro timer on Saturday, and it actually worked quite well. I used a longer work interval than suggested, 30 minutes on / 5 minutes off / 20 minute long break.

Next week should be okay, though I have a feeling I’ll waste hours on getting the input text positioned where I want it. But maybe I can just live with it the way it is; it is functionally not that important. But it’s ugly the way it is.

Estimated Timeframe

Dec 31st - Jan 31st

Week 1 Goal

At the end of this week, I would be happy if my prototype terminal can do the following;

  • Capture user input (as text), and display it on the screen as it is being entered
  • Visually appear VAGUELY like a text-terminal, displaying text one line at a time
  • Load defined commands and try to match them with user input, passing along parameters
  • Add one single test command; echo <input> - which just, well, echoes your input back at you. This command will be the testbed for basic command loading and triggering

Week 2 Goal

In week 2, I want to flesh out the terminal a bit, both visually and interactively;

  • Make a visual pass on font, font size, and basic formatting of the terminal text
  • Add more commands, for example a help command that lists all defined commands, or gives additional information about a specific command (help echo - prints the help text for the echo command)
  • BONUS: Add command history browsing via the ⬆️⬇️ arrow keys! Should not be too hard, if I use something like a command buffer to hold user input, which is the plan.

Week 3 Goal

This week, I would really like to experiment with supporting overlay elements. As part of normal gameplay, the player will often want to view certain non-text items, such as images. So, I should allow popping up a small overlay with f.ex. an image, or fullscreen view an image.

  • Implement a display <thing> command, that displays an item. To start with, let’s just support images.
  • By default, shows the image fullscreen. Given a parameter of some sort (display topright <item> ?), pop up the image in a corner of the screen, while still allowing terminal input to continue as normal.

I have a feeling that this might be trickier than expected to get right, so, I’ll leave it at that for week 3.

Week 4 Goal

I’m thinking I might need week 4 to finish up what I wanted to do for the month, but if I have the time to spare, I’d like to spend some time just extending the “operating system” that the user interacts with. Eventually there will be files, folders, and such - but for now, I’d be happy to just add some flair, visual or otherwise, to make the player feel like they are actually interacting with some complex system.

Tags

  • Godot
  • Gamedev
  • Prototype
  • GDScript