Add wires to database
parent
1404d6067e
commit
af85ae5ae7
11
src/game.zig
11
src/game.zig
|
@ -149,7 +149,7 @@ var frame_fba_buf: [8192]u8 = undefined;
|
|||
var frame_fba = std.heap.FixedBufferAllocator.init(&frame_fba_buf);
|
||||
var frame_alloc = frame_fba.allocator();
|
||||
|
||||
var db_fba_buf: [1024]u8 = undefined;
|
||||
var db_fba_buf: [2046]u8 = undefined;
|
||||
var db_fba = std.heap.FixedBufferAllocator.init(&db_fba_buf);
|
||||
var db_alloc = db_fba.allocator();
|
||||
|
||||
|
@ -226,9 +226,11 @@ fn loadLevel(lvl: usize) !void {
|
|||
{
|
||||
_ = try wires.resize(0);
|
||||
var a: usize = 0;
|
||||
while (db.getWire(level, a)) |wire| : (a += 1) {
|
||||
while (db.getWire(level, a)) |wireSlice| : (a += 1) {
|
||||
const wire = try world.Wire.getEnds(wireSlice);
|
||||
const coord0 = wire[0].coord.subC(levelc);
|
||||
const coord1 = wire[1].coord.subC(levelc);
|
||||
w4.tracef("---- Wire (%d, %d), (%d, %d)", coord0.val[0], coord0.val[1], coord1.val[0], coord1.val[1]);
|
||||
const p1 = util.vec2ToVec2f(coord0.toVec2() * tile_size + Vec2{ 4, 4 });
|
||||
const p2 = util.vec2ToVec2f(coord1.toVec2() * tile_size + Vec2{ 4, 4 });
|
||||
|
||||
|
@ -243,8 +245,8 @@ fn loadLevel(lvl: usize) !void {
|
|||
w.begin().pos = p1;
|
||||
w.end().pos = p2;
|
||||
|
||||
w.begin().pinned = wire[0].kind == world.EntityKind.WireAnchor;
|
||||
w.end().pinned = wire[1].kind == world.EntityKind.WireEndAnchor;
|
||||
w.begin().pinned = wire[0].anchored;
|
||||
w.end().pinned = wire[1].anchored;
|
||||
|
||||
w.straighten();
|
||||
}
|
||||
|
@ -530,6 +532,7 @@ pub fn update(time: usize) !State {
|
|||
return .Game;
|
||||
}
|
||||
|
||||
/// Holds data related to selecting/interacting with the world
|
||||
const Interaction = struct {
|
||||
pos: Vec2,
|
||||
details: union(enum) {
|
||||
|
|
|
@ -38,6 +38,7 @@ export fn update() void {
|
|||
error.NoLevelUp => showErr(@errorName(e)),
|
||||
error.NoLevelLeft => showErr(@errorName(e)),
|
||||
error.NoLevelRight => showErr(@errorName(e)),
|
||||
error.MissingEnds => showErr(@errorName(e)),
|
||||
},
|
||||
};
|
||||
if (state != newState) {
|
||||
|
@ -52,6 +53,7 @@ export fn update() void {
|
|||
error.NullTiles => showErr(@errorName(e)),
|
||||
error.SpawnOutOfBounds => showErr(@errorName(e)),
|
||||
error.InvalidLevel => showErr(@errorName(e)),
|
||||
error.MissingEnds => showErr(@errorName(e)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
174
src/world.zig
174
src/world.zig
|
@ -190,6 +190,10 @@ pub const Coordinate = struct {
|
|||
return .{ .val = .{ coord.val[0] - other.val[0], coord.val[1] - other.val[1] } };
|
||||
}
|
||||
|
||||
pub fn addOffset(coord: Coordinate, val: [2]i4) Coordinate {
|
||||
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
|
||||
}
|
||||
|
||||
pub fn eq(coord: Coordinate, other: Coordinate) bool {
|
||||
return coord.val[0] == other.val[0] and coord.val[1] == other.val[1];
|
||||
}
|
||||
|
@ -209,6 +213,10 @@ pub const Coordinate = struct {
|
|||
return .{ coord.val[0], coord.val[1] };
|
||||
}
|
||||
|
||||
pub fn toOffset(coord: Coordinate) [2]i4 {
|
||||
return .{ @intCast(i4, coord.val[0]), @intCast(i4, coord.val[1]) };
|
||||
}
|
||||
|
||||
pub fn fromWorld(x: i8, y: i8) Coordinate {
|
||||
return .{ .val = .{
|
||||
@intCast(i16, x) * 20,
|
||||
|
@ -429,10 +437,6 @@ pub const AutoTileset = struct {
|
|||
pub const EntityKind = enum(u8) {
|
||||
Player,
|
||||
Coin,
|
||||
WireNode,
|
||||
WireAnchor,
|
||||
WireEndNode,
|
||||
WireEndAnchor,
|
||||
Door,
|
||||
Trapdoor,
|
||||
Collected,
|
||||
|
@ -461,12 +465,109 @@ pub const Entity = struct {
|
|||
}
|
||||
};
|
||||
|
||||
// Data format:
|
||||
// | level count | node count |
|
||||
// | level headers... |
|
||||
// | node data... |
|
||||
// | level data... |
|
||||
const WireKind = enum {
|
||||
Begin,
|
||||
BeginPinned,
|
||||
Point,
|
||||
PointPinned,
|
||||
End,
|
||||
};
|
||||
|
||||
/// A wire is stored as a coordinate and at least one point relative to it,
|
||||
/// and then an end byte
|
||||
pub const Wire = union(enum) {
|
||||
Begin: Coordinate,
|
||||
BeginPinned: Coordinate,
|
||||
/// Relative to the last point
|
||||
Point: [2]i4,
|
||||
/// Relative to the last point
|
||||
PointPinned: [2]i4,
|
||||
End,
|
||||
|
||||
const EndData = struct { coord: Coordinate, anchored: bool };
|
||||
|
||||
pub fn getEnds(wires: []Wire) ![2]EndData {
|
||||
std.debug.assert(wires[0] == .Begin or wires[0] == .BeginPinned);
|
||||
var ends: [2]EndData = undefined;
|
||||
const w4 = @import("wasm4.zig");
|
||||
for (wires) |wire| {
|
||||
switch (wire) {
|
||||
.Begin => |coord| {
|
||||
ends[0] = .{ .coord = coord, .anchored = false };
|
||||
ends[1] = ends[0];
|
||||
w4.tracef("[getEnds] Begin (%d, %d)", coord.val[0], coord.val[1]);
|
||||
},
|
||||
.BeginPinned => |coord| {
|
||||
ends[0] = .{ .coord = coord, .anchored = true };
|
||||
ends[1] = ends[0];
|
||||
w4.tracef("[getEnds] BeginPinned (%d, %d)", coord.val[0], coord.val[1]);
|
||||
},
|
||||
.Point => |offset| {
|
||||
ends[1] = .{ .coord = ends[1].coord.addOffset(offset), .anchored = false };
|
||||
const o1 = @intCast(i32, offset[0]);
|
||||
const o2 = @intCast(i32, offset[1]);
|
||||
w4.tracef("[getEnds] Point (%d, %d)", o1, o2);
|
||||
},
|
||||
.PointPinned => |offset| {
|
||||
ends[1] = .{ .coord = ends[1].coord.addOffset(offset), .anchored = true };
|
||||
const o1 = @intCast(i32, offset[0]);
|
||||
const o2 = @intCast(i32, offset[1]);
|
||||
w4.tracef("[getEnds] Point Pinned (%d, %d)", o1, o2);
|
||||
},
|
||||
.End => {
|
||||
return ends;
|
||||
},
|
||||
}
|
||||
}
|
||||
return error.MissingEnds;
|
||||
}
|
||||
|
||||
pub fn write(wire: Wire, writer: anytype) !void {
|
||||
try writer.writeByte(@enumToInt(wire));
|
||||
switch (wire) {
|
||||
.Begin => |coord| {
|
||||
try coord.write(writer);
|
||||
},
|
||||
.BeginPinned => |coord| {
|
||||
try coord.write(writer);
|
||||
},
|
||||
.Point => |point| {
|
||||
const byte = @bitCast(u8, @intCast(i8, point[0])) | @bitCast(u8, @intCast(i8, point[1])) << 4;
|
||||
try writer.writeByte(byte);
|
||||
},
|
||||
.PointPinned => |point| {
|
||||
const byte = @bitCast(u8, @intCast(i8, point[0])) | @bitCast(u8, @intCast(i8, point[1])) << 4;
|
||||
try writer.writeByte(byte);
|
||||
},
|
||||
.End => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(reader: anytype) !Wire {
|
||||
const kind = @intToEnum(WireKind, try reader.readByte());
|
||||
switch (kind) {
|
||||
.Begin => return Wire{ .Begin = try Coord.read(reader) },
|
||||
.BeginPinned => return Wire{ .BeginPinned = try Coord.read(reader) },
|
||||
.Point => {
|
||||
const byte = try reader.readByte();
|
||||
return Wire{ .Point = .{
|
||||
@bitCast(i4, @truncate(u4, 0b0000_1111 & byte)),
|
||||
@bitCast(i4, @truncate(u4, (0b1111_0000 & byte) >> 4)),
|
||||
} };
|
||||
},
|
||||
.PointPinned => {
|
||||
const byte = try reader.readByte();
|
||||
return Wire{ .PointPinned = .{
|
||||
@bitCast(i4, @truncate(u4, 0b0000_1111 & byte)),
|
||||
@bitCast(i4, @truncate(u4, (0b1111_0000 & byte) >> 4)),
|
||||
} };
|
||||
},
|
||||
.End => return Wire.End,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Used to look up level data
|
||||
pub const LevelHeader = struct {
|
||||
x: i8,
|
||||
y: i8,
|
||||
|
@ -491,6 +592,7 @@ pub fn write(
|
|||
writer: anytype,
|
||||
level_headers: []LevelHeader,
|
||||
entities: []Entity,
|
||||
wires: []Wire,
|
||||
circuit_nodes: []CircuitNode,
|
||||
levels: []Level,
|
||||
) !void {
|
||||
|
@ -498,6 +600,8 @@ pub fn write(
|
|||
try writer.writeInt(u16, @intCast(u16, level_headers.len), .Little);
|
||||
// Write number of entities
|
||||
try writer.writeInt(u16, @intCast(u16, entities.len), .Little);
|
||||
// Write number of entities
|
||||
try writer.writeInt(u16, @intCast(u16, wires.len), .Little);
|
||||
// Write number of circuit nodes
|
||||
try writer.writeInt(u16, @intCast(u16, circuit_nodes.len), .Little);
|
||||
|
||||
|
@ -511,6 +615,11 @@ pub fn write(
|
|||
try entity.write(writer);
|
||||
}
|
||||
|
||||
// Write wire data
|
||||
for (wires) |wire| {
|
||||
try wire.write(writer);
|
||||
}
|
||||
|
||||
// Write node data
|
||||
for (circuit_nodes) |node| {
|
||||
try node.write(writer);
|
||||
|
@ -527,6 +636,8 @@ pub const Database = struct {
|
|||
cursor: Cursor,
|
||||
level_info: []LevelHeader,
|
||||
entities: []Entity,
|
||||
wires: []Wire,
|
||||
wire_count: usize,
|
||||
circuit_info: []CircuitNode,
|
||||
level_data_begin: usize,
|
||||
|
||||
|
@ -544,6 +655,8 @@ pub const Database = struct {
|
|||
const level_count = try reader.readInt(u16, .Little);
|
||||
// read number of entities
|
||||
const entity_count = try reader.readInt(u16, .Little);
|
||||
// read number of wires
|
||||
const wire_count = try reader.readInt(u16, .Little);
|
||||
// read number of nodes
|
||||
const node_count = try reader.readInt(u16, .Little);
|
||||
|
||||
|
@ -561,6 +674,16 @@ pub const Database = struct {
|
|||
entities[i] = try Entity.read(reader);
|
||||
}
|
||||
|
||||
// read wires
|
||||
// Allocate a fixed amount of space since wires are likely to be shuffled around
|
||||
var wires = try alloc.alloc(Wire, 255);
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < wire_count) : (i += 1) {
|
||||
wires[i] = try Wire.read(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// read circuits
|
||||
var circuit_nodes = try alloc.alloc(CircuitNode, node_count);
|
||||
|
||||
|
@ -575,6 +698,8 @@ pub const Database = struct {
|
|||
.cursor = cursor,
|
||||
.level_info = level_headers,
|
||||
.entities = entities,
|
||||
.wires = wires,
|
||||
.wire_count = wire_count,
|
||||
.circuit_info = circuit_nodes,
|
||||
.level_data_begin = level_data_begin,
|
||||
};
|
||||
|
@ -732,20 +857,33 @@ pub const Database = struct {
|
|||
db.entities[coin].kind = .Collected;
|
||||
}
|
||||
|
||||
pub fn getWire(database: *Database, level: Level, num: usize) ?[2]Entity {
|
||||
pub fn getWire(database: *Database, level: Level, num: usize) ?[]Wire {
|
||||
const nw = Coord.fromWorld(level.world_x, level.world_y);
|
||||
const se = nw.add(.{ 20, 20 });
|
||||
var node_begin: ?Entity = null;
|
||||
var node_begin: ?usize = null;
|
||||
var wire_count: usize = 0;
|
||||
for (database.entities) |entity| {
|
||||
if (!entity.coord.within(nw, se)) continue;
|
||||
if (entity.kind == .WireNode or entity.kind == .WireAnchor) {
|
||||
node_begin = entity;
|
||||
} else if (entity.kind == .WireEndNode or entity.kind == .WireEndAnchor) {
|
||||
if (node_begin) |begin| {
|
||||
if (wire_count == num) return [2]Entity{ begin, entity };
|
||||
var i: usize = 0;
|
||||
while (i < database.wire_count) : (i += 1) {
|
||||
const wire = database.wires[i];
|
||||
switch (wire) {
|
||||
.Begin => |coord| {
|
||||
if (!coord.within(nw, se)) continue;
|
||||
node_begin = i;
|
||||
},
|
||||
.BeginPinned => |coord| {
|
||||
if (!coord.within(nw, se)) continue;
|
||||
node_begin = i;
|
||||
},
|
||||
.Point, .PointPinned => continue,
|
||||
.End => {
|
||||
if (node_begin) |node| {
|
||||
if (wire_count == num) {
|
||||
return database.wires[node..i + 1];
|
||||
}
|
||||
wire_count += 1;
|
||||
node_begin = null;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -58,6 +58,9 @@ fn make(step: *std.build.Step) !void {
|
|||
var entity_array = std.ArrayList(world.Entity).init(allocator);
|
||||
defer entity_array.deinit();
|
||||
|
||||
var wires = std.ArrayList(world.Wire).init(allocator);
|
||||
defer wires.deinit();
|
||||
|
||||
for (ldtk.levels) |level| {
|
||||
std.log.warn("Level: {}", .{levels.items.len});
|
||||
const parsed_level = try parseLevel(.{
|
||||
|
@ -65,6 +68,7 @@ fn make(step: *std.build.Step) !void {
|
|||
.ldtk = ldtk,
|
||||
.level = level,
|
||||
.entity_array = &entity_array,
|
||||
.wires = &wires,
|
||||
});
|
||||
|
||||
try levels.append(parsed_level);
|
||||
|
@ -80,6 +84,10 @@ fn make(step: *std.build.Step) !void {
|
|||
std.log.warn("{:0>2}: {}", .{ i, node });
|
||||
}
|
||||
|
||||
for (wires.items) |node, i| {
|
||||
std.log.warn("Wire {:0>2}: {any}", .{ i, node });
|
||||
}
|
||||
|
||||
// Calculate the offset of each level and store it in the headers.
|
||||
// Offset is relative to the beginning of level.data
|
||||
var level_headers = std.ArrayList(world.LevelHeader).init(allocator);
|
||||
|
@ -109,7 +117,14 @@ fn make(step: *std.build.Step) !void {
|
|||
defer data.deinit();
|
||||
const writer = data.writer();
|
||||
|
||||
try world.write(writer, level_headers.items, entity_array.items, circuit.items, levels.items);
|
||||
try world.write(
|
||||
writer,
|
||||
level_headers.items,
|
||||
entity_array.items,
|
||||
wires.items,
|
||||
circuit.items,
|
||||
levels.items,
|
||||
);
|
||||
|
||||
// Open output file and write data into it
|
||||
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
||||
|
@ -127,11 +142,13 @@ fn parseLevel(opt: struct {
|
|||
ldtk: LDtk.Root,
|
||||
level: LDtk.Level,
|
||||
entity_array: *std.ArrayList(world.Entity),
|
||||
wires: *std.ArrayList(world.Wire),
|
||||
}) !world.Level {
|
||||
const ldtk = opt.ldtk;
|
||||
const level = opt.level;
|
||||
const entity_array = opt.entity_array;
|
||||
const allocator = opt.allocator;
|
||||
const wires = opt.wires;
|
||||
|
||||
const layers = level.layerInstances orelse return error.NoLayers;
|
||||
|
||||
|
@ -147,11 +164,12 @@ fn parseLevel(opt: struct {
|
|||
std.debug.assert(layer.__type == .Entities);
|
||||
|
||||
for (layer.entityInstances) |entity| {
|
||||
var is_wire = false;
|
||||
var kind_opt: ?world.EntityKind = null;
|
||||
if (std.mem.eql(u8, entity.__identifier, "Player")) {
|
||||
kind_opt = .Player;
|
||||
} else if (std.mem.eql(u8, entity.__identifier, "Wire")) {
|
||||
kind_opt = .WireNode;
|
||||
is_wire = true;
|
||||
} else if (std.mem.eql(u8, entity.__identifier, "Coin")) {
|
||||
kind_opt = .Coin;
|
||||
} else if (std.mem.eql(u8, entity.__identifier, "Door")) {
|
||||
|
@ -160,21 +178,18 @@ fn parseLevel(opt: struct {
|
|||
kind_opt = .Trapdoor;
|
||||
}
|
||||
|
||||
const levelc = world.Coordinate.fromWorld(world_x, world_y);
|
||||
// Parsing code for wire entities. They're a little more complex
|
||||
// than the rest
|
||||
if (kind_opt) |kind| {
|
||||
const levelc = world.Coordinate.fromWorld(world_x, world_y);
|
||||
if (kind != .WireNode) {
|
||||
const entc = world.Coordinate.init(.{
|
||||
@intCast(i16, entity.__grid[0]),
|
||||
@intCast(i16, entity.__grid[1]),
|
||||
});
|
||||
const world_entity = world.Entity{
|
||||
.kind = kind,
|
||||
.coord = levelc.addC(entc)
|
||||
};
|
||||
const world_entity = world.Entity{ .kind = kind, .coord = levelc.addC(entc) };
|
||||
try entity_array.append(world_entity);
|
||||
} else {
|
||||
}
|
||||
if (is_wire) {
|
||||
var anchor1 = false;
|
||||
var anchor2 = false;
|
||||
const p1_c = world.Coordinate.init(.{
|
||||
|
@ -201,18 +216,19 @@ fn parseLevel(opt: struct {
|
|||
};
|
||||
}
|
||||
}
|
||||
const wire_begin = world.Entity{
|
||||
.kind = if (anchor1) .WireAnchor else .WireNode,
|
||||
.coord = p1_c.addC(levelc),
|
||||
};
|
||||
try entity_array.append(wire_begin);
|
||||
|
||||
const wire_end = world.Entity{
|
||||
.kind = if (anchor2) .WireEndAnchor else .WireEndNode,
|
||||
.coord = p2_c.addC(levelc),
|
||||
};
|
||||
try entity_array.append(wire_end);
|
||||
if (anchor1) {
|
||||
try wires.append(.{ .BeginPinned = p1_c.addC(levelc) });
|
||||
} else {
|
||||
try wires.append(.{ .Begin = p1_c.addC(levelc) });
|
||||
}
|
||||
|
||||
if (anchor2) {
|
||||
try wires.append(.{ .PointPinned = p2_c.subC(p1_c).toOffset() });
|
||||
} else {
|
||||
try wires.append(.{ .Point = p2_c.subC(p1_c).toOffset() });
|
||||
}
|
||||
try wires.append(.End);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue