Hey, thank you for the interest!
The main design goals for the engine are
- To reduce friction. By scripting in a single file, with no needs for dependencies or even graphical assets, I can get started on a game or prototype simply by creating a new file and running it with
stil project.lua
.
- To encourage creativity. Game engines present fairly opinionated structures, and hence shape the way games need to behave. stil goes to an extreme, by making completely impossible the creation of traditional real time games ; ie.
getkey
being blocking, any visual update needs user input before proceeding.
- To challenge the perception of what a game is meant to be. So far, I’m using this engine to write small interactive experiments, some generative poetry tools and a few anti-games. All took less than an average coding session to get from concept to reality. Iteration is redundant when games are so fast to create (iterative game design is a commercial concept).
- To share ideas. Editing a single line in
src/main.zig
to indicate the path of a .lua
file and running zig build
creates a static executable that’s under 3 Mo. As a demonstration, here’s a small minesweeper homage I made as a reflection on the concept of win conditions: stil.zip (1.1 MB). I want to encourage sharing little things that do not require installation, simply download and run. (Sadly, this forum doesn’t authorize .exe files, but you can imagine this is pretty handy in most chatting softwares to demonstrate a small concept.)
By loop-based programming, I wanted to talk about the way most game engines assume games need to work at scale. Typically, you create a game loop that draws, updates, handles inputs and do some other stuff. Eg., in GameMakerStudio 2, if you want to create a menu, you need to create an object, write some initialization code, some draw code, and some update logic code. All runs in a loop, and is executed every frame. This is very sane at scale (and for real time games), but requires a lot of work and logical states for every single small element. By moving away from this model, I want to encourage writing small one-off interactions, such as input prompts or dialogs, without the need to climb in abstractions.
As a small example, imagine you wrote a small RPG and want to add an help menu. In a typical entity-based game engine, you could do it in such a way:
-- main loop
function update()
if key_pressed("h") then
pause_the_game_somehow()
spawn_entity(HelpMenu)
return
end
-- other logic stuff
end
-- help menu loop
function HelpMenu:update()
if key_pressed("any") then
unpause_the_game_somehow()
destroy(self)
end
end
function HelpMenu:draw()
draw_the_menu_somehow()
end
in my eyes, this is a lot of work anytime you want to add such small interactions. In contrast, this is how you could do it in stil:
-- title screen
locate(1, 1, "super fun game")
getkey()
clear()
-- explicit main loop
while true
local s, c = getkey() -- getkey returns two values, scancode and keycode
if c == string.byte'h' then
-- display help
locate(1, 1, "space to jump")
locate(1, 2, "arrows to move")
continue
end
-- do gamy things...
end
I hope this made some sense, I’d happily try to explain in some other ways if this was unclear.