Implment basic saves
parent
746d2c3a2f
commit
63ba55b565
BIN
assets/tiles.png
BIN
assets/tiles.png
Binary file not shown.
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 723 B |
224
src/main.zig
224
src/main.zig
|
@ -238,15 +238,6 @@ export fn start() void {
|
||||||
.kinematic = .{ .col = .{ .pos = .{ -3, -6 }, .size = .{ 5, 5 } } },
|
.kinematic = .{ .col = .{ .pos = .{ -3, -6 }, .size = .{ 5, 5 } } },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (assets.coins) |coin| {
|
|
||||||
coins.append(.{
|
|
||||||
.pos = Pos.init(util.vec2ToVec2f(coin * tile_size)),
|
|
||||||
.sprite = .{ .offset = .{ 0, 0 }, .size = .{ 8, 8 }, .index = 4, .flags = .{ .bpp = .b2 } },
|
|
||||||
.anim = Anim{ .anim = &anim_store.coin },
|
|
||||||
.area = .{ .pos = .{ 0, 0 }, .size = .{ 8, 8 } },
|
|
||||||
}) catch unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (assets.wire) |wire| {
|
for (assets.wire) |wire| {
|
||||||
const begin = vec2tovec2f(wire.p1);
|
const begin = vec2tovec2f(wire.p1);
|
||||||
const end = vec2tovec2f(wire.p2);
|
const end = vec2tovec2f(wire.p2);
|
||||||
|
@ -273,6 +264,17 @@ export fn start() void {
|
||||||
circuit.addDoor(door);
|
circuit.addDoor(door);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!load()) {
|
||||||
|
for (assets.coins) |coin| {
|
||||||
|
coins.append(.{
|
||||||
|
.pos = Pos.init(util.vec2ToVec2f(coin * tile_size)),
|
||||||
|
.sprite = .{ .offset = .{ 0, 0 }, .size = .{ 8, 8 }, .index = 4, .flags = .{ .bpp = .b2 } },
|
||||||
|
.anim = Anim{ .anim = &anim_store.coin },
|
||||||
|
.area = .{ .pos = .{ 0, 0 }, .size = .{ 8, 8 } },
|
||||||
|
}) catch unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateCircuit();
|
updateCircuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +306,7 @@ export fn update() void {
|
||||||
drawProcess(1, &player.pos, &player.sprite);
|
drawProcess(1, &player.pos, &player.sprite);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
var shouldSave = false;
|
||||||
var remove = std.BoundedArray(usize, 10).init(0) catch unreachable;
|
var remove = std.BoundedArray(usize, 10).init(0) catch unreachable;
|
||||||
for (coins.slice()) |*coin, i| {
|
for (coins.slice()) |*coin, i| {
|
||||||
staticAnimProcess(1, &coin.sprite, &coin.anim);
|
staticAnimProcess(1, &coin.sprite, &coin.anim);
|
||||||
|
@ -312,11 +315,14 @@ export fn update() void {
|
||||||
score += 1;
|
score += 1;
|
||||||
remove.append(i) catch unreachable;
|
remove.append(i) catch unreachable;
|
||||||
music.playCollect(score);
|
music.playCollect(score);
|
||||||
|
shouldSave = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (remove.popOrNull()) |i| {
|
while (remove.popOrNull()) |i| {
|
||||||
_ = coins.swapRemove(i);
|
_ = coins.swapRemove(i);
|
||||||
}
|
}
|
||||||
|
// We save here to prevent duplicate coins
|
||||||
|
if (shouldSave) save();
|
||||||
}
|
}
|
||||||
|
|
||||||
camera = @divTrunc(util.world2cell(player.pos.pos), @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));
|
camera = @divTrunc(util.world2cell(player.pos.pos), @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));
|
||||||
|
@ -404,6 +410,206 @@ export fn update() void {
|
||||||
time += 1;
|
time += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_diff(writer: anytype, stride: usize, initial: []const u8, mapBuf: []const u8) !u8 {
|
||||||
|
var written: u8 = 0;
|
||||||
|
for (initial) |init_tile, i| {
|
||||||
|
if (mapBuf[i] != init_tile) {
|
||||||
|
const x = @intCast(u8, i % @intCast(usize, stride));
|
||||||
|
const y = @intCast(u8, @divTrunc(i, @intCast(usize, stride)));
|
||||||
|
const temp = [3]u8{ x, y, mapBuf[i] };
|
||||||
|
try writer.writeAll(&temp);
|
||||||
|
written += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_diff(mapBuf: []u8, stride: usize, diff: []const u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < diff.len) : (i += 3) {
|
||||||
|
const x = diff[i];
|
||||||
|
const y = diff[i + 1];
|
||||||
|
const tile = diff[i + 2];
|
||||||
|
const a = x + y * stride;
|
||||||
|
mapBuf[a] = tile;
|
||||||
|
// this.set_cell(Cell{ x, y }, tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load() bool {
|
||||||
|
var load_buf: [1024]u8 = undefined;
|
||||||
|
const read = w4.diskr(&load_buf, 1024);
|
||||||
|
w4.tracef("%d bytes read", read);
|
||||||
|
|
||||||
|
for (load_buf[0 .. read - 1]) |byte| w4.tracef("%d", byte);
|
||||||
|
// if (true) return false;
|
||||||
|
if (read <= 0) return false;
|
||||||
|
|
||||||
|
var stream = std.io.fixedBufferStream(load_buf[0..read]);
|
||||||
|
var reader = stream.reader();
|
||||||
|
|
||||||
|
var header: [5]u8 = undefined;
|
||||||
|
_ = reader.read(&header) catch w4.tracef("couldn't load header");
|
||||||
|
w4.tracef("%s", &header);
|
||||||
|
if (!std.mem.eql(u8, "wired", &header)) return false; // w4.tracef("did not load, incorrect header bytes");
|
||||||
|
|
||||||
|
score = reader.readByte() catch return false;
|
||||||
|
|
||||||
|
const obj_len = reader.readByte() catch return false;
|
||||||
|
const map_len = reader.readByte() catch return false;
|
||||||
|
const conduit_len = reader.readByte() catch return false;
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < obj_len) : (i += 1) {
|
||||||
|
const b = reader.readByte() catch return false;
|
||||||
|
const obj = @intToEnum(SaveObj, @truncate(u4, b));
|
||||||
|
const id = @truncate(u4, b >> 4);
|
||||||
|
const x = reader.readByte() catch return false;
|
||||||
|
const y = reader.readByte() catch return false;
|
||||||
|
const cell = util.Cell{ x, y };
|
||||||
|
var pos = Pos.init(util.vec2ToVec2f(cell * Map.tile_size));
|
||||||
|
if (obj == .WireBeginPinned or obj == .WireBeginLoose or obj == .WireEndPinned or obj == .WireEndLoose)
|
||||||
|
pos.pos += Vec2f{ 4, 4 };
|
||||||
|
switch (obj) {
|
||||||
|
.Player => {
|
||||||
|
w4.tracef("player at %d, %d", x, y);
|
||||||
|
player.pos = pos;
|
||||||
|
// player.pos.pos += Vec2f{ 4, 6 };
|
||||||
|
},
|
||||||
|
.Coin => {
|
||||||
|
coins.append(.{
|
||||||
|
.pos = pos,
|
||||||
|
.sprite = .{ .offset = .{ 0, 0 }, .size = .{ 8, 8 }, .index = 4, .flags = .{ .bpp = .b2 } },
|
||||||
|
.anim = Anim{ .anim = &anim_store.coin },
|
||||||
|
.area = .{ .pos = .{ 0, 0 }, .size = .{ 8, 8 } },
|
||||||
|
}) catch unreachable;
|
||||||
|
},
|
||||||
|
.WireBeginPinned => {
|
||||||
|
var begin = wires.slice()[id].begin();
|
||||||
|
begin.* = pos;
|
||||||
|
begin.pinned = true;
|
||||||
|
},
|
||||||
|
.WireBeginLoose => {
|
||||||
|
var begin = wires.slice()[id].begin();
|
||||||
|
begin.* = pos;
|
||||||
|
begin.pinned = false;
|
||||||
|
},
|
||||||
|
.WireEndPinned => {
|
||||||
|
var end = wires.slice()[id].end();
|
||||||
|
end.* = pos;
|
||||||
|
end.pinned = true;
|
||||||
|
},
|
||||||
|
.WireEndLoose => {
|
||||||
|
var end = wires.slice()[id].end();
|
||||||
|
end.* = pos;
|
||||||
|
end.pinned = false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load map
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
// const len = reader.readByte() catch return;
|
||||||
|
const bytes_map = reader.read(buf[0 .. map_len * 3]) catch return false;
|
||||||
|
w4.tracef("loading %d map diffs... %d bytes", map_len, bytes_map);
|
||||||
|
load_diff(&solids_mutable, assets.solid_size[0], buf[0..bytes_map]);
|
||||||
|
|
||||||
|
// Load conduit
|
||||||
|
// const conduit_len = reader.readByte() catch return;
|
||||||
|
const bytes_conduit = reader.read(buf[0 .. conduit_len * 3]) catch return false;
|
||||||
|
w4.tracef("loading %d conduit diffs... %d bytes", conduit_len, bytes_conduit);
|
||||||
|
for (buf[0..bytes_conduit]) |byte| w4.tracef("%d", byte);
|
||||||
|
load_diff(&conduit_mutable, assets.conduit_size[0], buf[0..bytes_conduit]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SaveObj = enum(u4) {
|
||||||
|
Player,
|
||||||
|
Coin,
|
||||||
|
WireBeginPinned,
|
||||||
|
WireBeginLoose,
|
||||||
|
WireEndPinned,
|
||||||
|
WireEndLoose,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn cell2u8(cell: util.Cell) [2]u8 {
|
||||||
|
return [_]u8{ @intCast(u8, cell[0]), @intCast(u8, cell[1]) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save() void {
|
||||||
|
var save_buf: [1024]u8 = undefined;
|
||||||
|
var save_stream = std.io.fixedBufferStream(&save_buf);
|
||||||
|
var save_writer = save_stream.writer();
|
||||||
|
save_writer.writeAll("wired") catch return w4.tracef("Couldn't write header");
|
||||||
|
save_writer.writeByte(score) catch return w4.tracef("Couldn't save score");
|
||||||
|
w4.tracef("score %d written", score);
|
||||||
|
|
||||||
|
// Write temporary length values
|
||||||
|
const lengths_start = save_stream.getPos() catch return w4.tracef("Couldn't get pos");
|
||||||
|
save_writer.writeByte(0) catch return w4.tracef("Couldn't write obj length");
|
||||||
|
save_writer.writeByte(0) catch return w4.tracef("Couldn't write map length");
|
||||||
|
save_writer.writeByte(0) catch return w4.tracef("Couldn't write conduit length");
|
||||||
|
|
||||||
|
// Write player
|
||||||
|
const playerCell = util.world2cell(player.pos.pos);
|
||||||
|
save_writer.writeAll(&[_]u8{ @enumToInt(SaveObj.Player), @intCast(u8, playerCell[0]), @intCast(u8, playerCell[1]) }) catch return w4.tracef("Couldn't save player");
|
||||||
|
var obj_len: u8 = 1;
|
||||||
|
|
||||||
|
for (coins.slice()) |coin, i| {
|
||||||
|
obj_len += 1;
|
||||||
|
const id = @intCast(u8, @truncate(u4, i)) << 4;
|
||||||
|
const cell = util.world2cell(coin.pos.pos);
|
||||||
|
save_writer.writeByte(@enumToInt(SaveObj.Coin) | id) catch return w4.tracef("Couldn't save coin");
|
||||||
|
save_writer.writeAll(&cell2u8(cell)) catch return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write wires
|
||||||
|
for (wires.slice()) |*wire, i| {
|
||||||
|
const id = @intCast(u8, @truncate(u4, i)) << 4;
|
||||||
|
const begin = wire.begin();
|
||||||
|
const end = wire.end();
|
||||||
|
obj_len += 1;
|
||||||
|
if (begin.pinned) {
|
||||||
|
const cell = util.world2cell(begin.pos);
|
||||||
|
save_writer.writeByte(@enumToInt(SaveObj.WireBeginPinned) | id) catch return w4.tracef("Couldn't save wire");
|
||||||
|
save_writer.writeAll(&cell2u8(cell)) catch return;
|
||||||
|
} else {
|
||||||
|
const cell = util.world2cell(begin.pos);
|
||||||
|
save_writer.writeByte(@enumToInt(SaveObj.WireBeginLoose) | id) catch return w4.tracef("Couldn't save wire");
|
||||||
|
save_writer.writeAll(&cell2u8(cell)) catch return;
|
||||||
|
}
|
||||||
|
obj_len += 1;
|
||||||
|
if (end.pinned) {
|
||||||
|
const cell = util.world2cell(end.pos);
|
||||||
|
save_writer.writeByte(@enumToInt(SaveObj.WireEndPinned) | id) catch return w4.tracef("Couldn't save wire");
|
||||||
|
save_writer.writeAll(&cell2u8(cell)) catch return;
|
||||||
|
} else {
|
||||||
|
const cell = util.world2cell(end.pos);
|
||||||
|
save_writer.writeByte(@enumToInt(SaveObj.WireEndLoose) | id) catch return w4.tracef("Couldn't save wire");
|
||||||
|
save_writer.writeAll(&cell2u8(cell)) catch return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write map
|
||||||
|
const map_len = write_diff(save_writer, assets.solid_size[0], &assets.solid, &solids_mutable) catch return w4.tracef("Couldn't save map diff");
|
||||||
|
|
||||||
|
// Write conduit
|
||||||
|
const conduit_len = write_diff(save_writer, assets.conduit_size[0], &assets.conduit, &conduit_mutable) catch return w4.tracef("Couldn't save map diff");
|
||||||
|
|
||||||
|
const endPos = save_stream.getPos() catch return;
|
||||||
|
save_stream.seekTo(lengths_start) catch w4.tracef("Couldn't seek");
|
||||||
|
save_writer.writeByte(obj_len) catch return w4.tracef("Couldn't write obj length");
|
||||||
|
save_writer.writeByte(map_len) catch return w4.tracef("Couldn't write map length");
|
||||||
|
save_writer.writeByte(conduit_len) catch return w4.tracef("Couldn't write conduit length");
|
||||||
|
|
||||||
|
save_stream.seekTo(endPos) catch return;
|
||||||
|
const save_slice = save_stream.getWritten();
|
||||||
|
const written = w4.diskw(save_slice.ptr, save_slice.len);
|
||||||
|
w4.tracef("%d bytes written, %d map diffs", written, map_len);
|
||||||
|
for (save_buf[0..written]) |byte| w4.tracef("%d", byte);
|
||||||
|
}
|
||||||
|
|
||||||
const Interaction = struct {
|
const Interaction = struct {
|
||||||
pos: Vec2,
|
pos: Vec2,
|
||||||
details: union(enum) {
|
details: union(enum) {
|
||||||
|
|
34
src/map.zig
34
src/map.zig
|
@ -30,6 +30,35 @@ pub fn init(map: []u8, map_size: Vec2) @This() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset(this: *@This(), initialState: []const u8) void {
|
||||||
|
std.debug.assert(initialState.len == this.tiles.len);
|
||||||
|
std.mem.copy(u8, this.tiles, initialState);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_diff(this: *@This(), initialState: []const u8, buf: anytype) !u8 {
|
||||||
|
var written: u8 = 0;
|
||||||
|
for (initialState) |init_tile, i| {
|
||||||
|
if (this.tiles[i] != init_tile) {
|
||||||
|
const x = @intCast(u8, i % @intCast(usize, this.map_size[0]));
|
||||||
|
const y = @intCast(u8, @divTrunc(i, @intCast(usize, this.map_size[0])));
|
||||||
|
const temp = [3]u8{ x, y, this.tiles[i] };
|
||||||
|
try buf.writeAll(&temp);
|
||||||
|
written += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_diff(this: *@This(), diff: []const u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < diff.len) : (i += 3) {
|
||||||
|
const x = diff[i];
|
||||||
|
const y = diff[i + 1];
|
||||||
|
const tile = diff[i + 2];
|
||||||
|
this.set_cell(Cell{ x, y }, tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
|
pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
|
||||||
const x = cell[0];
|
const x = cell[0];
|
||||||
const y = cell[1];
|
const y = cell[1];
|
||||||
|
@ -38,11 +67,6 @@ pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
|
||||||
this.tiles[@intCast(usize, i)] = tile;
|
this.tiles[@intCast(usize, i)] = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(this: *@This(), initialState: []const u8) void {
|
|
||||||
std.debug.assert(initialState.len == this.tiles.len);
|
|
||||||
std.mem.copy(u8, this.tiles, initialState);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_cell(this: @This(), cell: Cell) ?u8 {
|
pub fn get_cell(this: @This(), cell: Cell) ?u8 {
|
||||||
const x = cell[0];
|
const x = cell[0];
|
||||||
const y = cell[1];
|
const y = cell[1];
|
||||||
|
|
Loading…
Reference in New Issue