tins2023/src/game/level.zig
Sander Schobers 7a89b05f8e Progress over >1 day.
- Added debug overlay.
- Added game scene.
  * Rendering of background, tiles, items & player.
  * Added levels (reading from text file).
  * No collision detection yet.
- Automatic resizing of fonts.
- Added sprites (animate textures).
- Lots of utility methods everywhere....
2023-06-04 17:05:20 +02:00

128 lines
3.7 KiB
Zig

const std = @import("std");
const engine = @import("../engine.zig");
pub const Level = struct {
pub fn Column(comptime Value: type) type {
return struct {
const Self = @This();
values: std.AutoHashMap(i64, Value),
pub fn init(allocator: std.mem.Allocator) Self {
return Self{
.values = std.AutoHashMap(i64, Value).init(allocator),
};
}
pub fn deinit(self: Self) void {
self.values.deinit();
}
pub fn get(self: Self, row: i64) ?Value {
return self.values.get(row);
}
pub fn set(self: *Self, row: i64, value: Value) !void {
try self.values.put(row, value);
}
};
}
pub fn Components(comptime Value: type) type {
return struct {
const Self = @This();
allocator: std.mem.Allocator,
columns: std.ArrayList(Column(Value)),
pub fn init(allocator: std.mem.Allocator) Self {
return Self{
.allocator = allocator,
.columns = std.ArrayList(Column(Value)).init(allocator),
};
}
pub fn deinit(self: Self) void {
for (self.columns.items) |item| {
item.deinit();
}
self.columns.deinit();
}
pub fn column(self: Self, i: i64) *Column(Value) {
return &self.columns.items[@intCast(usize, i)];
}
fn ensureColumns(self: *Self, n: usize) !void {
while (self.columns.items.len < n) {
try self.columns.append(Column(Value).init(self.allocator));
}
}
pub fn set(self: *Self, c: i64, r: i64, value: Value) !void {
try self.ensureColumns(@intCast(usize, c) + 1);
try self.column(c).set(r, value);
}
};
}
pub const Tile = enum {
Grass,
};
pub const Collectable = enum {
Star,
};
character: engine.Point,
tiles: Components(Tile),
collectables: Components(Collectable),
pub fn load(allocator: std.mem.Allocator, path: []const u8) !Level {
const path_ = try std.fs.realpathAlloc(allocator, path);
defer allocator.free(path_);
const file = try std.fs.openFileAbsolute(path_, .{ .mode = .read_only });
defer file.close();
const data = try file.readToEndAlloc(allocator, 1024 * 1024);
defer allocator.free(data);
return try Level.loadFromMemory(allocator, data);
}
pub fn loadFromMemory(allocator: std.mem.Allocator, data: []const u8) !Level {
const n = std.mem.count(u8, data, "\n");
_ = n;
var character: ?engine.Point = null;
var tiles = Components(Tile).init(allocator);
var collectables = Components(Collectable).init(allocator);
var lines = std.mem.split(u8, data, "\n");
var y: i64 = 0;
while (lines.next()) |line| {
defer y += 1;
try tiles.ensureColumns(line.len);
try collectables.ensureColumns(line.len);
for (line, 0..) |tile, column| {
var x = @intCast(i64, column);
switch (tile) {
'P' => character = engine.Point.init(x, y),
'S' => try collectables.set(x, y, Collectable.Star),
'x' => try tiles.set(x, y, Tile.Grass),
else => {},
}
}
}
return Level{
.character = character.?,
.tiles = tiles,
.collectables = collectables,
};
}
};