diff --git a/assets/tiled/map.tmx b/assets/tiled/map.tmx index a3ad273..214cbc3 100644 --- a/assets/tiled/map.tmx +++ b/assets/tiled/map.tmx @@ -25,7 +25,7 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -34,7 +34,7 @@ 0,0,0,0,0,0,98,98,101,98,98,98,98,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,98,0,0,98,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,98,0,0,0,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,98,0,0,0,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,98,0,7,0,0,26,0,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,98,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,98,0,0,98,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,98,98,98,98,98,101,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -47,34 +47,10 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,7,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,7,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - + diff --git a/assets/tiled/tileset.tsx b/assets/tiled/tileset.tsx index 1433f9c..e1e3538 100644 --- a/assets/tiled/tileset.tsx +++ b/assets/tiled/tileset.tsx @@ -1,4 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app.zig b/src/app.zig index b85ab78..4ae9db6 100644 --- a/src/app.zig +++ b/src/app.zig @@ -47,11 +47,11 @@ const PlayerSprites = struct { const Tile = struct { ground_sprite: ?Gfx.Sprite.Id, - entity: Entity.Id, + entities_by_layer: std.EnumArray(Entity.Layer, Entity.Id), const empty = Tile{ .ground_sprite = null, - .entity = .nil + .entities_by_layer = .initFill(.nil) }; }; @@ -84,6 +84,7 @@ const Tilemap = struct { const Entity = struct { type: Type, + layer: Layer, pos_x: i32 = -1, pos_y: i32 = -1, @@ -96,9 +97,15 @@ const Entity = struct { const Type = enum { player, box, + goal_marker, wall }; + const Layer = enum { + ground, + surface, + }; + const SlotMap = Platform.SlotMapType(u16, u8, Entity); const Id = SlotMap.Id; }; @@ -107,24 +114,22 @@ const World = struct { tilemap: Tilemap, entities: Entity.SlotMap, - fn spawnPlayer(self: *World) !Entity.Id { - return try self.entities.insert(Entity{ - .type = .player, - }); - } + fn spawnEntity(self: *World, opts: Entity) Entity.Id { + var e = opts; + e.pos_x = -1; + e.pos_y = -1; + const entity_id = self.entities.insert(e) catch |err| { + log.err("Failed to spawn entity: {}", .{err}); + return .nil; + }; - fn spawnBox(self: *World, sprite: Gfx.Sprite.Id) !Entity.Id { - return try self.entities.insert(Entity{ - .type = .box, - .sprite = sprite - }); - } + if (opts.pos_x != -1 or opts.pos_y != -1) { + assert(opts.pos_x != -1 and opts.pos_y != -1); + const success = self.setEntityPosition(entity_id, opts.pos_x, opts.pos_y); + assert(success); + } - fn spawnWall(self: *World, sprite: Gfx.Sprite.Id) !Entity.Id { - return try self.entities.insert(Entity{ - .type = .wall, - .sprite = sprite - }); + return entity_id; } fn getTile(self: *World, x: i32, y: i32) ?*Tile { @@ -136,23 +141,18 @@ const World = struct { return null; } - fn getEntityAt(self: *World, x: i32, y: i32) Entity.Id { - const tile = self.getTile(x, y) orelse return .nil; - return tile.entity; - } - fn setEntityPosition(self: *World, id: Entity.Id, x: i32, y: i32) bool { const e = self.entities.get(id) orelse return false; const destination_tile = self.getTile(x, y) orelse return false; - if (self.entities.exists(destination_tile.entity)) { + if (self.entities.exists(destination_tile.entities_by_layer.get(e.layer))) { // Cant't overwrite entity return false; } - destination_tile.entity = id; + destination_tile.entities_by_layer.set(e.layer, id); if (self.getTile(e.pos_x, e.pos_y)) |tile| { - tile.entity = .nil; + tile.entities_by_layer.set(e.layer, .nil); } e.pos_x = x; @@ -170,9 +170,10 @@ const World = struct { const destination_tile = self.getTile(next_x, next_y) orelse return false; if (e.type == .player or e.type == .box) { - if (self.entities.get(destination_tile.entity)) |destination_entity| { + const destination_entity_id = destination_tile.entities_by_layer.get(e.layer); + if (self.entities.get(destination_entity_id)) |destination_entity| { if (destination_entity.type == .box) { - if (!self.moveEntity(destination_tile.entity, dx, dy)) { + if (!self.moveEntity(destination_entity_id, dx, dy)) { return false; } } @@ -266,7 +267,6 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 { } }; - var player_pos: Vec2 = .zero; { var scratch = std.heap.ArenaAllocator.init(plt.gpa); defer scratch.deinit(); @@ -287,7 +287,7 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 { self.world.tilemap = try Tilemap.init(plt.gpa, bounds.width(), bounds.height()); const ground = tilemap.getLayer("Ground").?; - const walls = tilemap.getLayer("Walls").?; + const foreground = tilemap.getLayer("Foreground").?; for (0..bounds.height()) |oy| { for (0..bounds.width()) |ox| { const x = bounds.min_x + ox; @@ -300,39 +300,54 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 { tile.ground_sprite = tilesheet.get(pos.x, pos.y); } - if (tilemap.getTile(walls, tilesets, x, y)) |tiled_tile| { + if (tilemap.getTile(foreground, tilesets, x, y)) |tiled_tile| { const pos = tiled_tile.getPosition(); - const wall_id = try self.world.spawnWall(tilesheet.get(pos.x, pos.y)); - _ = self.world.setEntityPosition(wall_id, @intCast(ox), @intCast(oy)); + const props = tiled_tile.getProperties(); + const props_type = props.getString("type") orelse ""; + + var entity_type: ?Entity.Type = null; + var layer: Entity.Layer = .surface; + if (std.mem.eql(u8, props_type, "wall")) { + entity_type = .wall; + } else if (std.mem.eql(u8, props_type, "box")) { + entity_type = .box; + } else if (std.mem.eql(u8, props_type, "goal_marker")) { + entity_type = .goal_marker; + layer = .ground; + } else { + log.warn("Unknown tile type: '{s}'", .{props_type}); + } + + if (entity_type != null) { + _ = self.world.spawnEntity(Entity{ + .type = entity_type.?, + .layer = layer, + .pos_x = @intCast(ox), + .pos_y = @intCast(oy), + .sprite = tilesheet.get(pos.x, pos.y) + }); + } } } } const markers = &tilemap.getLayer("Markers").?.variant.object; const spawn = markers.getByName("spawn").?; + + var player_pos: Vec2 = .zero; player_pos.x = @divFloor(spawn.shape.point.x, @as(f32, @floatFromInt(tilemap.tile_width))); player_pos.x -= @floatFromInt(bounds.min_x); player_pos.y = @divFloor(spawn.shape.point.y, @as(f32, @floatFromInt(tilemap.tile_height))); player_pos.y -= @floatFromInt(bounds.min_y); - const boxes = tilemap.getLayer("Boxes").?; - for (0..bounds.height()) |oy| { - for (0..bounds.width()) |ox| { - const x = bounds.min_x + ox; - const y = bounds.min_y + oy; - - if (tilemap.getTile(boxes, tilesets, x, y)) |tiled_tile| { - const pos = tiled_tile.getPosition(); - const box_id = try self.world.spawnBox(tilesheet.get(pos.x, pos.y)); - _ = self.world.setEntityPosition(box_id, @intCast(ox), @intCast(oy)); - } - } - } + _ = self.world.spawnEntity(Entity{ + .type = .player, + .layer = .surface, + .pos_x = @intFromFloat(player_pos.x), + .pos_y = @intFromFloat(player_pos.y) + }); } - const player_id = try self.world.spawnPlayer(); - _ = self.world.setEntityPosition(player_id, @intFromFloat(player_pos.x), @intFromFloat(player_pos.y)); - return null; } @@ -378,56 +393,68 @@ pub fn frame(self: *App, plt: Platform.Frame) !void { } } - var entity_iter = self.world.entities.iterator(); - while (entity_iter.next()) |entity_id| { - const entity = self.world.entities.getAssumeExists(entity_id); - if (entity.type == .player) { - if ((dir_x != 0 or dir_y != 0) and self.world.moveEntity(entity_id, dir_x, dir_y)) { - var new_direction = entity.player_direction; - if (dir_x < 0) { - new_direction = .left; - } else if (dir_x > 0) { - new_direction = .right; - } else if (dir_y > 0) { - new_direction = .down; - } else if (dir_y < 0) { - new_direction = .up; + { + var entity_iter = self.world.entities.iterator(); + while (entity_iter.next()) |entity_id| { + const entity = self.world.entities.getAssumeExists(entity_id); + if (entity.type == .player) { + if ((dir_x != 0 or dir_y != 0) and self.world.moveEntity(entity_id, dir_x, dir_y)) { + var new_direction = entity.player_direction; + if (dir_x < 0) { + new_direction = .left; + } else if (dir_x > 0) { + new_direction = .right; + } else if (dir_y > 0) { + new_direction = .down; + } else if (dir_y < 0) { + new_direction = .up; + } + + if (entity.player_direction != new_direction) { + entity.player_frame_index = 0; + entity.player_direction = new_direction; + } + + self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .bus = self.sfx_bus }); } - if (entity.player_direction != new_direction) { + const frames = self.player_sprites.getDirection(entity.player_direction); + + if (dir_x != 0 or dir_y != 0) { + self.animation_timer += plt.input.delta_time; + const animatin_time = std.time.ns_per_s / 5; + while (self.animation_timer >= animatin_time) { + entity.player_frame_index = (entity.player_frame_index + 1) % @as(u32, @intCast(frames.len)); + self.animation_timer -= animatin_time; + } + } else { + self.animation_timer = 0; entity.player_frame_index = 0; - entity.player_direction = new_direction; } - self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .bus = self.sfx_bus }); + entity.sprite = frames[entity.player_frame_index]; } - const frames = self.player_sprites.getDirection(entity.player_direction); - - if (dir_x != 0 or dir_y != 0) { - self.animation_timer += plt.input.delta_time; - const animatin_time = std.time.ns_per_s / 5; - while (self.animation_timer >= animatin_time) { - entity.player_frame_index = (entity.player_frame_index + 1) % @as(u32, @intCast(frames.len)); - self.animation_timer -= animatin_time; - } - } else { - self.animation_timer = 0; - entity.player_frame_index = 0; - } - - entity.sprite = frames[entity.player_frame_index]; + entity.visual_pos = .initFromInt(i32, entity.pos_x, entity.pos_y); } + } - entity.visual_pos = .initFromInt(i32, entity.pos_x, entity.pos_y); + inline for (.{ Entity.Layer.ground, Entity.Layer.surface }) |layer| { + var entity_iter = self.world.entities.iterator(); + while (entity_iter.next()) |entity_id| { + const entity = self.world.entities.getAssumeExists(entity_id); + if (entity.layer != layer) { + continue; + } - if (entity.sprite) |sprite| { - Gfx.drawSprite( - sprite, - entity.visual_pos.multiply(tile_size), - tile_size, - .white - ); + if (entity.sprite) |sprite| { + Gfx.drawSprite( + sprite, + entity.visual_pos.multiply(tile_size), + tile_size, + .white + ); + } } }