diff --git a/src/ecs.zig b/src/ecs.zig deleted file mode 100644 index ec0c4cb..0000000 --- a/src/ecs.zig +++ /dev/null @@ -1,191 +0,0 @@ -const std = @import("std"); -const ArgsTuple = std.meta.Tuple; -const Tuple = std.meta.Tuple; - -pub fn World(comptime ComponentBase: type) type { - // Build a component type at comptime based off of ComponentBase. It makes all the fields - // nullable so they are easy to pull out of the store. - const ComponentCon = componentConstructor: { - var fields = std.meta.fields(ComponentBase); - var newFields: [fields.len]std.builtin.TypeInfo.StructField = undefined; - inline for (fields) |field, i| { - const T = field.field_type; - const default: ?T = null; - newFields[i] = std.builtin.TypeInfo.StructField{ - .name = field.name, - .field_type = ?T, - .default_value = default, - .is_comptime = false, - .alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0, - }; - } - break :componentConstructor @Type(.{ .Struct = .{ - .layout = .Auto, - .fields = &newFields, - .decls = &[_]std.builtin.TypeInfo.Declaration{}, - .is_tuple = false, - } }); - }; - return struct { - components: ComponentPool, - alloc: std.mem.Allocator, - pub const Query = ComponentQuery; - pub const Component = ComponentCon; - - const ComponentPool = std.MultiArrayList(Component); - const ComponentEnum = std.meta.FieldEnum(Component); - const ComponentSet = std.EnumSet(ComponentEnum); - const ComponentQuery = struct { - required: ComponentSet = ComponentSet.init(.{}), - excluded: ComponentSet = ComponentSet.init(.{}), - - pub fn init() @This() { - return @This(){}; - } - - pub fn query(require_set: []const ComponentEnum, exclude_set: []const ComponentEnum) @This() { - var this = @This(){}; - for (require_set) |f| { - this.required.insert(f); - } - for (exclude_set) |f| { - this.excluded.insert(f); - } - return this; - } - - pub fn require(require_set: []const ComponentEnum) @This() { - var this = @This(){}; - for (require_set) |f| { - this.required.insert(f); - } - return this; - } - - pub fn exclude(exclude_set: []const ComponentEnum) @This() { - var this = @This(){}; - for (exclude_set) |f| { - this.excluded.insert(f); - } - return this; - } - }; - - const fields = std.meta.fields(Component); - - pub fn init(alloc: std.mem.Allocator) @This() { - return @This(){ - .components = ComponentPool{}, - .alloc = alloc, - }; - } - - pub fn create(this: *@This(), component: Component) !usize { - const len = this.components.len; - try this.components.append(this.alloc, component); - return len; - } - - pub fn destroy(this: *@This(), entity: usize) void { - // TODO - _ = this; - _ = entity; - @compileError("unimplemented"); - } - - /// Returns a copy of the components on an entity - pub fn get(this: *@This(), entity: usize) Component { - return this.components.get(entity); - } - - pub fn set(this: *@This(), entity: usize, component: Component) void { - this.components.set(entity, component); - } - - fn enum2type(comptime enumList: []const ComponentEnum) []type { - var t: [enumList.len]type = undefined; - inline for (enumList) |e, i| { - const field_type = @typeInfo(fields[@enumToInt(e)].field_type); - t[i] = *field_type.Optional.child; - } - return &t; - } - - pub fn process(this: *@This(), dt: f32, comptime comp: []const ComponentEnum, func: anytype) void { - const Args = Tuple([_]type{f32} ++ enum2type(comp)); - var i = this.iter(Query.require(comp)); - while (i.next()) |eID| { - var e = this.get(eID); - var args: Args = undefined; - args[0] = dt; - inline for (comp) |f, j| { - args[j + 1] = &(@field(e, @tagName(f)).?); - } - @call(.{}, func, args); - this.set(eID, e); - } - } - - pub fn processWithID(this: *@This(), dt: f32, comptime comp: []const ComponentEnum, func: anytype) void { - const Args = Tuple([_]type{ f32, usize } ++ enum2type(comp)); - var i = this.iter(Query.require(comp)); - while (i.next()) |eID| { - var e = this.get(eID); - var args: Args = undefined; - args[0] = dt; - args[1] = eID; - inline for (comp) |f, j| { - args[j + 2] = &(@field(e, @tagName(f)).?); - } - @call(.{}, func, args); - this.set(eID, e); - } - } - - pub fn iterAll(this: *@This()) Iterator { - return Iterator.init(this, ComponentQuery{}); - } - - pub fn iter(this: *@This(), query: ComponentQuery) Iterator { - return Iterator.init(this, query); - } - - const Self = @This(); - const Iterator = struct { - world: *Self, - index: usize, - query: ComponentQuery, - - pub fn init(w: *Self, q: ComponentQuery) @This() { - return @This(){ - .world = w, - .index = 0, - .query = q, - }; - } - - pub fn next(this: *@This()) ?usize { - if (this.index == this.world.components.len) return null; - var match = false; - while (!match) { - if (this.index == this.world.components.len) return null; - const e = this.world.components.get(this.index); - match = true; - inline for (fields) |f| { - const fenum = std.meta.stringToEnum(ComponentEnum, f.name) orelse unreachable; - const required = this.query.required.contains(fenum); - const excluded = this.query.excluded.contains(fenum); - const has = @field(e, f.name) != null; - if ((required and !has) or (excluded and has)) { - match = false; - break; - } - } - this.index += 1; - if (match) return this.index - 1; - } - return null; - } - }; - }; -} diff --git a/src/main.zig b/src/main.zig index 4c6aa78..c023112 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,5 @@ const std = @import("std"); const w4 = @import("wasm4.zig"); -const ecs = @import("ecs.zig"); const assets = @import("assets"); const input = @import("input.zig"); const util = @import("util.zig"); @@ -271,6 +270,7 @@ export fn update() void { velocityProcess(1, &player.pos); physicsProcess(1, &player.pos, &player.physics); circuitManipulationProcess(1, &player.pos, &player.control); + wireManipulationProcess(1, &player.pos, &player.control); controlProcess(1, &player.pos, &player.control, &player.physics, &player.kinematic); kinematicProcess(1, &player.pos, &player.kinematic); controlAnimProcess(1, &player.sprite, &player.controlAnim, &player.control); @@ -369,84 +369,75 @@ fn circuitManipulationProcess(_: f32, pos: *Pos, control: *Control) void { } } -// fn wireManipulationProcess(_: f32, pos: *Pos, control: *Control) void { -// var offset = switch (control.facing) { -// .left => Vec2f{ -6, -4 }, -// .right => Vec2f{ 6, -4 }, -// .up => Vec2f{ 0, -12 }, -// .down => Vec2f{ 0, 4 }, -// }; -// var offsetPos = pos.pos + offset; -// var entity: World.Component = undefined; -// var mapPos = util.world2cell(offsetPos); +fn wireManipulationProcess(_: f32, pos: *Pos, control: *Control) void { + var offset = switch (control.facing) { + .left => Vec2f{ -6, -4 }, + .right => Vec2f{ 6, -4 }, + .up => Vec2f{ 0, -12 }, + .down => Vec2f{ 0, 4 }, + }; + var offsetPos = pos.pos + offset; + var mapPos = util.world2cell(offsetPos); -// if (control.grabbing) |details| { -// entity = world.get(details.id); -// var wire = &entity.wire.?; -// var nodes = wire.nodes.slice(); + if (control.grabbing) |details| { + var wire = &wires.slice()[details.id]; + var nodes = wire.nodes.slice(); -// var maxLength = wireMaxLength(wire); -// var length = wireLength(wire); + var maxLength = wireMaxLength(wire); + var length = wireLength(wire); -// if (length > maxLength * 1.5) { -// nodes[details.which].pinned = false; -// control.grabbing = null; -// world.set(details.id, entity); -// return; -// } else { -// nodes[details.which].pos = pos.pos + Vec2f{ 0, -4 }; -// } + if (length > maxLength * 1.5) { + nodes[details.which].pinned = false; + control.grabbing = null; + return; + } else { + nodes[details.which].pos = pos.pos + Vec2f{ 0, -4 }; + } -// if (Circuit.is_plug(circuit.get_cell(mapPos) orelse 0)) { -// const active = circuit.isEnabled(mapPos); -// indicator = .{ .t = .plug, .pos = mapPos * @splat(2, @as(i32, 8)) + Vec2{ 4, 4 }, .active = active }; -// if (input.btnp(.one, .two)) { -// nodes[details.which].pinned = true; -// nodes[details.which].pos = vec2tovec2f(indicator.?.pos); -// nodes[details.which].last = vec2tovec2f(indicator.?.pos); -// control.grabbing = null; -// } -// } else if (input.btnp(.one, .two)) { -// nodes[details.which].pinned = false; -// control.grabbing = null; -// } -// world.set(details.id, entity); -// } else { -// const interactDistance = 4; -// var minDistance: f32 = interactDistance; -// var wireIter = world.iter(WireQuery); -// var interactWireID: ?usize = null; -// var which: usize = 0; -// while (wireIter.next()) |entityID| { -// entity = world.get(entityID); -// const wire = entity.wire.?; -// const nodes = wire.nodes.constSlice(); -// const begin = nodes[0].pos; -// const end = nodes[wire.nodes.len - 1].pos; -// var dist = util.distancef(begin, offsetPos); -// if (dist < minDistance) { -// minDistance = dist; -// indicator = .{ .t = .wire, .pos = vec2ftovec2(begin), .active = wire.enabled }; -// interactWireID = entityID; -// which = 0; -// } -// dist = util.distancef(end, offsetPos); -// if (dist < minDistance) { -// minDistance = dist; -// indicator = .{ .t = .wire, .pos = vec2ftovec2(end), .active = wire.enabled }; -// interactWireID = entityID; -// which = wire.nodes.len - 1; -// } -// } -// if (interactWireID) |wireID| { -// entity = world.get(wireID); -// if (input.btnp(.one, .two)) { -// control.grabbing = .{ .id = wireID, .which = which }; -// } -// world.set(wireID, entity); -// } -// } -// } + if (Circuit.is_plug(circuit.get_cell(mapPos) orelse 0)) { + const active = circuit.isEnabled(mapPos); + indicator = .{ .t = .plug, .pos = mapPos * @splat(2, @as(i32, 8)) + Vec2{ 4, 4 }, .active = active }; + if (input.btnp(.one, .two)) { + nodes[details.which].pinned = true; + nodes[details.which].pos = vec2tovec2f(indicator.?.pos); + nodes[details.which].last = vec2tovec2f(indicator.?.pos); + control.grabbing = null; + } + } else if (input.btnp(.one, .two)) { + nodes[details.which].pinned = false; + control.grabbing = null; + } + } else { + const interactDistance = 4; + var minDistance: f32 = interactDistance; + var interactWireID: ?usize = null; + var which: usize = 0; + for (wires.slice()) |*wire, wireID| { + const nodes = wire.nodes.constSlice(); + const begin = nodes[0].pos; + const end = nodes[wire.nodes.len - 1].pos; + var dist = util.distancef(begin, offsetPos); + if (dist < minDistance) { + minDistance = dist; + indicator = .{ .t = .wire, .pos = vec2ftovec2(begin), .active = wire.enabled }; + interactWireID = wireID; + which = 0; + } + dist = util.distancef(end, offsetPos); + if (dist < minDistance) { + minDistance = dist; + indicator = .{ .t = .wire, .pos = vec2ftovec2(end), .active = wire.enabled }; + interactWireID = wireID; + which = wire.nodes.len - 1; + } + } + if (interactWireID) |wireID| { + if (input.btnp(.one, .two)) { + control.grabbing = .{ .id = wireID, .which = which }; + } + } + } +} fn wirePhysicsProcess(dt: f32, wire: *Wire) void { var nodes = wire.nodes.slice();