Following my passion #2: position vector and learning more Zig

Published: (December 31, 2025 at 10:20 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Introduction

I spent a work night coding a small project. After a busy day debugging Kafka, I returned to a Raylib bootstrap that was only drawing a square. The goal for today was to make the square move, which I managed to accomplish.

I’m not new to game development—I previously attempted a C++ game in 2024—but I’m fairly new to Zig, so this was an interesting challenge.

Player struct

const Player = struct {
    x: usize,
    y: usize,
    width: usize,
    height: usize,
};

This struct defines the position and size of the square on the screen.

Constructor

In Zig, constructors are regular functions placed inside the struct’s namespace. By convention we use an init function:

pub fn init() Player {
    return Player{
        // initializations go here
    };
}

You can also alias the struct type with const Self = @This();, but I chose not to use that here.

Draw function

pub fn draw(self: Player) void {
    const origin = rl.Vector2{
        .x = 0,
        .y = 0,
    };

    const rec = rl.Rectangle{
        .x = self.x,
        .y = self.y,
        .height = self.height,
        .width = self.width,
    };

    rl.drawRectanglePro(rec, origin, @as(f32, @floatFromInt(0)), .white);
}

rl is an alias for the Raylib library. The function builds a Rectangle from the player’s fields and draws it.

Update function

Initially the update method was defined as:

pub fn update(self: Player) void {
    self.x += 1;
}

This didn’t work because self was immutable. The fix is to pass a pointer so the struct can be mutated:

pub fn update(self: *Player) void {
    self.x += 1;
}

Centering the square

To start the square roughly in the middle of the screen I tried:

return Player{
    .x = rl.getScreenHeight() / 2,
    .y = rl.getScreenWidth() / 2,
    .height = 10,
    .width = 10,
};

Since rl.getScreenHeight() and rl.getScreenWidth() return i32 while Raylib drawing functions expect f32, I converted the values:

return Player{
    .x = @as(f32, @floatFromInt(rl.getScreenHeight())) / 2,
    .y = @as(f32, @floatFromInt(rl.getScreenWidth())) / 2,
    .height = 10,
    .width = 10,
};

The conversion satisfies the compiler, though the precision isn’t perfect yet.

Main loop and input handling

if (rl.isKeyDown(.d)) {
    player.update();
    player.draw();
}
rl.beginDrawing();
defer rl.endDrawing();

rl.clearBackground(.dark_gray);
player.draw();

Pressing the D key moves the square to the right.

Conclusion

Today I learned more about Zig than about game development. Tomorrow I plan to draw additional squares and explore collision detection so my square can interact with them.

Back to Blog

Related posts

Read more »

Learning debunning

Hi, I’m currently learning programming. I decided to focus on debugging as a core skill, especially being able to explain why code fails instead of jumping stra...

When Compilers Surprise You

Article URL: https://xania.org/202512/24-cunning-clang Comments URL: https://news.ycombinator.com/item?id=46375384 Points: 20 Comments: 3...