DEV Community

loading...

Setup Zig for Gamedev

Fabio Arnold
Hobby gamedev
・5 min read

This is a step by step guide on how to get started with game development using the Zig programming language on Windows.

TL;DR, here's an 8 min video of every step:

Visual Studio Code

We're going to use Visual Studio Code as our IDE. It will provide us with syntax highlighting, code completion and an interactive debugging experience. So go to https://visualstudio.microsoft.com/downloads/ download and install Visual Studio Code.

Zig

Out of the box Visual Studio Code doesn't support the Zig language. So, first we need to grab the Zig compiler itself. Since Zig is currently pre 1.0 I recommend getting the latest master build from https://ziglang.org/download/ for your platform (e.g. zig-windows-x86_64-0.8.0-dev.1463+f950489ed.zip). To make the zig command available from the command line extract the downloaded archive to a known location: e.g. C:\Users\<Username>\Downloads\zig and add the location to your PATH variable.

This is how you can edit your PATH variable on Windows:

  1. Search for "advanced system settings" in your start menu and hit enter
  2. Click on environment variables
  3. Now you can edit the PATH for your user
  4. Add the location where you extracted Zig to your PATH

Now you are able build Zig software from the command line! 😊

Zig language server

ZLS provides Visual Studio Code (or any other editor with LSP support) with features such as completions, goto definition, find references, rename symbol and format code. If you have git installed recursively clone the repository else you can download and extract an archive of the source from here: https://github.com/zigtools/zls/archive/master.zip. Also download and extract https://github.com/ziglibs/known-folders/archive/master.zip and https://github.com/ziglibs/zinput/archive/master.zip and extract them to the zls/src directory. Use your terminal (cmd.exe) to change into the zls directory and run zig build. If that was successful a zls.exe should exist in zig-cache/bin.

Setup Zig development in Visual Studio Code

For ZLS integration we want to install "ZLS for VSCode" from the extension marketplace. We need to tell it the location of the zls.exe executable we just built in the previous step. Click the little gear icon and on "Extension Settings". Here we can paste the path to zls.exe: C:\Users\<Username>\Downloads\zls\zig-cache\bin\zls.exe.

For debugging we want the C/C++ (ms-vscode.cpptools) extension. After installing the extension go to Visual Studio Code's settings and activate "Allow Breakpoints Everywhere".

Now that everything is installed we can start our first project. Choose File > Open Folder... I create a folder hello-gamedev and click Open. Then press Ctrl + J to open the terminal and type in zig init-exe. This will create the main source file of your project in src/main.zig and a build.zig file which tells zig how to build your project.

To build your project we want to create a build task in Visual Studio Code. Hit Ctrl + Shift + B to run the build task. Since there is none Visual Studio Code will prompt you to create a tasks.json file. Just hit enter a couple of times and choose the "Others" template. Edit your tasks.json to look like this:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "zig build",
            "group": "build",
            "problemMatcher": [
                "$gcc"
            ]
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Now press Ctrl + Shift + B again and your project should build.

Finally, let's run your project from Visual Studio Code. Hit F5 (Run). This will bring up the environment selection. Choose "C++ (Windows)". This will create a launch.json file. Edit the "program" property to point to your freshly built executable: "${workspaceFolder}/zig-cache/bin/hello-gamedev.exe". Also, conveniently configure your build task as "preLaunchTask" to build your project every time before you run. Your launch.json should look something like this:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(Windows) Launch",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/zig-cache/bin/hello-gamedev.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "preLaunchTask": "build"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Your program should run if you hit F5 and you should be able to place breakpoints in your code.

Graphics

Having only text can be a bit boring. So, let's create a window for drawing some fancy graphics! I recommend the SDL2 library to do this. Grab https://libsdl.org/release/SDL2-devel-2.0.14-VC.zip and extract the archive to a known location such as C:\lib\. Edit your build.zig so it looks like this:

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const target = b.standardTargetOptions(.{ .default_target = .{ .abi = .gnu } });
    const mode = b.standardReleaseOptions();

    const exe = b.addExecutable("hello-gamedev", "src/main.zig");
    exe.setTarget(target);
    exe.setBuildMode(mode);

    const sdl_path = "C:\\lib\\SDL2-2.0.14\\";
    exe.addIncludeDir(sdl_path ++ "include");
    exe.addLibPath(sdl_path ++ "lib\\x64");
    b.installBinFile(sdl_path ++ "lib\\x64\\SDL2.dll", "SDL2.dll");
    exe.linkSystemLibrary("sdl2");
    exe.linkLibC();
    exe.install();
}
Enter fullscreen mode Exit fullscreen mode

