ZL001 - Assembly Programming Game
Source Code + Build on Github
The news that puzzle game studio zachtronics would stop making games inspired me to begin
creating a little game in the style of some of their programming games (TS100, ShenzenIO, Exapunks).
I’m using this project to play about with a library(SDL2) and a language(Rust) I haven’t used for games before.
I’ve been working on it slowly and I have some of the more basic mechanics in a playable form.
The game has a custom text editor and a circuit creation gui. It doesn’t have any levels yet, instead it works as a sandbox. The GUI handles writing code, placing/deleting microcontrollers, connecting IO ports together, saving/loading and compiling/stepping the code. The shell shows the state of the registers after every execution step and any compile errors.
As you can see from the video the circuit designer lets you place microcontrollers and connect up their IO ports. They can then be programmed to do whatever is desired. The code can be stepped through and the shell shows which values are in each of the registers, as well as if the microcontroller is waiting for an io port.
The Language
The language is not accurate assembly, it does not correspond one to one with a binary format, it is inspired by the languages from zachtronic games, as well as other fake assembly langauges like Sigma16.
What makes it unique from the usual zach-like languages is that code lables are just converted to numbers, so register, direct addresses, inputs can all be used as branch destinations. Another difference is that the program counter is treated as a normal register that the programmer can manipulate, which would make it possible to have simple functions.
The langauge is made up of a series of instructions, which are for:
maths -> ADD, SUB, MUL, DIV
branching -> CMP, BRC, BEQ, BGT, BLT
no operation -> NOP
halt -> HLT
Each instruction can be followed by up to three operands depending on the instruction.
An operand is a value (which includes lables), or a register. Each microcontroller has 4 normal register and 4 IO registers.
The registers are:
PC -> Program Counter
RT -> Test register (holds CMP flags)
R1, R2 -> General Registers
IO0, IO1, IO2, IO3 -> IO registers, can be read to or written from (blocks until another microcontroller read/writes the value)
Experience with SDL2 and Rust
I found SDL2 to be pretty unintuitive compared to frameworks like Monogame, I had to look at a lot of example code and check the source code to see what it was doing. I didn’t like the system of a canvas being passed around. The Rust borrow checker also meant that a lot of types that rely on the sdl2 lifetime needed to have explicit lifetimes.
Once I had made a few helper functions in place to handle texture/font loading and drawing it became a lot more managable. I moved the sdl2 resources to resource managers and just exposed cheap representations of the resource to the rest of the game. I found Rust to be enjoyable to use, but I definitely found myself missing some of the freedom that comes with C++.
The amount of string parsing functions that Rust has, the easy to use iterator system, and the pattern match syntax, made this specific program fun to code. I found being thorough with my error checking to be much easier with rust, as it really encourages you to handle errors, instead of having to remember to do it yourself.
What’s next
The next stage of this project would be to add in input and output devices that would give the user some sort of puzzle to complete with the provided sandbox, as in a zach-like game. But for now I will be putting this on hold to work on other things. I will have to overhaul the rendering, to make it more friendly for resolution scaling.