Use grid of levels to improve performance
Makes Wired run at full speed on the RG351M.master
parent
77a3fb166e
commit
3c3c9b4ddc
|
@ -172,16 +172,14 @@ fn get_plugs(tile: u8) Plugs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cell(this: @This(), cell: Cell) ?u8 {
|
pub fn get_cell(this: @This(), cell: Cell) ?u8 {
|
||||||
if (this.cell_map.get_const(cell)) |c| return c.tile;
|
const i = this.indexOf(cell) orelse return null;
|
||||||
const c = cell;
|
|
||||||
if (c[0] < 0 or c[0] > this.map_size[0] or c[1] > this.map_size[1] or c[1] < 0) return null;
|
|
||||||
const i = @intCast(usize, @mod(c[0], this.map_size[0]) + (c[1] * this.map_size[1]));
|
|
||||||
return if (this.map[i] != 0) this.map[i] - 1 else null;
|
return if (this.map[i] != 0) this.map[i] - 1 else null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
|
pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
|
||||||
var cellData = CellData{ .tile = tile };
|
const i = this.indexOf(cell) orelse return;
|
||||||
this.cell_map.set(cell, cellData);
|
this.map[i] = tile + 1;
|
||||||
|
this.levels[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAXCELLS = 400;
|
const MAXCELLS = 400;
|
||||||
|
@ -190,38 +188,30 @@ const MAXSOURCES = 10;
|
||||||
const MAXDOORS = 40;
|
const MAXDOORS = 40;
|
||||||
const MAXLOGIC = 40;
|
const MAXLOGIC = 40;
|
||||||
|
|
||||||
const CellData = struct { level: u8 = 0, tile: u8 };
|
pub const CellData = struct { level: u8 = 0, tile: u8 };
|
||||||
const CellMap = util.Map(Cell, CellData, MAXCELLS);
|
|
||||||
|
|
||||||
const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool };
|
const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool };
|
||||||
const DoorState = struct { cell: Cell, enabled: bool };
|
const DoorState = struct { cell: Cell, enabled: bool };
|
||||||
|
|
||||||
map: []const u8,
|
/// Tile id of the tiles
|
||||||
|
map: []u8,
|
||||||
|
/// Logic levels of the tiles
|
||||||
|
levels: []u8,
|
||||||
map_size: Vec2,
|
map_size: Vec2,
|
||||||
cell_map: CellMap,
|
|
||||||
bridges: std.BoundedArray(BridgeState, MAXBRIDGES),
|
bridges: std.BoundedArray(BridgeState, MAXBRIDGES),
|
||||||
sources: std.BoundedArray(Cell, MAXSOURCES),
|
sources: std.BoundedArray(Cell, MAXSOURCES),
|
||||||
doors: std.BoundedArray(DoorState, MAXDOORS),
|
doors: std.BoundedArray(DoorState, MAXDOORS),
|
||||||
logic_map: std.BoundedArray(Cell, MAXLOGIC),
|
|
||||||
|
|
||||||
pub fn init(map: []const u8, map_size: Vec2) @This() {
|
pub fn init(map: []u8, levels: []u8, map_size: Vec2) @This() {
|
||||||
|
std.debug.assert(map.len == levels.len);
|
||||||
var this = @This(){
|
var this = @This(){
|
||||||
.map = map,
|
.map = map,
|
||||||
|
.levels = levels,
|
||||||
.map_size = map_size,
|
.map_size = map_size,
|
||||||
.cell_map = CellMap.init(),
|
|
||||||
.bridges = std.BoundedArray(BridgeState, MAXBRIDGES).init(0) catch unreachable,
|
.bridges = std.BoundedArray(BridgeState, MAXBRIDGES).init(0) catch unreachable,
|
||||||
.sources = std.BoundedArray(Cell, MAXSOURCES).init(0) catch unreachable,
|
.sources = std.BoundedArray(Cell, MAXSOURCES).init(0) catch unreachable,
|
||||||
.doors = std.BoundedArray(DoorState, MAXDOORS).init(0) catch unreachable,
|
.doors = std.BoundedArray(DoorState, MAXDOORS).init(0) catch unreachable,
|
||||||
.logic_map = std.BoundedArray(Cell, MAXLOGIC).init(0) catch unreachable,
|
|
||||||
};
|
};
|
||||||
for (map) |tile, index| {
|
|
||||||
if (is_logic(tile)) {
|
|
||||||
const i = @intCast(i32, index);
|
|
||||||
const cell = Cell{ @mod(i, this.map_size[0]), @divTrunc(i, this.map_size[0]) };
|
|
||||||
// w4.tracef("%d, %d: %d", cell[0], cell[1], this.logic_map.len);
|
|
||||||
this.logic_map.append(cell) catch unreachable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,12 +221,8 @@ pub fn indexOf(this: @This(), cell: Cell) ?usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(this: *@This(), cell: Cell) void {
|
pub fn enable(this: *@This(), cell: Cell) void {
|
||||||
if (this.cell_map.get(cell)) |c| {
|
const i = this.indexOf(cell) orelse return;
|
||||||
c.level += 1;
|
this.levels[i] += 1;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const t = this.get_cell(cell) orelse return;
|
|
||||||
this.cell_map.set(cell, .{ .tile = t, .level = 1 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void {
|
pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void {
|
||||||
|
@ -276,10 +262,8 @@ pub fn enabledDoors(this: @This()) std.BoundedArray(Cell, MAXDOORS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isEnabled(this: @This(), cell: Cell) bool {
|
pub fn isEnabled(this: @This(), cell: Cell) bool {
|
||||||
if (this.cell_map.get_const(cell)) |c| {
|
const i = this.indexOf(cell) orelse return false;
|
||||||
return c.level >= 1;
|
return this.levels[i] >= 1;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle(this: *@This(), c: Cell) void {
|
pub fn toggle(this: *@This(), c: Cell) void {
|
||||||
|
@ -293,9 +277,7 @@ pub fn toggle(this: *@This(), c: Cell) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(this: *@This()) void {
|
pub fn clear(this: *@This()) void {
|
||||||
for (this.cell_map.values.slice()) |*cell| {
|
std.mem.set(u8, this.levels, 0);
|
||||||
cell.level = 0;
|
|
||||||
}
|
|
||||||
for (this.doors.slice()) |*door| {
|
for (this.doors.slice()) |*door| {
|
||||||
door.enabled = false;
|
door.enabled = false;
|
||||||
}
|
}
|
||||||
|
@ -335,11 +317,8 @@ pub fn fill(this: *@This()) usize {
|
||||||
if (get_logic(tile)) |logic| {
|
if (get_logic(tile)) |logic| {
|
||||||
// TODO: implement other logic (though I'm pretty sure that requires a graph...)
|
// TODO: implement other logic (though I'm pretty sure that requires a graph...)
|
||||||
if (logic != .And) continue;
|
if (logic != .And) continue;
|
||||||
if (this.cell_map.get(cell)) |data| {
|
if (this.levels[index] < 2) continue;
|
||||||
// Skip current loop if and isn't high enough
|
q.insert(cell + util.Dir.up);
|
||||||
if (data.level < 2) continue;
|
|
||||||
q.insert(cell + util.Dir.up);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (get_outputs(tile)) |conductor, i| {
|
for (get_outputs(tile)) |conductor, i| {
|
||||||
if (!conductor) continue;
|
if (!conductor) continue;
|
||||||
|
|
|
@ -173,6 +173,8 @@ const Coin = struct { pos: Pos, sprite: Sprite, anim: Anim, area: AABB };
|
||||||
var coins = std.BoundedArray(Coin, 20).init(0) catch unreachable;
|
var coins = std.BoundedArray(Coin, 20).init(0) catch unreachable;
|
||||||
var score: u8 = 0;
|
var score: u8 = 0;
|
||||||
var solids_mutable = assets.solid;
|
var solids_mutable = assets.solid;
|
||||||
|
var conduit_mutable = assets.conduit;
|
||||||
|
var conduitLevels_mutable: [conduit_mutable.len]u8 = undefined;
|
||||||
|
|
||||||
const anim_store = struct {
|
const anim_store = struct {
|
||||||
const stand = Anim.frame(8);
|
const stand = Anim.frame(8);
|
||||||
|
@ -203,7 +205,8 @@ fn showErr(msg: []const u8) noreturn {
|
||||||
export fn start() void {
|
export fn start() void {
|
||||||
particles = ParticleSystem.init();
|
particles = ParticleSystem.init();
|
||||||
|
|
||||||
circuit = Circuit.init(&assets.conduit, assets.conduit_size);
|
std.mem.set(u8, &conduitLevels_mutable, 0);
|
||||||
|
circuit = Circuit.init(&conduit_mutable, &conduitLevels_mutable, assets.conduit_size);
|
||||||
map = Map.init(&solids_mutable, assets.solid_size);
|
map = Map.init(&solids_mutable, assets.solid_size);
|
||||||
|
|
||||||
camera = @divTrunc(assets.spawn, @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));
|
camera = @divTrunc(assets.spawn, @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));
|
||||||
|
|
36
src/util.zig
36
src/util.zig
|
@ -81,39 +81,3 @@ pub fn Queue(comptime T: type, len: usize) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Map(comptime K: type, comptime V: type, len: usize) type {
|
|
||||||
return struct {
|
|
||||||
keys: std.BoundedArray(K, len),
|
|
||||||
values: std.BoundedArray(V, len),
|
|
||||||
pub fn init() @This() {
|
|
||||||
return @This(){
|
|
||||||
.keys = std.BoundedArray(K, len).init(0) catch unreachable,
|
|
||||||
.values = std.BoundedArray(V, len).init(0) catch unreachable,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub fn get(this: *@This(), key: K) ?*V {
|
|
||||||
for (this.keys.slice()) |k, i| {
|
|
||||||
if (@reduce(.And, key == k)) {
|
|
||||||
return &this.values.slice()[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
pub fn get_const(this: @This(), key: Cell) ?V {
|
|
||||||
for (this.keys.constSlice()) |k, i| {
|
|
||||||
if (@reduce(.And, key == k)) {
|
|
||||||
return this.values.constSlice()[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
pub fn set(this: *@This(), key: K, new: V) void {
|
|
||||||
if (this.get(key)) |v| {
|
|
||||||
v.* = new;
|
|
||||||
} else {
|
|
||||||
this.keys.append(key) catch unreachable;
|
|
||||||
this.values.append(new) catch unreachable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue