Remove ecs
parent
c87da2a4ae
commit
555c200033
191
src/ecs.zig
191
src/ecs.zig
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
141
src/main.zig
141
src/main.zig
|
@ -1,6 +1,5 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const w4 = @import("wasm4.zig");
|
const w4 = @import("wasm4.zig");
|
||||||
const ecs = @import("ecs.zig");
|
|
||||||
const assets = @import("assets");
|
const assets = @import("assets");
|
||||||
const input = @import("input.zig");
|
const input = @import("input.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
@ -271,6 +270,7 @@ export fn update() void {
|
||||||
velocityProcess(1, &player.pos);
|
velocityProcess(1, &player.pos);
|
||||||
physicsProcess(1, &player.pos, &player.physics);
|
physicsProcess(1, &player.pos, &player.physics);
|
||||||
circuitManipulationProcess(1, &player.pos, &player.control);
|
circuitManipulationProcess(1, &player.pos, &player.control);
|
||||||
|
wireManipulationProcess(1, &player.pos, &player.control);
|
||||||
controlProcess(1, &player.pos, &player.control, &player.physics, &player.kinematic);
|
controlProcess(1, &player.pos, &player.control, &player.physics, &player.kinematic);
|
||||||
kinematicProcess(1, &player.pos, &player.kinematic);
|
kinematicProcess(1, &player.pos, &player.kinematic);
|
||||||
controlAnimProcess(1, &player.sprite, &player.controlAnim, &player.control);
|
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 {
|
fn wireManipulationProcess(_: f32, pos: *Pos, control: *Control) void {
|
||||||
// var offset = switch (control.facing) {
|
var offset = switch (control.facing) {
|
||||||
// .left => Vec2f{ -6, -4 },
|
.left => Vec2f{ -6, -4 },
|
||||||
// .right => Vec2f{ 6, -4 },
|
.right => Vec2f{ 6, -4 },
|
||||||
// .up => Vec2f{ 0, -12 },
|
.up => Vec2f{ 0, -12 },
|
||||||
// .down => Vec2f{ 0, 4 },
|
.down => Vec2f{ 0, 4 },
|
||||||
// };
|
};
|
||||||
// var offsetPos = pos.pos + offset;
|
var offsetPos = pos.pos + offset;
|
||||||
// var entity: World.Component = undefined;
|
var mapPos = util.world2cell(offsetPos);
|
||||||
// var mapPos = util.world2cell(offsetPos);
|
|
||||||
|
|
||||||
// if (control.grabbing) |details| {
|
if (control.grabbing) |details| {
|
||||||
// entity = world.get(details.id);
|
var wire = &wires.slice()[details.id];
|
||||||
// var wire = &entity.wire.?;
|
var nodes = wire.nodes.slice();
|
||||||
// var nodes = wire.nodes.slice();
|
|
||||||
|
|
||||||
// var maxLength = wireMaxLength(wire);
|
var maxLength = wireMaxLength(wire);
|
||||||
// var length = wireLength(wire);
|
var length = wireLength(wire);
|
||||||
|
|
||||||
// if (length > maxLength * 1.5) {
|
if (length > maxLength * 1.5) {
|
||||||
// nodes[details.which].pinned = false;
|
nodes[details.which].pinned = false;
|
||||||
// control.grabbing = null;
|
control.grabbing = null;
|
||||||
// world.set(details.id, entity);
|
return;
|
||||||
// return;
|
} else {
|
||||||
// } else {
|
nodes[details.which].pos = pos.pos + Vec2f{ 0, -4 };
|
||||||
// nodes[details.which].pos = pos.pos + Vec2f{ 0, -4 };
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// if (Circuit.is_plug(circuit.get_cell(mapPos) orelse 0)) {
|
if (Circuit.is_plug(circuit.get_cell(mapPos) orelse 0)) {
|
||||||
// const active = circuit.isEnabled(mapPos);
|
const active = circuit.isEnabled(mapPos);
|
||||||
// indicator = .{ .t = .plug, .pos = mapPos * @splat(2, @as(i32, 8)) + Vec2{ 4, 4 }, .active = active };
|
indicator = .{ .t = .plug, .pos = mapPos * @splat(2, @as(i32, 8)) + Vec2{ 4, 4 }, .active = active };
|
||||||
// if (input.btnp(.one, .two)) {
|
if (input.btnp(.one, .two)) {
|
||||||
// nodes[details.which].pinned = true;
|
nodes[details.which].pinned = true;
|
||||||
// nodes[details.which].pos = vec2tovec2f(indicator.?.pos);
|
nodes[details.which].pos = vec2tovec2f(indicator.?.pos);
|
||||||
// nodes[details.which].last = vec2tovec2f(indicator.?.pos);
|
nodes[details.which].last = vec2tovec2f(indicator.?.pos);
|
||||||
// control.grabbing = null;
|
control.grabbing = null;
|
||||||
// }
|
}
|
||||||
// } else if (input.btnp(.one, .two)) {
|
} else if (input.btnp(.one, .two)) {
|
||||||
// nodes[details.which].pinned = false;
|
nodes[details.which].pinned = false;
|
||||||
// control.grabbing = null;
|
control.grabbing = null;
|
||||||
// }
|
}
|
||||||
// world.set(details.id, entity);
|
} else {
|
||||||
// } else {
|
const interactDistance = 4;
|
||||||
// const interactDistance = 4;
|
var minDistance: f32 = interactDistance;
|
||||||
// var minDistance: f32 = interactDistance;
|
var interactWireID: ?usize = null;
|
||||||
// var wireIter = world.iter(WireQuery);
|
var which: usize = 0;
|
||||||
// var interactWireID: ?usize = null;
|
for (wires.slice()) |*wire, wireID| {
|
||||||
// var which: usize = 0;
|
const nodes = wire.nodes.constSlice();
|
||||||
// while (wireIter.next()) |entityID| {
|
const begin = nodes[0].pos;
|
||||||
// entity = world.get(entityID);
|
const end = nodes[wire.nodes.len - 1].pos;
|
||||||
// const wire = entity.wire.?;
|
var dist = util.distancef(begin, offsetPos);
|
||||||
// const nodes = wire.nodes.constSlice();
|
if (dist < minDistance) {
|
||||||
// const begin = nodes[0].pos;
|
minDistance = dist;
|
||||||
// const end = nodes[wire.nodes.len - 1].pos;
|
indicator = .{ .t = .wire, .pos = vec2ftovec2(begin), .active = wire.enabled };
|
||||||
// var dist = util.distancef(begin, offsetPos);
|
interactWireID = wireID;
|
||||||
// if (dist < minDistance) {
|
which = 0;
|
||||||
// minDistance = dist;
|
}
|
||||||
// indicator = .{ .t = .wire, .pos = vec2ftovec2(begin), .active = wire.enabled };
|
dist = util.distancef(end, offsetPos);
|
||||||
// interactWireID = entityID;
|
if (dist < minDistance) {
|
||||||
// which = 0;
|
minDistance = dist;
|
||||||
// }
|
indicator = .{ .t = .wire, .pos = vec2ftovec2(end), .active = wire.enabled };
|
||||||
// dist = util.distancef(end, offsetPos);
|
interactWireID = wireID;
|
||||||
// if (dist < minDistance) {
|
which = wire.nodes.len - 1;
|
||||||
// minDistance = dist;
|
}
|
||||||
// indicator = .{ .t = .wire, .pos = vec2ftovec2(end), .active = wire.enabled };
|
}
|
||||||
// interactWireID = entityID;
|
if (interactWireID) |wireID| {
|
||||||
// which = wire.nodes.len - 1;
|
if (input.btnp(.one, .two)) {
|
||||||
// }
|
control.grabbing = .{ .id = wireID, .which = which };
|
||||||
// }
|
}
|
||||||
// if (interactWireID) |wireID| {
|
}
|
||||||
// entity = world.get(wireID);
|
}
|
||||||
// if (input.btnp(.one, .two)) {
|
}
|
||||||
// control.grabbing = .{ .id = wireID, .which = which };
|
|
||||||
// }
|
|
||||||
// world.set(wireID, entity);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn wirePhysicsProcess(dt: f32, wire: *Wire) void {
|
fn wirePhysicsProcess(dt: f32, wire: *Wire) void {
|
||||||
var nodes = wire.nodes.slice();
|
var nodes = wire.nodes.slice();
|
||||||
|
|
Loading…
Reference in New Issue