Zig feedback from a game developer (Dirtbike sim dev)

Writing shaders in zig would be incredible :slight_smile: Looking forward to it!

2 Likes

Woohoo! Woohoo!
[post needs to be at least 10 chars… :slight_smile: ]

4 Likes

This makes me very happy, and will be a really exciting addition to the language. :grin:

Being able to write your GPU code in Zig is a really nice feature, not one that exists and/or is easily accessible most other general purpose languages. I imagine it will make it attractive to AI developers, but I am personally just excited about it for the game-dev possibilities.

3 Likes

I’m pretty sure it always worked with try. Here is feature description from when it was first implemented. It doesn’t work with catch tho maybe you mixed them up

2 Likes

(regarding memory management and shrinking/growing memory)

Also, games typically oscillate around a predictable max memory usage, and object lifetimes can be roughly divided into a handful of buckets:

  1. ‘static lifetime’, e.g. created at startup and destroyed at shutdown
  2. ‘level/zone lifetime’, e.g. created during the ‘lifetime’ of a map/level/zone/region and bulk-destroyed when that area is left
  3. ‘frame lifetime’, created at some point during a frame and bulk-destroyed at the end of the frame
  4. ‘unpredictable’ anything else, although here various strategies make sense to still avoid fine-grained per-object lifetime management and unlimited growth.

For anything in the ‘unpredictable lifetime’ category I would use a fixed-size pool where items are only marked as dead and the oldest dead item will be recycled when a new item is needed. For instance for something like killed monsters you’d want their carcasses to still be around, but at the same time don’t want to pile them up beyond a maximum number.

…or for bullets (here I wouldn’t use a fully fledged game object per bullet, but something more lightweight more akin to a particle system).

Inventory items can also be fully virtualized instead of being actual game objects. E.g. just build the inventory system completely separate from the rest of the game.

Etc etc etc… IME it’s especially dangerous/tempting in games to run into the ‘everything is an object trap’, because most games deal with representations of actual physical objects.

6 Likes

I agree that it’s a good time to try out bespoke engines. Great video

1 Like

After 7 months, I’ve got a new video for my Dirtbike sim! Still having a good time with zig :slight_smile:

https://youtu.be/MRQpUHUC_8Y

37 Likes

This looks incredibly well designed. Really cool to see this.

Are you planning on including a game mode inspired by those old 2D dirtbike flash games where you have to cross seemingly impossible terrain, often uphill with big boulders, but turns out you can do it with pure skill and endless patience?

3 Likes

Thank you!

Haha yeah there’s a whole genre of dirtbike racing called Hard Enduro where you do this :slight_smile: Those guys are nuts. Going to have some challenges involving it for sure.

4 Likes

:ok_hand: I will have fun watching videos before bed tonight

1 Like

This is looking sick, great work! I can almost smell the dirt and fumes from the bike haha.

3 Likes

Wow that looks insane!
I always wanted to create a clone of the old DOS game “Lotus” but with higher resolution.
This looks like it.

2 Likes

Wow! What a huge leap forward! Looks fantastic!

1 Like

Looks awesome. You’ve obviously put a lot of work in.

I’d be interested if there’s anything that’s changed since that feedback video you did. Are you still in much the same place? Any new favourite or less-than-favourite things?

4 Likes

this is looking amazing! great progress from first video. excited to see where you take it from here. love how the physics looks. :slight_smile:
I would say the biggest issue for me personally is the quality of the animations of the player, but i understand that is a hard problem to solve.

1 Like

I’m a little sad custom build steps is deprecated since a lot of my art pipeline depends on them, just means that I have to make my own hash / change detection for when art assets should be re-exported.

Since I’ve made an exporter for Audacity so I can label a large sequence for different individual sounds and get auto normalization, eq, pitch shift post processing. Also an experimental one for Inkscape once I get controller diagrams animating.

Still using my goofy decl literal vector math and having a good time with it

Generating zig union/enum types from art assets still works and helps wrangle gameplay code, get nice compile errors in switch statements and the like when I change mesh names, sound effect names etc

Build times are getting slow because I keep making new Hashmap and ArrayList types, too much generic code. So releasesmall builds take 10 seconds ish, still tolerable, though releasefast builds take like 30 seconds, which is annoying when I want to test optimizations

Arenas for memory management are still awesome. My fancy nodes that only run when inputs change and have their own arenas is good for most gameplay code, but I still need a seperate persistent allocator for terrain modifications, which is data heavy and accumulates over the course of the session. I was thinking that I’ll have an easy time with multiplayer because my gameplay state / intermediate data seperation is so clean, but terrain deformation sync is a daunting problem still.

Simulation costs 1 ms per tick (240hz, so 4 ms @ 60fps) for one bike and is very stable, scaling to many bikes in multiplayer feels a bit daunting (authoritative server), but multi threading could help a lot, or optimize and/or scale down the workload. Not feeling performance limited by the lang here :slight_smile: ambition just went up

I started putting Nan detection assertions in my runtime to crash before the game state gets corrupted. It’s good!

The Mx guys are definitely picking up on the custom physics and deformation tech, so that’s a win. Overall a lot of positive feedback from them, I get to build the game the way I like, win win :slight_smile: hopefully intial playtesting goes well, not just them looking at a video, need good performance and stability!

7 Likes

just means that I have to make my own hash / change detection for when art assets should be re-exported.

You almost certainly don’t need to do this! The workflow we’ve been trying to encourage people towards here is making proper use of Run steps, which deal with caching for you. I’m not familiar enough with file formats used for game art (etc) to know exactly what you’re doing here (if you can provide more details I’ll be happy to help you out more concretely), but if you have a process which translates files named foo.in to files named foo.out, your logic might look something like this:

// Put your code for exporting an asset in a little self-contained program in
// the file `export_asset.zig`, with this CLI usage:
//
//    export_asset <input path> <output path>
//
// Then, have your build script compile that program:
const export_asset_exe = b.addExecutable(.{
    .name = "export_asset",
    .root_module = b.createModule(.{
        .root_source_file = b.path("export_asset.zig"),
        // Even if we're compiling the game for a different target, we always
        // want to build this utility program for the native machine, since
        // it's used as a part of the build process:
        .target = b.graph.host,
        // Of course, if the export takes a while, you can use a Release mode
        // here instead of Debug---up to you!
        .optimize = .Debug,
    }),
});

// Maybe we have a list of names of assets, each of which we want to be
// exported and installed to the prefix:
const asset_names: []const []const u8 = &.{
    "foo",
    "bar",
};
// We need to run `export_asset_exe` on each one, so loop over them...
for (asset_names) |asset_name| {
    const asset_path = b.path(b.fmt("assets/{s}.in", .{asset_name})); // e.g. "assets/foo.in"
    const out_basename = b.fmt("{s}.out", .{asset_name}); // e.g. "foo.out"

    // Make a step to run `export_asset_exe` on that file:
    const run_export = b.addRunArtifact(export_asset_exe);
    // And add the two CLI args to it:
    run_export.addFileArg(asset_path);
    const out_path = run_export.addOutputFileArg(out_basename);
    // Using `addFileArg` and `addOutputFileArg` above teaches the build system
    // how to cache this step's output---it will cache the output file based on
    // the contents of the input file.

    // Lastly, just install the file we generated. (This dumps it directly into
    // the installation prefix, but you can obviously do whatever you want!)
    const install_asset = b.addInstallFile(out_path, out_basename);
    b.getInstallStep().dependOn(&install_asset.step);
}

That’ll cause export_asset to be run once for each of asset_names, and the resulting file installed into the prefix (zig-out/ by default)—and the results of this will be cached for you based on the contents of the input file. Hopefully that helps you out!

15 Likes

In case it’s helpful to see another reference, here is how I bake my assets using run steps similar to what @mlugg described but with the file names discovered automatically.

10 Likes

Oh yeah, that’s perfect

@setRuntimeSafety is planned to be replaced by @optimizeFor which can enable/disable both runtime safety checks and optimizations, but the issue has been open for a while and has no due date :​/