Components

This commit is contained in:
duck
2025-07-28 23:12:17 +05:00
parent 7e162221ef
commit 92cc3e2f27
3 changed files with 114 additions and 23 deletions

89
src/components.zig Normal file
View File

@@ -0,0 +1,89 @@
const std = @import("std");
const err = @import("error.zig");
const Game = @import("game.zig");
pub const StorageOptions = struct {
min_capacity: usize = 32,
};
pub fn Storage(comptime T: type, comptime options: StorageOptions) type {
return struct {
pub const Key = packed struct {
cell: u32,
version: u32,
};
pub const MIN_CAPACITY = options.min_capacity;
const Array = std.ArrayListUnmanaged;
const Cell = struct {
component: T,
version: u32,
count: u32,
};
components: Array(Cell),
const Self = @This();
pub fn init() Self {
return .{
.components = Array(Cell).empty,
};
}
pub fn deinit(self: *Self) void {
self.components.deinit(Game.alloc);
}
pub fn add(self: *Self, component: T) Key {
for (0.., self.components.items) |i, *cell| {
if (cell.count == 0) {
return populateCell(cell, i, component);
}
}
const cell = self.components.addOne(Game.alloc) catch err.oom();
return populateCell(cell, self.components.items.len - 1, component);
}
pub fn lock(self: *Self, key: Key) void {
self.components.items[key.cell].count += 1;
}
pub fn get(self: *Self, key: Key) ?*T {
const cell = &self.components.items[key.cell];
if (cell.version == key.version) {
return &cell.component;
}
return null;
}
pub fn free(self: *Self, key: Key) bool {
self.components.items[key.cell].count -= 1;
}
pub fn iter(self: *Self) Iterator {
return .{
.array = self.components.items,
.current = 0,
};
}
fn populateCell(cell: *Cell, index: usize, component: T) Key {
cell.version += 1;
cell.count = 1;
cell.component = component;
return .{
.cell = @intCast(index),
.version = cell.version,
};
}
pub const Iterator = struct {
array: []Cell,
current: usize,
pub fn next(self: *@This()) ?*T {
while (self.current < self.array.len) {
defer self.current += 1;
if (self.array[self.current].count != 0) {
return &self.array[self.current].component;
}
}
return null;
}
};
};
}

View File

@@ -13,7 +13,7 @@ const Time = struct {
now: sdl.Time,
};
var alloc: std.mem.Allocator = undefined;
pub var alloc: std.mem.Allocator = undefined;
var running: bool = false;
var time: Time = .{ .delta = 0, .now = 0 };

View File

@@ -1,10 +1,11 @@
const Graphics = @import("graphics.zig");
const Entity = @import("entity.zig");
const Time = @import("time.zig");
const comp = @import("components.zig");
pub var time: Time = undefined;
var next_stop: Time = undefined;
var entities: [16]?Entity = undefined;
var entities: comp.Storage(Entity, .{}) = undefined;
pub var plane_mesh: Graphics.Mesh = undefined;
pub var cube_mesh: Graphics.Mesh = undefined;
@@ -12,25 +13,25 @@ pub var texture: Graphics.Texture = undefined;
const World = @This();
pub fn initDebug() void {
entities = .{null} ** 16;
entities[0] = .{
entities = comp.Storage(Entity, .{}).init();
_ = entities.add(.{
.position = .{ 0, 0 },
.player = true,
};
entities[1] = .{
});
_ = entities.add(.{
.position = .{ 2, 0 },
.enemy = true,
.controller = .{
.move_units = 0.25,
},
};
entities[2] = .{
});
_ = entities.add(.{
.position = .{ 3, 0 },
.enemy = true,
.controller = .{
.move_units = 0.25,
},
};
});
time = Time.ZERO;
World.plane_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA));
World.cube_mesh = Graphics.loadMesh(@ptrCast(&CUBE_MESH_DATA));
@@ -41,6 +42,7 @@ pub fn deinit() void {
Graphics.unloadMesh(World.plane_mesh);
Graphics.unloadMesh(World.cube_mesh);
Graphics.unloadTexture(World.texture);
World.entities.deinit();
}
pub fn updateReal(delta: f32) void {
@@ -49,16 +51,18 @@ pub fn updateReal(delta: f32) void {
const current = Time.earliest(World.next_stop, update_until);
defer World.time = current;
for (&World.entities) |*entity| {
if (entity.*) |*e| e.update();
var iter = World.entities.iter();
while (iter.next()) |entity| {
entity.update();
}
}
}
pub fn draw(delta: f32) void {
Graphics.drawMesh(World.plane_mesh, World.texture, .{ .scale = @splat(5) });
for (&World.entities) |*entity| {
if (entity.*) |*e| e.draw(delta);
var iter = World.entities.iter();
while (iter.next()) |entity| {
entity.draw(delta);
}
}
@@ -67,11 +71,10 @@ pub fn requestUpdate(at: Time) void {
}
pub fn entityAt(position: @Vector(2, i32)) ?*Entity {
for (&World.entities) |*maybe_entity| {
if (maybe_entity.*) |*entity| {
if (@reduce(.And, entity.position == position))
return entity;
}
var iter = World.entities.iter();
while (iter.next()) |entity| {
if (@reduce(.And, entity.position == position))
return entity;
}
return null;
}
@@ -81,11 +84,10 @@ pub fn isFree(position: @Vector(2, i32)) bool {
}
pub fn getPlayer() ?*Entity {
for (&World.entities) |*maybe_entity| {
if (maybe_entity.*) |*entity| {
if (entity.player)
return entity;
}
var iter = World.entities.iter();
while (iter.next()) |entity| {
if (entity.player)
return entity;
}
return null;
}