Personal Log »

This week in gamedev #8

Oh, looks like it is Thursday again. Let’s see what happened in my gamedev time!

Unnamed programming language

As I mentioned in my previous update, I was investigating a scripting solution, but somehow I got distracted in the process. Which is OK, sometimes these distractions lead to good things.

So far I’ve implemented a recursive descent parser for a C-alike language –although I’m using something closer to Scala syntax–, and I can go through the abstract syntax tree and generate something.

And that was fun, but I need to start writing tests and perhaps emit code so I can prove that my language design makes sense.

If I want to use this in any of my 8-bit projects, I probably want to generate something that is useful in those cases. I could compile to Z80 ASM that integrates well with SDCC tools, which sounds very hard –and very interesting at the same time–; or perhaps bytecode for a simple VM, which is probably easier and a more achievable task.

But then I thought that writing the VM itself would be a non-trivial amount of work, so I had the “brilliant idea” to generate WAT (WebAssembly Text), which looks like ASM that can be compiled to be run in a WA (WebAssembly) virtual machine. And so far has been very interesting, and not as complicated as I was expecting. It is also useful that the nuances of generating code to run on WA are helping me to refine the language design, even if that means I’m also being influenced by WA.

This is a code example:

def fac(acc: dword, n: dword): dword
  if (n == 0)
    fac(n * acc, n - 1);

fac(1, 10);

And this is the resulting WAT code:

  (func (result i32)
    i32.const 1
    i32.const 10
    call $fac
  (func $fac (param $acc i32) (param $n i32) (result i32)
    local.get $n
    i32.const 0
    if (result i32)
      local.get $acc
      local.get $n
      local.get $acc
      local.get $n
      i32.const 1
      call $fac
  (export "lang.main" (func 0))

I got to a point where the WAT generation has “revealed” some inconsistencies in my language design and I need to revisit it, which is perfect, because it means the project can grow with less chances of getting to a dead end.

I’m implementing it all in Python with type hints and mypy via a Python LSP server, and I’m really enjoying the experience. Initially I thought the type annotations were slowing me down, but in reality it was all my fault because my code wasn’t great. Now it feels a lot like writing Scala, and it is saving me a lot of time by finding bugs early –plus the better code design to make mypy happy–.

I don’t have a name, and is not a problem; but surely a name would be useful if this project has any future.

More ZX Spectrum 48K coding

Arguably this went a bit cold. Firstly because I spent some time writing a beeper engine, and after that because writing a compiler –see previous point– is fun!

In reality I was thinking about it, because I need a game idea before I can make the game itself. I’m still undecided, but I’m leaning towards a platform game, probably what “Starblind” was going to be before I moved into a more top-down multi-directional scroll idea, that was kind of interesting as a tech demo, but there was never a proper game idea behind it. I’m not looking to make a genre-shaking game, only something that is fun to play and has a good speccy 48K vibe.

I’ve been planning on how to encode the map data reducing the memory footprint as much as possible. In Brick Rick on the speccy 128K I had lots of memory, so I didn’t bother doing anything smart –just good old compression–; but that won’t do it in a 48K game, even if the engine itself doesn’t use a lot of memory. For now I have some ideas on paper, but it is a bit too early to start writing a prototype.

Other than that, I’m trying to clarify what are going to be the features supported by the game engine. So far far I have:

  • Flick-screen platforming action, probably with object based puzzles.
  • A large map area, or at least not small.
  • Different sprite sizes; I’m testing a spaceman sprite that is 16x24 pixels, but enemies are likely to be 16x16.
  • Colour sprites for the enemies, because the type of sprites I’m using, the background will be mostly black; so it makes sense to use coloured sprites.
  • No buffering, drawing directly on the screen!

And that last point is what has kept me busy this week, mostly.

I knew that my sprite routines aren’t the fastest you can write, but Brick Rick uses hardware double buffer (I write to the back-screen, and swap with the visible screen when finished), so it didn’t matter at all because the game updates a 16FPS, so updating 1 of every 3 frames leaves more than enough time to update the game state and draw.

In this project I don’t have that nice hardware support, and I don’t have memory either! So I’m reducing scope, for example, by using XOR sprites (instead of masked) and limiting the backgrounds (mostly black). But the sprite routines aren’t fast enough to draw enough things in one frame, so I was getting flickering all over the place.

Although I’m still testing, I’ve decided to do something similar to Brick Rick’s approach: if you can’t update all the screen in one frame, that’s fine because our target is not the 50 frames per second but 16. The only difference is that I don’t have a back buffer to compose the scene and then make it visible in one step –or fast enough so there is no flickering–. But, what if I can spread the updates in several frames?

If you run the game slow enough you can see that the sprites are drawn on the screen in groups –or at least that’s what I meant!–, but because all the game state is updated at the same time, is not noticeable.

This is not a technical marvel, is more about hiding that my sprite routines aren’t fast enough. Combined with some code to sort the sprites so the groups are optimal, I can move a good number of thins on screen without any flicker –most of the time, at least!–.

So far I’m happy. I’ll keep testing and if it is confirmed that this idea is stable enough, that may be the base for the game engine!

Would you like to discuss the post? You can send me an email!