diff --git a/src/level.zig b/src/level.zig index f536a67..e2eb5fb 100644 --- a/src/level.zig +++ b/src/level.zig @@ -1,7 +1,12 @@ //! Level structure, grid containing tile data. +const ray = @cImport({ + @cInclude("raylib.h"); +}); const std = @import("std"); const expect = std.testing.expect; +const Vec2 = @import("vec2.zig"); + const Self = @This(); const cell_t = u16; @@ -13,13 +18,21 @@ buffer: []cell_t, /// Create structure and allocate required memory. The `buffer` array size will /// be equal to `width` times `height`. pub fn init(allocator: *std.mem.Allocator, width: u16, height: u16) !Self { - var level = Self{ + var self = Self{ .width = width, .height = height, .buffer = undefined, }; - level.buffer = try allocator.alloc(cell_t, width * height); - return level; + + // Try to allocate necessary memory. + self.buffer = try allocator.alloc(cell_t, width * height); + errdefer allocator.free(self.buffer); + + // Fill with 0s to avoid undefined behavior. + var i: u16 = 0; + while (i < self.width * self.height) : (i += 1) + self.buffer[i] = 0; + return self; } /// Free the level buffer. @@ -27,6 +40,32 @@ pub fn deinit(self: *Self, allocator: *std.mem.Allocator) void { allocator.free(self.buffer); } +/// Draw level tiles from `offset` to fill the window. +pub fn draw(self: *Self, offset: Vec2) void { + // Pixel position (were we draw). + var x: Vec2.int_type = 0; + var y: Vec2.int_type = 0; + // Cursor position. + var cx: Vec2.int_type = offset.x; + while (cx < self.width) { + var cy: Vec2.int_type = offset.y; + while (cy < self.height) { + const cell_content: cell_t = self.buffer[cx * self.width + cy]; + const color = switch (cell_content) { + 0 => ray.GRAY, + 1 => ray.WHITE, + else => ray.PURPLE, //unknown + }; + ray.DrawPixel(x, y, color); + y += 1; + cy += 1; + } + y = 0; + x += 1; + cx += 1; + } +} + test "create level buffer" { // Create allocator. var gpa = std.heap.GeneralPurposeAllocator(.{}){}; diff --git a/src/main.zig b/src/main.zig index 89fb684..ec36629 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,36 +1,57 @@ -const std = @import("std"); -const assert = std.debug.assert; -const Level = @import("level.zig"); const ray = @cImport({ @cInclude("raylib.h"); }); +const std = @import("std"); +const assert = std.debug.assert; +const format = std.fmt.format; +const maxInt = std.math.maxInt; + +const Level = @import("level.zig"); +const Vec2 = @import("vec2.zig"); pub fn main() !void { // Create allocator var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer { - const leaked = gpa.deinit(); + const leaked: bool = gpa.deinit(); if (leaked) assert(false); //raise error } const allocator = &gpa.allocator; - // Create window + // Create window. ray.SetConfigFlags(ray.FLAG_WINDOW_RESIZABLE); ray.InitWindow(640, 480, "KBLE"); defer ray.CloseWindow(); - // Limit FPS for performance + // Limit FPS for performance. ray.SetTargetFPS(60); // Create level var level: Level = try Level.init(allocator, 128, 128); defer level.deinit(allocator); + // Create camera + var camera: Vec2 = Vec2.init(0, 0); + while (!ray.WindowShouldClose()) { + // Temp code: move camera with arrow keys. + if (ray.IsKeyDown(ray.KEY_LEFT) and camera.x > 0) + camera.x -= 1; + if (ray.IsKeyDown(ray.KEY_RIGHT) and + camera.x < comptime maxInt(Vec2.int_type)) + camera.x += 1; + if (ray.IsKeyDown(ray.KEY_UP) and camera.y > 0) + camera.y -= 1; + if (ray.IsKeyDown(ray.KEY_DOWN) and + camera.y < comptime maxInt(Vec2.int_type)) + camera.y += 1; + + // Put all draw code after this. ray.BeginDrawing(); defer ray.EndDrawing(); - ray.ClearBackground(ray.RAYWHITE); - ray.DrawText("Hellowo!", 190, 200, 20, ray.LIGHTGRAY); + ray.ClearBackground(ray.BLACK); + level.draw(camera); + ray.DrawFPS(0, 0); } } diff --git a/src/vec2.zig b/src/vec2.zig index 27e4788..81b1de1 100644 --- a/src/vec2.zig +++ b/src/vec2.zig @@ -4,11 +4,13 @@ const expect = @import("std").testing.expect; const Self = @This(); -x: i32, -y: i32, +pub const int_type = u16; + +x: int_type, +y: int_type, /// Create a vector with `x` and `y` values. -pub fn init(x: i32, y: i32) Self { +pub fn init(x: int_type, y: int_type) Self { return Self { .x = x, .y = y,