Now paste this program which draws three colored squares using SDL in your main.zig:

const std = @import("std");
const c = @cImport({
    @cInclude("SDL.h");
});

pub fn main() anyerror!void {
    _ = c.SDL_Init(c.SDL_INIT_VIDEO);
    defer c.SDL_Quit();

    var window = c.SDL_CreateWindow("hello gamedev", c.SDL_WINDOWPOS_CENTERED, c.SDL_WINDOWPOS_CENTERED, 640, 400, 0);
    defer c.SDL_DestroyWindow(window);

    var renderer = c.SDL_CreateRenderer(window, 0, c.SDL_RENDERER_PRESENTVSYNC);
    defer c.SDL_DestroyRenderer(renderer);

    var frame: usize = 0;
    mainloop: while (true) {
        var sdl_event: c.SDL_Event = undefined;
        while (c.SDL_PollEvent(&sdl_event) != 0) {
            switch (sdl_event.type) {
                c.SDL_QUIT => break :mainloop,
                else => {},
            }
        }

        _ = c.SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
        _ = c.SDL_RenderClear(renderer);
        var rect = c.SDL_Rect{ .x = 0, .y = 0, .w = 60, .h = 60 };
        const a = 0.06 * @intToFloat(f32, frame);
        const t = 2 * std.math.pi / 3.0;
        const r = 100 * @cos(0.1 * a);
        rect.x = 290 + @floatToInt(i32, r * @cos(a));
        rect.y = 170 + @floatToInt(i32, r * @sin(a));
        _ = c.SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff);
        _ = c.SDL_RenderFillRect(renderer, &rect);
        rect.x = 290 + @floatToInt(i32, r * @cos(a + t));
        rect.y = 170 + @floatToInt(i32, r * @sin(a + t));
        _ = c.SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0xff);
        _ = c.SDL_RenderFillRect(renderer, &rect);
        rect.x = 290 + @floatToInt(i32, r * @cos(a + 2 * t));
        rect.y = 170 + @floatToInt(i32, r * @sin(a + 2 * t));
        _ = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0xff, 0xff);
        _ = c.SDL_RenderFillRect(renderer, &rect);
        c.SDL_RenderPresent(renderer);
        frame += 1;
    }
}
Enter fullscreen mode Exit fullscreen mode

Hit F5 and after the build is complete you should have this on your screen:

three colored squares

Congratulations! πŸŽ‰ Now you can finally start programming games in Zig.

Discussion (4)

Collapse
zealouswombat profile image
ZealousWombat

Got the example running on mac using a homebrew installed SDL2 using the following build.zig.

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const target = b.standardTargetOptions(.{ .default_target = .{ .abi = .gnu } });
    const mode = b.standardReleaseOptions();

    const exe = b.addExecutable("hello-gamedev", "src/main.zig");
    exe.setTarget(target);
    exe.setBuildMode(mode);

    exe.addIncludeDir("/usr/local/include/SDL2");
    exe.addLibPath("/usr/local/lib");
    exe.linkSystemLibrary("sdl2");
    exe.linkLibC();
    exe.install();
}
Enter fullscreen mode Exit fullscreen mode

Thanks for the example!

Collapse
fabioarnold profile image
Fabio Arnold Author • Edited

Nice one!
I think you don't even need exe.addIncludeDir and exe.addLibPath since Zig makes use of pkg-config. Given you have pkg-config installed.

Collapse
fabioarnold profile image
Fabio Arnold Author

I agree. Zig is awesome. πŸ˜ƒ I think it makes systems programming really fun.

You can include C header files which automatically get translated by Zig's translate C feature. You can also link C libraries. So it integrates well with existing C/C++ code. 😊

The output is native by default. This means x86_64 on my machine. But since Zig uses LLVM it can generate code for any processor architecture supported by LLVM.