UPDATE 2023-04-02: Updated the guide for the latest Zig version 0.11.0-dev.2336+5b82b4004
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:
Sadly, the video is outdated because it uses an old version of Zig (0.8.0-dev.1463+f950489ed). That's why the written guide is recommended.
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 (at the time of writing zig-windows-x86_64-0.11.0-dev.2336+5b82b4004.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:
- Search for "advanced system settings" in your start menu (be careful not to perform a Bing web search 😅)
- Click on environment variables
- Now you can edit the PATH for your user
- Add the location where you extracted Zig to your PATH
- You can verify the
zig
executable is found by runningzig version
from a new cmd prompt
Now you are able build Zig software from the command line! 😊
Setup Zig development in Visual Studio Code
In Visual Studio Code we want to install the Zig Language extension (extension id: ziglang.vscode-zig
) to get features such as completions, goto definition, find references, rename symbol, and format code.
For debugging we want the C/C++ extension (extension id: ms-vscode.cpptools
). If you're still unable to set breakpoints in your code go to Visual Studio Code's settings and activate "Allow Breakpoints Everywhere".
Now that everything is installed we can start our first Zig 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 + P
and run >Tasks: Configure Task
. Then choose Create tasks.json from template
, and then the Others
tempate. Edit your tasks.json to look like this:
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "zig build",
"group": "build",
"problemMatcher": [
"$gcc"
]
}
]
}
Now press Ctrl + Shift + B
again and your project should build.
Finally, let's run your project from Visual Studio Code. Hit Ctrl + Shift + D
to go to the debug activity and click on the link to create a launch.json file. You can choose any debugger. We will overwrite the contents anyways with the following:
{
"version": "0.2.0",
"configurations": [
{
"name": "(Windows) Launch",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}/zig-out/bin/hello-gamedev.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"preLaunchTask": "build"
}
]
}
Your program should run if you hit F5 and the breakpoints you have set in your code should be hit.
Graphics
Having only text can be a bit boring. So, let's create a window for to draw some fancy graphics! I recommend the SDL2 library to do this. Grab SDL2-devel-2.26.4-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) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "hello-gamedev",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
const sdl_path = "C:\\lib\\SDL2-2.26.4\\";
exe.addIncludePath(sdl_path ++ "include");
exe.addLibraryPath(sdl_path ++ "lib\\x64");
b.installBinFile(sdl_path ++ "lib\\x64\\SDL2.dll", "SDL2.dll");
exe.linkSystemLibrary("sdl2");
exe.linkLibC();
exe.install();
}
Now paste this code which draws three colored squares using SDL into your main.zig:
const std = @import("std");
const c = @cImport({
@cInclude("SDL.h");
});
pub fn main() !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);
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.001 * @intToFloat(f32, c.SDL_GetTicks());
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);
}
}
Hit F5 and after the build is complete you should have this on your screen:
Congratulations! 🎉 Now you can finally start programming games in Zig.
Top comments (8)
Got the example running on mac using a homebrew installed SDL2 using the following build.zig.
Thanks for the example!
Nice one!
I think you don't even need
exe.addIncludeDir
andexe.addLibPath
since Zig makes use of pkg-config. Given you havepkg-config
installed.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.
A few little updates needed for zig version 0.14
build.zig
Replace
src/deps/
with your path. The.install()
call is no longer needed.main.zig
@floatToInt
and@intToFloat
are no longer supported, they now have newer syntax to do the same job, here's the two you'll need:for those interested in how to fix the syntax of the build to compile successfully,
change the relevant lines to these:
exe.addIncludePath(std.Build.LazyPath{ .path = sdl_path ++ "include" });
exe.addLibraryPath(std.Build.LazyPath{ .path = sdl_path ++ "lib\\x64" });
Changes needed discord.com/channels/6055718032886...
thanks for this post !
For now I just tested the first part of the tuto for setting up the debugger and it worked like a charm for me with ZIG 0.12 and VScode 1.85.0.
Thanks, this helped me setting up my VSCode Run/Debug for Zig
I'm going to use SDL (good tip!) later on for my Vic20 emulator (yes, I know qemu is better, but it's fun to build my own)