Updated to use world coordinates
parent
73cb53e5e3
commit
a458426bed
161
src/circuit.zig
161
src/circuit.zig
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
const assets = @import("assets");
|
||||||
|
|
||||||
const Vec2 = util.Vec2;
|
const Vec2 = util.Vec2;
|
||||||
const Cell = util.Cell;
|
const Cell = util.Cell;
|
||||||
|
@ -20,7 +21,7 @@ pub fn is_conduit(tile: u8) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_switch(tile: u8) bool {
|
pub fn is_switch(tile: u8) bool {
|
||||||
return tile == 27 and tile == 28;
|
return tile == 27 or tile == 28;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_switch(tile: u8) u8 {
|
pub fn toggle_switch(tile: u8) u8 {
|
||||||
|
@ -93,43 +94,76 @@ fn get_plugs(tile: u8) Plugs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cell(this: @This(), cell: Cell) ?u8 {
|
pub fn get_cell(this: @This(), cell: Cell) ?u8 {
|
||||||
const c = cell - this.offset;
|
if (this.cell_map.getConstCell(cell)) |c| return c.tile;
|
||||||
if (c[0] < 0 or c[0] > 19 or c[1] > 19 or c[1] < 0) return null;
|
const c = cell;
|
||||||
const i = @intCast(usize, @mod(c[0], 20) + (c[1] * 20));
|
if (c[0] < 0 or c[0] > this.map_size[0] or c[1] > this.map_size[1] or c[1] < 0) return null;
|
||||||
return if (this.cells[i].tile != 0) this.cells[i].tile - 1 else 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cell(this: *@This(), c: Cell, tile: u8) void {
|
pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
|
||||||
if (c[0] < 0 or c[0] > 19 or c[1] > 19 or c[1] < 0) return;
|
var cellstate = CellState{ .cell = cell, .tile = tile };
|
||||||
const i = @intCast(usize, @mod(c[0], 20) + (c[1] * 20));
|
this.cell_map.setCell(cellstate);
|
||||||
this.cells[i].tile = tile + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index2cell(i: usize) Cell {
|
|
||||||
return Vec2{ i % 20, @divTrunc(i, 20) };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cell2index(c: Cell) ?usize {
|
|
||||||
if (c[0] < 0 or c[0] >= 20 or c[1] >= 20 or c[1] < 0) return null;
|
|
||||||
return @intCast(usize, @mod(c[0], 20) + (c[1] * 20));
|
|
||||||
}
|
|
||||||
|
|
||||||
const CellState = struct { enabled: bool = false, tile: u8 };
|
|
||||||
const MAXCELLS = 400;
|
const MAXCELLS = 400;
|
||||||
const MAXBRIDGES = 10;
|
const MAXBRIDGES = 10;
|
||||||
const MAXSOURCES = 10;
|
const MAXSOURCES = 10;
|
||||||
const CellMap = [MAXCELLS]CellState;
|
|
||||||
|
const CellState = struct { cell: Cell, enabled: bool = false, tile: u8 };
|
||||||
|
const CellMap = struct {
|
||||||
|
data: std.BoundedArray(CellState, MAXCELLS),
|
||||||
|
pub fn init() @This() {
|
||||||
|
return @This(){ .data = std.BoundedArray(CellState, MAXCELLS).init(0) catch unreachable };
|
||||||
|
}
|
||||||
|
pub fn getCell(this: *@This(), cell: Cell) ?*CellState {
|
||||||
|
for (this.data.slice()) |*cellstate| {
|
||||||
|
if (@reduce(.And, cellstate.cell == cell)) {
|
||||||
|
return cellstate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
pub fn getConstCell(this: @This(), cell: Cell) ?CellState {
|
||||||
|
for (this.data.constSlice()) |cellstate| {
|
||||||
|
if (@reduce(.And, cellstate.cell == cell)) {
|
||||||
|
return cellstate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
pub fn setCell(this: *@This(), newcell: CellState) void {
|
||||||
|
for (this.data.slice()) |*cellstate| {
|
||||||
|
if (@reduce(.And, cellstate.cell == newcell.cell)) {
|
||||||
|
cellstate.* = newcell;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.data.append(newcell) catch unreachable;
|
||||||
|
}
|
||||||
|
pub fn is_enabled(this: @This(), cell: Cell) bool {
|
||||||
|
if (this.getConstCell(cell)) |cellstate| {
|
||||||
|
return cellstate.enabled;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool };
|
const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool };
|
||||||
|
|
||||||
offset: Cell,
|
offset: Cell,
|
||||||
cells: CellMap,
|
map: []const u8,
|
||||||
|
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),
|
||||||
|
|
||||||
pub fn init() @This() {
|
pub fn init() @This() {
|
||||||
var this = @This(){
|
var this = @This(){
|
||||||
.offset = Cell{ 0, 0 },
|
.offset = Cell{ 0, 0 },
|
||||||
.cells = undefined,
|
.map = &assets.conduit,
|
||||||
|
.map_size = assets.conduit_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,
|
||||||
};
|
};
|
||||||
|
@ -138,25 +172,31 @@ pub fn init() @This() {
|
||||||
|
|
||||||
pub fn load(this: *@This(), offset: Cell, map: []const u8, map_size: Vec2) void {
|
pub fn load(this: *@This(), offset: Cell, map: []const u8, map_size: Vec2) void {
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
var y: usize = 0;
|
this.map = map;
|
||||||
while (y < 20) : (y += 1) {
|
this.map_size = map_size;
|
||||||
var x: usize = 0;
|
// var y: usize = 0;
|
||||||
while (x < 20) : (x += 1) {
|
// while (y < 20) : (y += 1) {
|
||||||
const i = x + y * 20;
|
// var x: usize = 0;
|
||||||
const a = (@intCast(usize, offset[0]) + x) + (@intCast(usize, offset[1]) + y) * @intCast(usize, map_size[0]);
|
// while (x < 20) : (x += 1) {
|
||||||
this.cells[i].tile = map[a];
|
// const i = x + y * 20;
|
||||||
}
|
// const a = (@intCast(usize, offset[0]) + x) + (@intCast(usize, offset[1]) + y) * @intCast(usize, map_size[0]);
|
||||||
}
|
// this.cells[i].tile = map[a];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indexOf(this: @This(), cell: Cell) ?usize {
|
pub fn indexOf(this: @This(), cell: Cell) ?usize {
|
||||||
return cell2index(cell - this.offset);
|
if (cell[0] < 0 or cell[0] >= this.map_size[0] or cell[1] >= this.map_size[1] or cell[1] < 0) return null;
|
||||||
|
return @intCast(usize, @mod(cell[0], this.map_size[0]) + (cell[1] * this.map_size[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(this: *@This(), cell: Cell) void {
|
pub fn enable(this: *@This(), cell: Cell) void {
|
||||||
if (this.indexOf(cell)) |c| {
|
if (this.cell_map.getCell(cell)) |c| {
|
||||||
this.cells[c].enabled = true;
|
c.enabled = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
const t = this.get_cell(cell) orelse unreachable;
|
||||||
|
this.cell_map.setCell(.{ .cell = cell, .tile = t, .enabled = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void {
|
pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void {
|
||||||
|
@ -182,23 +222,22 @@ pub fn enabledBridges(this: @This()) std.BoundedArray(usize, MAXBRIDGES) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isEnabled(this: @This(), cell: Cell) bool {
|
pub fn isEnabled(this: @This(), cell: Cell) bool {
|
||||||
if (this.indexOf(cell)) |c| {
|
return this.cell_map.is_enabled(cell);
|
||||||
return this.cells[c].enabled;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle(this: *@This(), c: Cell) void {
|
pub fn toggle(this: *@This(), c: Cell) void {
|
||||||
const cell = c - this.offset;
|
const cell = c;
|
||||||
if (this.get_cell(cell)) |tile| {
|
if (this.get_cell(cell)) |tile| {
|
||||||
if (is_switch(tile)) {
|
if (is_switch(tile)) {
|
||||||
this.set_cell(cell, toggle_switch(tile));
|
const toggled = toggle_switch(tile);
|
||||||
|
w4.tracef("%d, %d: %d to %d", cell[0], cell[1], tile, toggled);
|
||||||
|
this.set_cell(cell, toggled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(this: *@This()) void {
|
pub fn clear(this: *@This()) void {
|
||||||
for (this.cells) |*cell| {
|
for (this.cell_map.data.slice()) |*cell| {
|
||||||
cell.enabled = false;
|
cell.enabled = false;
|
||||||
}
|
}
|
||||||
this.bridges.resize(0) catch unreachable;
|
this.bridges.resize(0) catch unreachable;
|
||||||
|
@ -214,16 +253,17 @@ const w4 = @import("wasm4.zig");
|
||||||
pub fn fill(this: *@This()) usize {
|
pub fn fill(this: *@This()) usize {
|
||||||
const Queue = util.Queue(Cell, MAXCELLS);
|
const Queue = util.Queue(Cell, MAXCELLS);
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
var visited: [MAXCELLS]bool = [_]bool{false} ** MAXCELLS;
|
var visited = std.BoundedArray(usize, MAXCELLS).init(0) catch unreachable;
|
||||||
var q = Queue.init();
|
var q = Queue.init();
|
||||||
for (this.sources.slice()) |source| {
|
for (this.sources.slice()) |source| {
|
||||||
q.insert(source);
|
q.insert(source);
|
||||||
}
|
}
|
||||||
while (q.remove()) |cell| {
|
while (q.remove()) |cell| {
|
||||||
const index = this.indexOf(cell) orelse continue;
|
const index = this.indexOf(cell) orelse continue;
|
||||||
|
const hasVisited = std.mem.containsAtLeast(usize, visited.slice(), 1, &.{index});
|
||||||
|
if (hasVisited) continue;
|
||||||
const tile = this.get_cell(cell) orelse continue;
|
const tile = this.get_cell(cell) orelse continue;
|
||||||
if (visited[index]) continue;
|
visited.append(index) catch unreachable;
|
||||||
visited[index] = true;
|
|
||||||
this.enable(cell);
|
this.enable(cell);
|
||||||
count += 1;
|
count += 1;
|
||||||
for (get_inputs(tile)) |conductor, i| {
|
for (get_inputs(tile)) |conductor, i| {
|
||||||
|
@ -247,3 +287,36 @@ pub fn fill(this: *@This()) usize {
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const width = 20;
|
||||||
|
const height = 20;
|
||||||
|
const tile_size = Vec2{ 8, 8 };
|
||||||
|
const tilemap_width = 16;
|
||||||
|
const tilemap_height = 16;
|
||||||
|
const tilemap_stride = 128;
|
||||||
|
|
||||||
|
pub fn draw(this: @This()) void {
|
||||||
|
var y: usize = 0;
|
||||||
|
while (y < height) : (y += 1) {
|
||||||
|
var x: usize = 0;
|
||||||
|
while (x < width) : (x += 1) {
|
||||||
|
const cell = Vec2{ @intCast(i32, x), @intCast(i32, y) };
|
||||||
|
const pos = cell * tile_size;
|
||||||
|
const tile = this.get_cell(cell + this.offset) orelse continue;
|
||||||
|
if (tile == 0) continue;
|
||||||
|
if (this.isEnabled(cell + this.offset)) w4.DRAW_COLORS.* = 0x0210 else w4.DRAW_COLORS.* = 0x0310;
|
||||||
|
const t = Vec2{
|
||||||
|
@intCast(i32, (tile % tilemap_width) * tile_size[0]),
|
||||||
|
@intCast(i32, (tile / tilemap_width) * tile_size[0]),
|
||||||
|
};
|
||||||
|
w4.blitSub(
|
||||||
|
&assets.tiles,
|
||||||
|
pos,
|
||||||
|
tile_size,
|
||||||
|
t,
|
||||||
|
tilemap_stride,
|
||||||
|
.{ .bpp = .b2 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
20
src/main.zig
20
src/main.zig
|
@ -253,17 +253,9 @@ export fn update() void {
|
||||||
w4.DRAW_COLORS.* = 0x0004;
|
w4.DRAW_COLORS.* = 0x0004;
|
||||||
w4.rect(.{ 0, 0 }, .{ 160, 160 });
|
w4.rect(.{ 0, 0 }, .{ 160, 160 });
|
||||||
drawProcess(1, &player.pos, &player.sprite);
|
drawProcess(1, &player.pos, &player.sprite);
|
||||||
map.draw();
|
|
||||||
|
|
||||||
for (circuit.cells) |cell, i| {
|
map.draw();
|
||||||
const tilePlus = cell.tile;
|
circuit.draw();
|
||||||
if (tilePlus == 0) continue;
|
|
||||||
if (circuit.cells[i].enabled) w4.DRAW_COLORS.* = 0x0210 else w4.DRAW_COLORS.* = 0x0310;
|
|
||||||
const tile = tilePlus - 1;
|
|
||||||
const t = w4.Vec2{ @intCast(i32, (tile % 16) * 8), @intCast(i32, (tile / 16) * 8) };
|
|
||||||
const pos = w4.Vec2{ @intCast(i32, (i % 20) * 8), @intCast(i32, (i / 20) * 8) };
|
|
||||||
w4.blitSub(&assets.tiles, pos, .{ 8, 8 }, t, 128, .{ .bpp = .b2 });
|
|
||||||
}
|
|
||||||
|
|
||||||
for (wires.slice()) |*wire| {
|
for (wires.slice()) |*wire| {
|
||||||
wireDrawProcess(1, wire);
|
wireDrawProcess(1, wire);
|
||||||
|
@ -287,7 +279,7 @@ export fn update() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indicator) |details| {
|
if (indicator) |details| {
|
||||||
const pos = details.pos;
|
const pos = details.pos - (map.offset * Map.tile_size);
|
||||||
const stage = @divTrunc((time % 60), 30);
|
const stage = @divTrunc((time % 60), 30);
|
||||||
var size = Vec2{ 0, 0 };
|
var size = Vec2{ 0, 0 };
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
|
@ -333,8 +325,9 @@ fn manipulationProcess(pos: *Pos, control: *Control) void {
|
||||||
|
|
||||||
if (control.grabbing == null) {
|
if (control.grabbing == null) {
|
||||||
if (circuit.get_cell(cell)) |tile| {
|
if (circuit.get_cell(cell)) |tile| {
|
||||||
|
// w4.tracef("%d, %d: %d", cell[0], cell[1], tile);
|
||||||
if (Circuit.is_switch(tile)) {
|
if (Circuit.is_switch(tile)) {
|
||||||
indicator = .{ .t = .lever, .pos = cell * @splat(2, @as(i32, 8)) + Vec2{ 4, 4 } };
|
indicator = .{ .t = .lever, .pos = cell * Map.tile_size + Vec2{ 4, 4 } };
|
||||||
if (input.btnp(.one, .two)) {
|
if (input.btnp(.one, .two)) {
|
||||||
circuit.toggle(cell);
|
circuit.toggle(cell);
|
||||||
updateCircuit();
|
updateCircuit();
|
||||||
|
@ -492,7 +485,8 @@ fn wireDrawProcess(_: f32, wire: *Wire) void {
|
||||||
w4.DRAW_COLORS.* = if (wire.enabled) 0x0002 else 0x0003;
|
w4.DRAW_COLORS.* = if (wire.enabled) 0x0002 else 0x0003;
|
||||||
for (nodes) |node, i| {
|
for (nodes) |node, i| {
|
||||||
if (i == 0) continue;
|
if (i == 0) continue;
|
||||||
w4.line(vec2ftovec2(nodes[i - 1].pos), vec2ftovec2(node.pos));
|
const offset = (map.offset * Map.tile_size);
|
||||||
|
w4.line(vec2ftovec2(nodes[i - 1].pos) - offset, vec2ftovec2(node.pos) - offset);
|
||||||
}
|
}
|
||||||
wire.enabled = false;
|
wire.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue