Skip to content

Instantly share code, notes, and snippets.

@Lightnet
Created August 12, 2026 05:54
Show Gist options
  • Select an option

  • Save Lightnet/07677389c36d910fe59a71acc625cf59 to your computer and use it in GitHub Desktop.

Select an option

Save Lightnet/07677389c36d910fe59a71acc625cf59 to your computer and use it in GitHub Desktop.
Zig 0.16.0 Raylib 6.0 Box3D

Information:

Sample test physics box3d and raylib zig.

https://github.com/erincatto/box3d
zig fetch --save=box3d git+https://github.com/erincatto/box3d.git
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const raylib_dep = b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
});
const raylib = raylib_dep.module("raylib"); // main raylib module
const raygui = raylib_dep.module("raygui"); // raygui module
const raylib_artifact = raylib_dep.artifact("raylib"); // raylib C library
const box3d_dep = b.dependency("box3d", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "zig_raylib_box3d",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
exe.root_module.linkLibrary(raylib_artifact);
exe.root_module.addImport("raylib", raylib);
exe.root_module.addImport("raygui", raygui);
exe.root_module.addIncludePath(box3d_dep.path("include"));
exe.root_module.addIncludePath(box3d_dep.path("include/box3d"));
exe.root_module.addIncludePath(box3d_dep.path("src")); // Some engines require internal src headers
// exe.root_module.linkLibrary(box3d_dep.artifact("box3d"));
const box3d_srcs = &[_][]const u8{
"src/aabb.c",
"src/arena_allocator.c", // Added
"src/bitset.c",
"src/block_allocator.c",
"src/body.c",
"src/broad_phase.c",
"src/capsule.c",
"src/compound.c",
"src/constraint_graph.c",
"src/contact.c",
"src/contact_solver.c",
"src/convex_manifold.c",
"src/core.c",
"src/distance.c",
"src/distance_joint.c",
"src/dynamic_tree.c",
"src/height_field.c",
"src/hull.c",
"src/id_pool.c",
"src/island.c",
"src/joint.c",
"src/manifold.c",
"src/math_functions.c",
"src/mesh.c",
"src/mesh_contact.c",
"src/motor_joint.c", // Added
"src/mover.c",
"src/name_cache.c",
"src/parallel_for.c",
"src/parallel_joint.c",
"src/physics_world.c",
"src/prismatic_joint.c",
"src/recording.c",
"src/recording_replay.c",
"src/revolute_joint.c", // Added
"src/scheduler.c",
"src/sensor.c",
"src/shape.c",
"src/simd.c",
"src/solver.c",
"src/solver_set.c",
"src/sphere.c",
"src/spherical_joint.c",
// "src/stack_allocator.c", // nope
"src/table.c",
"src/timer.c",
"src/triangle_manifold.c",
"src/types.c",
"src/weld_joint.c",
"src/wheel_joint.c",
"src/world_snapshot.c",
};
inline for (box3d_srcs) |src| {
exe.root_module.addCSourceFile(.{
.file = box3d_dep.path(src),
// Box3D is portable C17 code
.flags = &.{ "-std=c17", "-O3" },
});
}
b.installArtifact(exe);
const run_step = b.step("run", "Run the app");
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
}
.{
// This is the default name used by packages depending on this one. For
// example, when a user runs `zig fetch --save <url>`, this field is used
// as the key in the `dependencies` table. Although the user can choose a
// different name, most users will stick with this provided value.
//
// It is redundant to include "zig" in this name because it is already
// within the Zig package namespace.
.name = .zig_raylib_box3d,
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.0",
// Together with name, this represents a globally unique package
// identifier. This field is generated by the Zig toolchain when the
// package is first created, and then *never changes*. This allows
// unambiguous detection of one package being an updated version of
// another.
//
// When forking a Zig project, this id should be regenerated (delete the
// field and run `zig build`) if the upstream project is still maintained.
// Otherwise, the fork is *hostile*, attempting to take control over the
// original project's identity. Thus it is recommended to leave the comment
// on the following line intact, so that it shows up in code reviews that
// modify the field.
.fingerprint = 0x975c3bafb37097c7, // Changing this has security and trust implications.
// Tracks the earliest Zig version that the package considers to be a
// supported use case.
.minimum_zig_version = "0.16.0",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
.raylib_zig = .{
.url = "git+https://github.com/raylib-zig/raylib-zig.git#8758f4cd3a5ae0df6941c4715257223d34c5ad3e",
.hash = "raylib_zig-6.0.0-KE8RECZ8BQDm-txuospkpZHbJ6DNpacUF7D88RWQ_qAe",
},
.box3d = .{
.url = "git+https://github.com/erincatto/box3d.git#f42be210a21023e55881afa4c8daba159a60ef47",
.hash = "N-V-__8AALYluQDdWuYuhnaYTP6Ppmc1i1RZQAxX9i8QRu2n",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
// For example...
//"LICENSE",
//"README.md",
},
}
const std = @import("std");
const rl = @import("raylib");
// Import Box3D headers mapped via your build.zig layout
const c = @cImport({
@cInclude("box3d/box3d.h");
});
/// Helper utility to convert a Box3D vector into a Raylib Vector3 structure
fn toRlVec3(v: c.b3Vec3) rl.Vector3 {
return rl.Vector3.init(v.x, v.y, v.z);
}
pub fn main() !void {
// 1. Initialize Raylib 3D Application Window Context
const screen_width = 1280;
const screen_height = 720;
rl.initWindow(screen_width, screen_height, "Zig + Box3D Physics Simulation Workspace");
defer rl.closeWindow();
// Configure camera positioning in 3D dimensional space
var camera = rl.Camera3D{
.position = rl.Vector3.init(0.0, 12.0, 18.0), // Elevated overview position
.target = rl.Vector3.init(0.0, 2.0, 0.0), // Tracking target center point
.up = rl.Vector3.init(0.0, 1.0, 0.0), // Standard vertical orientation axis
.fovy = 45.0, // Field of view angle degree
.projection = .perspective,
};
rl.setTargetFPS(60);
// 2. Configure and Instatiate Box3D Physics Simulation Environment
var world_def = c.b3DefaultWorldDef();
world_def.gravity = c.b3Vec3{ .x = 0.0, .y = -9.81, .z = 0.0 }; // Standard Earth downward gravity acceleration
const world_id = c.b3CreateWorld(&world_def);
if (c.b3World_IsValid(world_id) == false) {
std.debug.print("Failed to initialize Box3D physics world context.\n", .{});
return error.PhysicsInitializationFailed;
}
defer c.b3DestroyWorld(world_id);
// 3. Create Static Ground Plane Platform Body
var ground_body_def = c.b3DefaultBodyDef();
ground_body_def.type = c.b3_staticBody;
ground_body_def.position = c.b3Vec3{ .x = 0.0, .y = 0.0, .z = 0.0 };
const ground_body_id = c.b3CreateBody(world_id, &ground_body_def);
var ground_shape_def = c.b3DefaultShapeDef();
// Define half-extents parameters for a flat platform using the correct box hull helper
var ground_box = c.b3MakeBoxHull(8.0, 0.5, 8.0);
_ = c.b3CreateHullShape(ground_body_id, &ground_shape_def, &ground_box.base);
// 4. Create Dynamic Falling Sphere Body
var sphere_body_def = c.b3DefaultBodyDef();
sphere_body_def.type = c.b3_dynamicBody;
sphere_body_def.position = c.b3Vec3{ .x = -1.5, .y = 8.0, .z = 0.0 }; // Left side high offset
const sphere_body_id = c.b3CreateBody(world_id, &sphere_body_def);
var sphere_shape_def = c.b3DefaultShapeDef();
sphere_shape_def.density = 1.0;
sphere_shape_def.baseMaterial.restitution = 0.4; // Set restitution via baseMaterial nested field
var sphere = c.b3Sphere{ .radius = 0.6 };
_ = c.b3CreateSphereShape(sphere_body_id, &sphere_shape_def, &sphere);
// 5. Create Dynamic Dropping Box Cube Body
var box_body_def = c.b3DefaultBodyDef();
box_body_def.type = c.b3_dynamicBody;
box_body_def.position = c.b3Vec3{ .x = 1.5, .y = 10.0, .z = 0.5 }; // Right side higher offset
const box_body_id = c.b3CreateBody(world_id, &box_body_def);
var box_shape_def = c.b3DefaultShapeDef();
box_shape_def.density = 1.2;
box_shape_def.baseMaterial.friction = 0.3; // Set friction via baseMaterial nested field
// Define half-extents parameters for a box: 0.75m x 0.75m x 0.75m (Translates into a 1.5m solid cube)
var box_hull = c.b3MakeBoxHull(0.75, 0.75, 0.75);
_ = c.b3CreateHullShape(box_body_id, &box_shape_def, &box_hull.base);
// Real-Time Frame Update Logic & Graphics Rendering Loop
const time_step: f32 = 1.0 / 60.0; // Fixed update time step mapping 60Hz
const sub_step_count: i32 = 4; // Constraint sub-stepping engine iteration accuracy pass
while (!rl.windowShouldClose()) {
// Handle simulation state reset commands
if (rl.isKeyPressed(.r)) {
// Reset Sphere body to its launch configuration definition properties
c.b3Body_SetTransform(sphere_body_id, sphere_body_def.position, sphere_body_def.rotation);
c.b3Body_SetLinearVelocity(sphere_body_id, c.b3Vec3{ .x = 0.0, .y = 0.0, .z = 0.0 });
c.b3Body_SetAngularVelocity(sphere_body_id, c.b3Vec3{ .x = 0.0, .y = 0.0, .z = 0.0 });
// Reset Box body to its launch configuration definition properties
c.b3Body_SetTransform(box_body_id, box_body_def.position, box_body_def.rotation);
c.b3Body_SetLinearVelocity(box_body_id, c.b3Vec3{ .x = 0.0, .y = 0.0, .z = 0.0 });
c.b3Body_SetAngularVelocity(box_body_id, c.b3Vec3{ .x = 0.0, .y = 0.0, .z = 0.0 });
}
// Step the internal physics world forward in time matching target update frames
c.b3World_Step(world_id, time_step, sub_step_count);
// Allow orbital camera manipulation directly via mouse mechanics
rl.updateCamera(&camera, .orbital);
// Graphics Render Phase Execution
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
{
camera.begin();
defer camera.end();
// Draw a base layout configuration grid for measurement comparisons
rl.drawGrid(20, 1.0);
// Render Static Ground Platform (Dimensions convert half-extents to full sizing dimensions)
const ground_pos = toRlVec3(c.b3Body_GetPosition(ground_body_id));
rl.drawCube(ground_pos, 16.0, 1.0, 16.0, rl.Color.gray);
rl.drawCubeWires(ground_pos, 16.0, 1.0, 16.0, rl.Color.dark_gray);
// Render Dynamic Falling Sphere
const sphere_pos = toRlVec3(c.b3Body_GetPosition(sphere_body_id));
rl.drawSphere(sphere_pos, 0.6, rl.Color.red);
rl.drawSphereWires(sphere_pos, 0.6, 16, 16, rl.Color.maroon);
// Render Dynamic Dropping Box Cube
const box_pos = toRlVec3(c.b3Body_GetPosition(box_body_id));
rl.drawCube(box_pos, 1.5, 1.5, 1.5, rl.Color.blue);
rl.drawCubeWires(box_pos, 1.5, 1.5, 1.5, rl.Color.dark_blue);
}
// Display Real-Time Overlay Diagnostics Text HUD Information
rl.drawFPS(10, 10);
rl.drawText("Box3D Physics + Raylib-Zig Render Workspace", 10, 35, 20, rl.Color.dark_gray);
rl.drawText("Use Mouse to Rotate Camera Perspective", 10, 60, 16, rl.Color.gray);
rl.drawText("Red Entity: Sphere | Blue Entity: Box/Hull Cube | Gray: Static Platform Ground", 10, 85, 16, rl.Color.dark_gray);
rl.drawText("Press [R] to Reset Objects to Spawn State", 10, 110, 16, rl.Color.red);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment