GLQSOF6B4KBQ42VLWSGMAFGW2F53QBLGLQ2F2MKB4WPHXCTNKPVAC
const std = @import("std");
const rl = @cImport(@cInclude("raylib.h"));
const ecs = @import("zflecs");
const screen_width = 800;
const screen_height = 450;
// Globals
var camera = rl.Camera2D{
.offset = rl.Vector2{
.x = screen_width / 2.0,
.y = screen_height / 2.0,
},
.target = rl.Vector2{ .x = 0, .y = 0 },
.rotation = 0,
.zoom = 1,
};
// Constants
const MAX_BUILDINGS = 100;
// Game States
const GameStateStartup = struct {};
const GameStateStartScreen = struct {};
const GameStateLoop = struct {};
const GameStateExitRequested = struct {};
const GameState = union(enum) {
startup: GameStateStartup,
start_screen: GameStateStartScreen,
loop: GameStateLoop,
exit_requested: GameStateExitRequested,
};
// Parts
const ColorRectangle = struct { rect: rl.Rectangle, color: rl.Color };
// Components
const Position = struct { x: f32, y: f32 };
const Drawable = union(enum) { rect: rl.Rectangle, color_rect: ColorRectangle };
// Tags
const Player = struct {};
const CameraTarget = struct {};
const Background = struct {};
const Foreground = struct {};
// Systems
fn handle_input(it: *ecs.iter_t) callconv(.C) void {
const pos = ecs.field(it, Position, 1).?;
_ = ecs.field(it, Player, 2);
for (0..it.count()) |i| {
if (rl.IsKeyDown(rl.KEY_A)) {
pos[i].x -= 2;
}
if (rl.IsKeyDown(rl.KEY_D)) {
pos[i].x += 2;
}
if (rl.IsKeyDown(rl.KEY_W)) {
pos[i].y -= 2;
}
if (rl.IsKeyDown(rl.KEY_S)) {
pos[i].y += 2;
}
}
}
fn get_camera_target(it: *ecs.iter_t) callconv(.C) void {
const pos = ecs.field(it, Position, 1).?;
_ = ecs.field(it, CameraTarget, 2);
for (0..it.count()) |i| {
camera.target = rl.Vector2{ .x = pos[i].x, .y = pos[i].y };
break;
}
}
fn draw(it: *ecs.iter_t) callconv(.C) void {
const pos = ecs.field(it, Position, 1).?;
const drawable = ecs.field(it, Drawable, 2).?;
for (0..it.count()) |i| {
const p = pos[i];
switch (drawable[i]) {
Drawable.rect => |d| {
rl.DrawRectangleRec(rl.Rectangle{
.x = d.x + p.x,
.y = d.y + p.y,
.width = d.width,
.height = d.height,
}, rl.RED);
},
Drawable.color_rect => |d| {
rl.DrawRectangleRec(rl.Rectangle{
.x = d.rect.x + p.x,
.y = d.rect.y + p.y,
.width = d.rect.width,
.height = d.rect.height,
}, rl.RED);
},
}
}
}
fn init_ecs() *ecs.world_t {
const world = ecs.init();
ecs.COMPONENT(world, Position);
ecs.COMPONENT(world, ecs.EcsRest);
ecs.COMPONENT(world, Drawable);
ecs.TAG(world, Player);
ecs.TAG(world, CameraTarget);
ecs.TAG(world, Background);
ecs.TAG(world, Foreground);
{
var system_desc = ecs.system_desc_t{};
system_desc.callback = handle_input;
system_desc.query.filter.terms[0] = .{ .id = ecs.id(Position) };
system_desc.query.filter.terms[1] = .{ .id = ecs.id(Player) };
ecs.SYSTEM(world, "handle_input", ecs.OnUpdate, &system_desc);
}
{
var system_desc = ecs.system_desc_t{};
system_desc.callback = get_camera_target;
system_desc.query.filter.terms[0] = .{ .id = ecs.id(Position) };
system_desc.query.filter.terms[1] = .{ .id = ecs.id(CameraTarget) };
ecs.SYSTEM(world, "get_camera_target", ecs.OnUpdate, &system_desc);
}
{
var system_desc = ecs.system_desc_t{};
system_desc.callback = draw;
system_desc.query.filter.terms[0] = .{ .id = ecs.id(Position) };
system_desc.query.filter.terms[1] = .{ .id = ecs.id(Drawable) };
system_desc.query.filter.terms[2] = .{ .id = ecs.id(Background) };
ecs.SYSTEM(world, "draw_background", ecs.PostUpdate, &system_desc);
}
{
var system_desc = ecs.system_desc_t{};
system_desc.callback = draw;
system_desc.query.filter.terms[0] = .{ .id = ecs.id(Position) };
system_desc.query.filter.terms[1] = .{ .id = ecs.id(Drawable) };
system_desc.query.filter.terms[2] = .{ .id = ecs.id(Foreground), .oper = ecs.oper_kind_t.Not };
system_desc.query.filter.terms[3] = .{ .id = ecs.id(Background), .oper = ecs.oper_kind_t.Not };
ecs.SYSTEM(world, "draw", ecs.PostUpdate, &system_desc);
}
{
var system_desc = ecs.system_desc_t{};
system_desc.callback = draw;
system_desc.query.filter.terms[0] = .{ .id = ecs.id(Position) };
system_desc.query.filter.terms[1] = .{ .id = ecs.id(Drawable) };
system_desc.query.filter.terms[2] = .{ .id = ecs.id(Foreground) };
ecs.SYSTEM(world, "draw_foreground", ecs.PostUpdate, &system_desc);
}
_ = singleton(world, ecs.EcsRest, .{});
return world;
}
fn generate_buildings(world: *ecs.world_t) void {
std.debug.print("here", .{});
var spacing: i32 = 0;
for (0..MAX_BUILDINGS) |_| {
const entity = ecs.new_entity(world, "");
const width: f32 = @floatFromInt(rl.GetRandomValue(50, 200));
const height: f32 = @floatFromInt(rl.GetRandomValue(100, 800));
const x: f32 = @floatFromInt(-6000 + spacing);
const building = rl.Rectangle{ .x = x, .y = 0, .width = width, .height = height };
spacing += @as(i32, @intFromFloat(width));
const r: u8 = @truncate(@as(u32, @intCast(rl.GetRandomValue(200, 240))));
const g: u8 = @truncate(@as(u32, @intCast(rl.GetRandomValue(200, 240))));
const b: u8 = @truncate(@as(u32, @intCast(rl.GetRandomValue(200, 240))));
std.debug.print("Color: {d} {d} {d}\n", .{ r, g, b });
const col = rl.Color{ .r = r, .g = g, .b = b, .a = 255 };
_ = ecs.set(world, entity, Position, .{ .x = building.x, .y = building.y });
_ = ecs.set(world, entity, Drawable, .{ .color_rect = .{ .rect = building, .color = col } });
_ = ecs.add(world, entity, Background);
}
}
pub fn main() anyerror!void {
const world = init_ecs();
defer _ = ecs.fini(world);
generate_buildings(world);
const player = ecs.new_entity(world, "Player");
_ = ecs.set(world, player, Position, .{ .x = 400, .y = 280 });
_ = ecs.set(world, player, Drawable, .{
.rect = rl.Rectangle{
.x = 0,
.y = 0,
.width = 40,
.height = 40,
},
});
_ = ecs.add(world, player, Player);
_ = ecs.add(world, player, CameraTarget);
// Initialization
//--------------------------------------------------------------------------------------
var exitWindow = false;
var game_state = GameState{ .startup = GameStateStartup{} };
var last_state = game_state;
rl.InitWindow(screen_width, screen_height, "ZigGame");
defer rl.CloseWindow();
rl.SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!exitWindow) {
switch (game_state) {
GameState.startup => {
last_state = game_state;
game_state = GameState.start_screen;
},
GameState.start_screen => {
last_state = game_state;
game_state = GameState.loop;
},
GameState.loop => {
if (rl.WindowShouldClose()) {
// last_state = game_state;
// game_state = GameState.exit_requested;
exitWindow = true;
}
},
GameState.exit_requested => {
if (rl.IsKeyPressed(rl.KEY_Y) or rl.IsKeyPressed(rl.KEY_Z)) {
exitWindow = true;
} else if (rl.IsKeyPressed(rl.KEY_N)) {
game_state = last_state;
}
},
}
rl.BeginDrawing();
defer rl.EndDrawing();
rl.ClearBackground(rl.WHITE);
rl.BeginMode2D(camera);
defer rl.EndMode2D();
_ = ecs.progress(world, 0);
}
}
pub const ecs_app_desc_t = extern struct {
target_fps: f32 = 0,
delta_time: f32 = 0,
threads: c_int = 0,
frames: c_int = 0,
enable_rest: bool = false,
enable_monitor: bool = false,
init: ?*anyopaque = null,
ctx: ?*anyopaque = null,
};
extern "c" fn ecs_app_run(world: *ecs.world_t, app_desc: *ecs_app_desc_t) c_int;
pub inline fn app_run(world: *ecs.world_t, app_desc: *ecs_app_desc_t) i32 {
return ecs_app_run(world, app_desc);
}
pub inline fn singleton(world: *ecs.world_t, comptime T: type, val: T) ecs.entity_t {
return ecs.set(world, ecs.id(T), T, val);
}
pub inline fn get_singleton_mut(world: *ecs.world_t, comptime T: type) ?*T {
return ecs.get_mut(world, ecs.id(T), T);
}
.{
.name = "zig-game",
.version = "0.0.1",
.paths = .{
"build.zig",
"build.zig.zon",
},
.dependencies = .{
// .zsdl = .{ .path = "thirdparty/zig-gamedev/libs/zsdl" },
// .zopengl = .{ .path = "thirdparty/zig-gamedev/libs/zopengl" },
// .zmath = .{ .path = "thirdparty/zig-gamedev/libs/zmath" },
// .zglfw = .{ .path = "thirdparty/zig-gamedev/libs/zglfw" },
// .zpool = .{ .path = "thirdparty/zig-gamedev/libs/zpool" },
// .zjobs = .{ .path = "thirdparty/zig-gamedev/libs/zjobs" },
// .zmesh = .{ .path = "thirdparty/zig-gamedev/libs/zmesh" },
// .znoise = .{ .path = "thirdparty/zig-gamedev/libs/znoise" },
// .zstbi = .{ .path = "thirdparty/zig-gamedev/libs/zstbi" },
// .zwin32 = .{ .path = "thirdparty/zig-gamedev/libs/zwin32" },
// .zd3d12 = .{ .path = "thirdparty/zig-gamedev/libs/zd3d12" },
// .zxaudio2 = .{ .path = "thirdparty/zig-gamedev/libs/zxaudio2" },
// .zpix = .{ .path = "thirdparty/zig-gamedev/libs/zpix" },
// .common = .{ .path = "thirdparty/zig-gamedev/libs/common" },
// .zbullet = .{ .path = "thirdparty/zig-gamedev/libs/zbullet" },
// .zgui = .{ .path = "thirdparty/zig-gamedev/libs/zgui" },
// .zgpu = .{ .path = "thirdparty/zig-gamedev/libs/zgpu" },
// .ztracy = .{ .path = "thirdparty/zig-gamedev/libs/ztracy" },
// .zphysics = .{ .path = "thirdparty/zig-gamedev/libs/zphysics" },
// .zaudio = .{ .path = "thirdparty/zig-gamedev/libs/zaudio" },
.zflecs = .{ .path = "thirdparty/zig-gamedev/libs/zflecs" },
// .system_sdk = .{ .path = "thirdparty/zig-gamedev/libs/system-sdk" },
// .dawn_x86_64_windows_gnu = .{
// .url = "https://github.com/michal-z/webgpu_dawn-x86_64-windows-gnu/archive/d3a68014e6b6b53fd330a0ccba99e4dcfffddae5.tar.gz",
// .hash = "1220f9448cde02ef3cd51bde2e0850d4489daa0541571d748154e89c6eb46c76a267",
// },
// .dawn_x86_64_linux_gnu = .{
// .url = "https://github.com/michal-z/webgpu_dawn-x86_64-linux-gnu/archive/7d70db023bf254546024629cbec5ee6113e12a42.tar.gz",
// .hash = "12204a3519efd49ea2d7cf63b544492a3a771d37eda320f86380813376801e4cfa73",
// },
// .dawn_aarch64_linux_gnu = .{
// .url = "https://github.com/michal-z/webgpu_dawn-aarch64-linux-gnu/archive/c1f55e740a62f6942ff046e709ecd509a005dbeb.tar.gz",
// .hash = "12205cd13f6849f94ef7688ee88c6b74c7918a5dfb514f8a403fcc2929a0aa342627",
// },
// .dawn_aarch64_macos = .{
// .url = "https://github.com/michal-z/webgpu_dawn-aarch64-macos/archive/d2360cdfff0cf4a780cb77aa47c57aca03cc6dfe.tar.gz",
// .hash = "12201fe677e9c7cfb8984a36446b329d5af23d03dc1e4f79a853399529e523a007fa",
// },
// .dawn_x86_64_macos = .{
// .url = "https://github.com/michal-z/webgpu_dawn-x86_64-macos/archive/901716b10b31ce3e0d3fe479326b41e91d59c661.tar.gz",
// .hash = "1220b1f02f2f7edd98a078c64e3100907d90311d94880a3cc5927e1ac009d002667a",
// },
},
}
const std = @import("std");
const raySdk = @import("thirdparty/raylib/src/build.zig");
const zflecs = @import("zflecs");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) !void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "zig_game",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(exe);
const raylib = try raySdk.addRaylib(b, target, optimize, .{});
exe.addIncludePath(.{ .path = "thirdparty/raylib/src" });
exe.linkLibrary(raylib);
const zflecs_pkg = zflecs.package(b, target, optimize, .{});
zflecs_pkg.link(exe);
// This *creates* a Run step in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Debug",
"type": "shell",
"command": "zig",
"args": [
"build",
"-Doptimize=Debug"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": []
}
]
}
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "lldb",
"request": "launch",
"program": "./zig-out/bin/zig_game",
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build Debug",
"terminal": "console",
}
]
}
[submodule "thirdparty/raylib"]
path = thirdparty/raylib
url = git@github.com:raysan5/raylib.git
[submodule "thirdparty/zig-gamedev"]
path = thirdparty/zig-gamedev
url = https://github.com/zig-gamedev/zig-gamedev
# Created by https://www.toptal.com/developers/gitignore/api/zig
# Edit at https://www.toptal.com/developers/gitignore?templates=zig
### zig ###
# Zig programming language
zig-cache/
zig-out/
build/
build-*/
docgen_tmp/
# End of https://www.toptal.com/developers/gitignore/api/zig