Add map struct
parent
b5aa3db4e8
commit
a64b7198a0
|
@ -1,4 +1,8 @@
|
|||
const std = @import("std");
|
||||
const util = @import("util.zig");
|
||||
|
||||
const Vec2 = util.Vec2;
|
||||
const Cell = util.Cell;
|
||||
|
||||
fn is_circuit(tile: u8) bool {
|
||||
return is_plug(tile) or is_conduit(tile) or is_switch(tile);
|
||||
|
@ -95,8 +99,6 @@ fn get_signals(tile: u8) Signals {
|
|||
};
|
||||
}
|
||||
|
||||
const Vec2 = std.meta.Vector(2, i32);
|
||||
const Cell = Vec2;
|
||||
fn dir(s: Side) Cell {
|
||||
return switch (s) {
|
||||
.up => Vec2{ 0, -1 },
|
||||
|
@ -129,7 +131,7 @@ fn cell2index(c: Cell) ?usize {
|
|||
|
||||
const CellState = struct { enabled: bool = false, tile: u8 };
|
||||
const MAXCELLS = 400;
|
||||
const CellMap = [MAXCELLS]CellState; // std.AutoHashMap(Cell, CellState);
|
||||
const CellMap = [MAXCELLS]CellState;
|
||||
|
||||
offset: Cell,
|
||||
cells: CellMap,
|
||||
|
|
|
@ -152,21 +152,18 @@ pub fn World(comptime ComponentBase: type) type {
|
|||
const Self = @This();
|
||||
const Iterator = struct {
|
||||
world: *Self,
|
||||
// lastIndex: ?usize,
|
||||
index: usize,
|
||||
query: ComponentQuery,
|
||||
|
||||
pub fn init(w: *Self, q: ComponentQuery) @This() {
|
||||
return @This(){
|
||||
.world = w,
|
||||
// .lastComponent = null,
|
||||
.index = 0,
|
||||
.query = q,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(this: *@This()) ?usize {
|
||||
// if (this.lastIndex) |_| this.index += 1;
|
||||
if (this.index == this.world.components.len) return null;
|
||||
var match = false;
|
||||
while (!match) {
|
||||
|
|
147
src/main.zig
147
src/main.zig
|
@ -3,18 +3,13 @@ const w4 = @import("wasm4.zig");
|
|||
const ecs = @import("ecs.zig");
|
||||
const assets = @import("assets");
|
||||
const input = @import("input.zig");
|
||||
const util = @import("util.zig");
|
||||
const Circuit = @import("circuit.zig");
|
||||
const Map = @import("map.zig");
|
||||
|
||||
const Vec2 = std.meta.Vector(2, i32);
|
||||
const Vec2f = std.meta.Vector(2, f32);
|
||||
const AABB = struct {
|
||||
pos: Vec2f,
|
||||
size: Vec2f,
|
||||
|
||||
pub fn addv(this: @This(), vec2f: Vec2f) @This() {
|
||||
return @This(){ .pos = this.pos + vec2f, .size = this.size };
|
||||
}
|
||||
};
|
||||
const Vec2 = util.Vec2;
|
||||
const Vec2f = util.Vec2f;
|
||||
const AABB = util.AABB;
|
||||
const Anim = struct {
|
||||
time: usize = 0,
|
||||
currentOp: usize = 0,
|
||||
|
@ -112,9 +107,10 @@ const World = ecs.World(Component);
|
|||
|
||||
// Global vars
|
||||
const KB = 1024;
|
||||
var heap: [8 * KB]u8 = undefined;
|
||||
var heap: [16 * KB]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&heap);
|
||||
var world: World = World.init(fba.allocator());
|
||||
var map: Map = undefined;
|
||||
var circuit = Circuit.init(Vec2{ 0, 0 }, &assets.conduit);
|
||||
|
||||
const anim_store = struct {
|
||||
|
@ -143,6 +139,7 @@ fn showErr(msg: []const u8) noreturn {
|
|||
}
|
||||
|
||||
export fn start() void {
|
||||
map = Map.init(Vec2{ 0, 0 }, &assets.solid, fba.allocator()) catch showErr("Couldn't init map");
|
||||
_ = world.create(.{
|
||||
.pos = Pos.init(Vec2f{ 100, 80 }),
|
||||
.control = .{ .controller = .player, .state = .stand },
|
||||
|
@ -215,13 +212,7 @@ export fn update() void {
|
|||
}
|
||||
}
|
||||
|
||||
w4.DRAW_COLORS.* = 0x0210;
|
||||
for (assets.solid) |tilePlus, i| {
|
||||
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 });
|
||||
}
|
||||
map.draw();
|
||||
|
||||
for (circuit.cells) |cell, i| {
|
||||
const tilePlus = cell.tile;
|
||||
|
@ -337,7 +328,8 @@ fn wireManipulationProcess(_: f32, id: usize, pos: *Pos, control: *Control) void
|
|||
} else {
|
||||
const interactDistance = 4;
|
||||
var minDistance: f32 = interactDistance;
|
||||
var wireIter = world.iter(World.Query.require(&.{.wire}));
|
||||
const q = World.Query.require(&.{.wire});
|
||||
var wireIter = world.iter(q);
|
||||
var interactWireID: ?usize = null;
|
||||
var which: usize = 0;
|
||||
while (wireIter.next()) |entityID| {
|
||||
|
@ -346,15 +338,16 @@ fn wireManipulationProcess(_: f32, id: usize, pos: *Pos, control: *Control) void
|
|||
const nodes = wire.nodes.constSlice();
|
||||
const begin = nodes[0].pos;
|
||||
const end = nodes[wire.nodes.len - 1].pos;
|
||||
var beginDist = distancef(begin, pos.pos + offset);
|
||||
var endDist = distancef(end, pos.pos + offset);
|
||||
if (beginDist < minDistance) {
|
||||
minDistance = beginDist;
|
||||
var dist = distancef(begin, pos.pos + offset);
|
||||
if (dist < minDistance) {
|
||||
minDistance = dist;
|
||||
indicator = .{ .t = .wire, .pos = vec2ftovec2(begin) };
|
||||
interactWireID = entityID;
|
||||
which = 0;
|
||||
} else if (endDist < minDistance) {
|
||||
minDistance = endDist;
|
||||
}
|
||||
dist = distancef(end, pos.pos + offset);
|
||||
if (dist < minDistance) {
|
||||
minDistance = dist;
|
||||
indicator = .{ .t = .wire, .pos = vec2ftovec2(end) };
|
||||
interactWireID = entityID;
|
||||
which = wire.nodes.len - 1;
|
||||
|
@ -384,13 +377,6 @@ fn distancef(a: Vec2f, b: Vec2f) f32 {
|
|||
return @reduce(.Max, subbed);
|
||||
}
|
||||
|
||||
fn is_solid(pos: Vec2) bool {
|
||||
if (get_tile(pos[0], pos[1])) |tile| {
|
||||
return tile != 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn vec_length(vec: Vec2f) f32 {
|
||||
var squared = vec * vec;
|
||||
return @sqrt(@reduce(.Add, squared));
|
||||
|
@ -430,64 +416,19 @@ fn collideNode(node: *Pos) void {
|
|||
const tileSizef = vec2tovec2f(tileSize);
|
||||
const iPos = vec2ftovec2(node.pos);
|
||||
const mapPos = @divTrunc(iPos, tileSize);
|
||||
if (is_solid(mapPos)) {
|
||||
if (map.isSolid(mapPos)) {
|
||||
const velNorm = normalize(node.pos - node.last);
|
||||
var collideVec = node.last;
|
||||
while (!is_solid(vec2ftovec2((collideVec + velNorm) / tileSizef))) {
|
||||
while (!map.isSolid(vec2ftovec2((collideVec + velNorm) / tileSizef))) {
|
||||
collideVec += velNorm;
|
||||
}
|
||||
node.pos = collideVec;
|
||||
}
|
||||
}
|
||||
|
||||
const Hit = struct {
|
||||
delta: Vec2f,
|
||||
normal: Vec2f,
|
||||
pos: Vec2f,
|
||||
};
|
||||
const mapTileVecf = Vec2f{ 8, 8 };
|
||||
const mapTileVec = Vec2{ 8, 8 };
|
||||
/// Returns delta
|
||||
fn collidePointMap(point: Vec2f) ?Hit {
|
||||
const cell = vec2ftovec2(point / mapTileVecf);
|
||||
const mapPos = vec2tovec2f(cell * mapTileVec);
|
||||
const half = (mapTileVecf / @splat(2, @as(f32, 2)));
|
||||
if (is_solid(cell)) {
|
||||
const diff = mapPos - point;
|
||||
const p = half - @fabs(diff);
|
||||
var delta = Vec2f{ 0, 0 };
|
||||
var normal = Vec2f{ 0, 0 };
|
||||
var pos = Vec2f{ 0, 0 };
|
||||
if (p[0] > p[1]) {
|
||||
const sx = std.math.copysign(f32, 1, delta[0]);
|
||||
delta[0] = p[0] * sx;
|
||||
normal[0] = sx;
|
||||
pos = Vec2f{ point[0] + (half[0] * sx), point[1] };
|
||||
} else {
|
||||
const sy = std.math.copysign(f32, 1, delta[1]);
|
||||
delta[1] = p[1] * sy;
|
||||
normal[1] = sy;
|
||||
pos = Vec2f{ point[0], point[1] + (half[1] * sy) };
|
||||
}
|
||||
return Hit{
|
||||
.delta = delta,
|
||||
.normal = normal,
|
||||
.pos = pos,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const wireSegmentMaxLength = 4;
|
||||
const wireSegmentMaxLengthV = @splat(2, @as(f32, wireSegmentMaxLength));
|
||||
|
||||
// fn constrainToAnchor(anchor: *Pos, node: *Pos) void {
|
||||
// var diff = anchor.pos - node.pos;
|
||||
// var dist = distancef(node.pos, anchor.pos);
|
||||
// var wireLength = @maximum(wireSegmentMaxLength, dist);
|
||||
// node.pos = anchor.pos - (normalize(diff) * @splat(2, @as(f32, wireLength)));
|
||||
// }
|
||||
|
||||
fn wireMaxLength(wire: *Wire) f32 {
|
||||
return @intToFloat(f32, wire.nodes.len) * wireSegmentMaxLength;
|
||||
}
|
||||
|
@ -600,13 +541,6 @@ fn controlProcess(_: f32, pos: *Pos, control: *Control, physics: *Physics, kinem
|
|||
pos.pos += move;
|
||||
}
|
||||
|
||||
/// pos should be in tile coordinates, not world coordinates
|
||||
fn get_tile(x: i32, y: i32) ?u8 {
|
||||
if (x < 0 or x > 19 or y < 0 or y > 19) return null;
|
||||
const i = x + y * 20;
|
||||
return assets.solid[@intCast(u32, i)];
|
||||
}
|
||||
|
||||
fn getTile(cell: Vec2) ?u8 {
|
||||
const x = cell[0];
|
||||
const y = cell[1];
|
||||
|
@ -615,45 +549,10 @@ fn getTile(cell: Vec2) ?u8 {
|
|||
return assets.solid[@intCast(u32, i)];
|
||||
}
|
||||
|
||||
fn cellCollider(cell: Vec2) AABB {
|
||||
const tileSize = 8;
|
||||
return AABB{
|
||||
.pos = vec2tovec2f(cell * tileSize),
|
||||
.size = @splat(2, @as(f32, tileSize)),
|
||||
};
|
||||
}
|
||||
|
||||
/// rect should be absolutely positioned. Add pos to kinematic.collider
|
||||
fn level_collide(rect: AABB) std.BoundedArray(AABB, 9) {
|
||||
const tileSize = 8;
|
||||
const top_left = rect.pos / @splat(2, @as(f32, tileSize));
|
||||
const bot_right = (rect.pos + rect.size) / @splat(2, @as(f32, tileSize));
|
||||
var collisions = std.BoundedArray(AABB, 9).init(0) catch unreachable;
|
||||
|
||||
var i: isize = @floatToInt(i32, top_left[0]);
|
||||
while (i <= @floatToInt(i32, bot_right[0])) : (i += 1) {
|
||||
var a: isize = @floatToInt(i32, top_left[1]);
|
||||
while (a <= @floatToInt(i32, bot_right[1])) : (a += 1) {
|
||||
var tile = get_tile(i, a);
|
||||
if (tile == null or tile.? != 1) {
|
||||
collisions.append(AABB{
|
||||
.pos = Vec2f{
|
||||
@intToFloat(f32, i * tileSize),
|
||||
@intToFloat(f32, a * tileSize),
|
||||
},
|
||||
.size = Vec2f{ tileSize, tileSize },
|
||||
}) catch unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return collisions;
|
||||
}
|
||||
|
||||
fn kinematicProcess(_: f32, pos: *Pos, kinematic: *Kinematic) void {
|
||||
var next = pos.last;
|
||||
next[0] = pos.pos[0];
|
||||
var hcol = level_collide(kinematic.col.addv(next));
|
||||
var hcol = map.collide(kinematic.col.addv(next));
|
||||
if (hcol.len > 0) {
|
||||
kinematic.lastCol[0] = next[0] - pos.last[0];
|
||||
next[0] = pos.last[0];
|
||||
|
@ -662,7 +561,7 @@ fn kinematicProcess(_: f32, pos: *Pos, kinematic: *Kinematic) void {
|
|||
}
|
||||
|
||||
next[1] = pos.pos[1];
|
||||
var vcol = level_collide(kinematic.col.addv(next));
|
||||
var vcol = map.collide(kinematic.col.addv(next));
|
||||
if (vcol.len > 0) {
|
||||
kinematic.lastCol[1] = next[1] - pos.last[1];
|
||||
next[1] = pos.last[1];
|
||||
|
@ -671,7 +570,7 @@ fn kinematicProcess(_: f32, pos: *Pos, kinematic: *Kinematic) void {
|
|||
}
|
||||
|
||||
var colPosAbs = next + kinematic.lastCol;
|
||||
var lastCol = level_collide(kinematic.col.addv(colPosAbs));
|
||||
var lastCol = map.collide(kinematic.col.addv(colPosAbs));
|
||||
if (lastCol.len == 0) {
|
||||
kinematic.lastCol = Vec2f{ 0, 0 };
|
||||
}
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
const std = @import("std");
|
||||
const assets = @import("assets");
|
||||
const util = @import("util.zig");
|
||||
const w4 = @import("wasm4.zig");
|
||||
|
||||
const Vec2 = util.Vec2;
|
||||
const Vec2f = util.Vec2f;
|
||||
const Cell = util.Cell;
|
||||
|
||||
const MAXCELLS = 400;
|
||||
|
||||
const width = 20;
|
||||
const height = 20;
|
||||
const tile_width = 8;
|
||||
const tile_height = 8;
|
||||
const tile_size = Vec2{ 8, 8 };
|
||||
const tile_sizef = Vec2f{ 8, 8 };
|
||||
const tilemap_width = 16;
|
||||
const tilemap_height = 16;
|
||||
const tilemap_stride = 128;
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
tiles: []u8,
|
||||
offset: Cell,
|
||||
|
||||
pub fn init(offset: Cell, map: []const u8, alloc: std.mem.Allocator) !@This() {
|
||||
var tiles = try alloc.alloc(u8, MAXCELLS);
|
||||
var this = @This(){
|
||||
.alloc = alloc,
|
||||
.offset = offset,
|
||||
.tiles = tiles,
|
||||
};
|
||||
var y: usize = 0;
|
||||
while (y < height) : (y += 1) {
|
||||
var x: usize = 0;
|
||||
while (x < width) : (x += 1) {
|
||||
const i = x + y * 20;
|
||||
const a = (@intCast(usize, offset[0]) + x) + (@intCast(usize, offset[1]) + y) * 20;
|
||||
this.tiles[i] = map[a];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
pub fn deinit(this: @This()) void {
|
||||
this.alloc.free(this.tiles);
|
||||
}
|
||||
|
||||
pub fn draw(this: @This()) void {
|
||||
w4.DRAW_COLORS.* = 0x0210;
|
||||
for (this.tiles) |tilePlus, i| {
|
||||
const tile = tilePlus - 1;
|
||||
const t = Vec2{
|
||||
@intCast(i32, (tile % tilemap_width) * tile_width),
|
||||
@intCast(i32, (tile / tilemap_width) * tile_width),
|
||||
};
|
||||
const pos = Vec2{
|
||||
@intCast(i32, (i % width) * tile_width),
|
||||
@intCast(i32, (i / width) * tile_width),
|
||||
};
|
||||
w4.blitSub(
|
||||
&assets.tiles,
|
||||
pos,
|
||||
.{ tile_width, tile_height },
|
||||
t,
|
||||
tilemap_stride,
|
||||
.{ .bpp = .b2 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// pos should be in tile coordinates, not world coordinates
|
||||
fn getTile(this: @This(), x: i32, y: i32) ?u8 {
|
||||
if (x < 0 or x > 19 or y < 0 or y > 19) return null;
|
||||
const i = x + y * 20;
|
||||
return this.tiles[@intCast(u32, i)];
|
||||
}
|
||||
|
||||
pub fn collide(this: @This(), rect: util.AABB) std.BoundedArray(util.AABB, 9) {
|
||||
const top_left = rect.pos / tile_sizef;
|
||||
const bot_right = (rect.pos + rect.size) / tile_sizef;
|
||||
var collisions = std.BoundedArray(util.AABB, 9).init(0) catch unreachable;
|
||||
|
||||
var i: isize = @floatToInt(i32, top_left[0]);
|
||||
while (i <= @floatToInt(i32, bot_right[0])) : (i += 1) {
|
||||
var a: isize = @floatToInt(i32, top_left[1]);
|
||||
while (a <= @floatToInt(i32, bot_right[1])) : (a += 1) {
|
||||
var tile = this.getTile(i, a);
|
||||
if (tile == null or tile.? != 1) {
|
||||
collisions.append(util.AABB{
|
||||
.pos = Vec2f{
|
||||
@intToFloat(f32, i * tile_width),
|
||||
@intToFloat(f32, a * tile_height),
|
||||
},
|
||||
.size = tile_sizef,
|
||||
}) catch unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return collisions;
|
||||
}
|
||||
|
||||
pub fn isSolid(this: @This(), cell: Cell) bool {
|
||||
if (this.getTile(cell[0], cell[1])) |tile| {
|
||||
return tile != 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Debug functions
|
||||
|
||||
pub fn trace(this: @This()) void {
|
||||
var y: usize = 0;
|
||||
while (y < height) : (y += 1) {
|
||||
const i = y * width;
|
||||
w4.trace("{any}", .{this.tiles[i .. i + width]});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn traceDraw(this: @This()) void {
|
||||
for (this.tiles) |tilePlus, i| {
|
||||
const tile = tilePlus - 1;
|
||||
const t = Vec2{
|
||||
@intCast(i32, (tile % tilemap_width) * tile_width),
|
||||
@intCast(i32, (tile / tilemap_width) * tile_width),
|
||||
};
|
||||
const pos = Vec2{
|
||||
@intCast(i32, (i % width) * tile_width),
|
||||
@intCast(i32, (i / width) * tile_width),
|
||||
};
|
||||
w4.trace("{}, {}, {}, {}, {}", .{
|
||||
pos,
|
||||
.{ tile_width, tile_height },
|
||||
t,
|
||||
tilemap_stride,
|
||||
.{ .bpp = .b2 },
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const Vec2f = std.meta.Vector(2, f32);
|
||||
pub const Vec2 = std.meta.Vector(2, i32);
|
||||
pub const Cell = Vec2;
|
||||
|
||||
pub fn world2cell(vec: Vec2f) Vec2 {
|
||||
return vec2fToVec2(vec / @splat(2, @as(f32, 8)));
|
||||
}
|
||||
|
||||
fn vec2ToVec2f(vec2: Vec2) Vec2f {
|
||||
return Vec2f{ @intToFloat(f32, vec2[0]), @intToFloat(f32, vec2[1]) };
|
||||
}
|
||||
|
||||
fn vec2fToVec2(vec2f: Vec2f) Vec2 {
|
||||
return Vec2{ @floatToInt(i32, vec2f[0]), @floatToInt(i32, vec2f[1]) };
|
||||
}
|
||||
|
||||
pub const AABB = struct {
|
||||
pos: Vec2f,
|
||||
size: Vec2f,
|
||||
|
||||
pub fn addv(this: @This(), vec2f: Vec2f) @This() {
|
||||
return @This(){ .pos = this.pos + vec2f, .size = this.size };
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue