implement parsing multiple levels from map file
This commit is contained in:
parent
b6d9f1664b
commit
a6bf95c570
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.10" tiledversion="1.12.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="64" tileheight="64" infinite="1" nextlayerid="8" nextobjectid="17">
|
<map version="1.10" tiledversion="1.12.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="64" tileheight="64" infinite="1" nextlayerid="8" nextobjectid="19">
|
||||||
<tileset firstgid="1" source="tileset.tsx"/>
|
<tileset firstgid="1" source="tileset.tsx"/>
|
||||||
<layer id="2" name="Ground" width="30" height="20">
|
<layer id="2" name="Ground" width="30" height="20">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
@ -85,14 +85,17 @@
|
|||||||
<object id="1" name="spawn" x="484" y="555">
|
<object id="1" name="spawn" x="484" y="555">
|
||||||
<point/>
|
<point/>
|
||||||
</object>
|
</object>
|
||||||
|
<object id="17" name="spawn" x="1381.33" y="497.333">
|
||||||
|
<point/>
|
||||||
|
</object>
|
||||||
</objectgroup>
|
</objectgroup>
|
||||||
<objectgroup id="7" name="Level bounds">
|
<objectgroup id="7" name="Level bounds">
|
||||||
<object id="15" x="345.333" y="218.667" width="633.333" height="566.667">
|
<object id="15" x="324" y="214.667" width="633.333" height="566.667">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="level" type="int" value="1"/>
|
<property name="level" type="int" value="1"/>
|
||||||
</properties>
|
</properties>
|
||||||
</object>
|
</object>
|
||||||
<object id="16" x="1228" y="172" width="565.333" height="593.333">
|
<object id="18" x="1196.67" y="206" width="633.333" height="566.667">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="level" type="int" value="2"/>
|
<property name="level" type="int" value="2"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ const std = @import("std");
|
|||||||
const xml = @import("./xml.zig");
|
const xml = @import("./xml.zig");
|
||||||
const Position = @import("./position.zig");
|
const Position = @import("./position.zig");
|
||||||
const Color = @import("./color.zig");
|
const Color = @import("./color.zig");
|
||||||
|
const Property = @import("./property.zig");
|
||||||
|
|
||||||
const Object = @This();
|
const Object = @This();
|
||||||
|
|
||||||
@ -113,6 +114,7 @@ class: []const u8,
|
|||||||
rotation: f32, // TODO: maybe this field should be moved to Shape struct
|
rotation: f32, // TODO: maybe this field should be moved to Shape struct
|
||||||
visible: bool,
|
visible: bool,
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
|
properties: Property.List,
|
||||||
|
|
||||||
pub fn initFromXml(
|
pub fn initFromXml(
|
||||||
arena: std.mem.Allocator,
|
arena: std.mem.Allocator,
|
||||||
@ -255,13 +257,16 @@ pub fn initFromXml(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const properties = try Property.List.initFromXmlContainer(arena, doc, element_id);
|
||||||
|
|
||||||
return Object{
|
return Object{
|
||||||
.id = id,
|
.id = id,
|
||||||
.name = name,
|
.name = name,
|
||||||
.class = class,
|
.class = class,
|
||||||
.rotation = rotation,
|
.rotation = rotation,
|
||||||
.visible = visible,
|
.visible = visible,
|
||||||
.shape = shape orelse return error.UnknownShapeType
|
.shape = shape orelse return error.UnknownShapeType,
|
||||||
|
.properties = properties
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,24 @@ pub const List = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initFromXmlContainer(
|
||||||
|
arena: std.mem.Allocator,
|
||||||
|
doc: xml.Document,
|
||||||
|
element_id: xml.Element.Id
|
||||||
|
) !Property.List {
|
||||||
|
var iter = doc.iterChildren(element_id);
|
||||||
|
while (iter.next()) |child_id| {
|
||||||
|
const child = doc.getTag(child_id) orelse continue;
|
||||||
|
const child_name = child.variant.tag.name;
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, child_name, "properties")) {
|
||||||
|
return try Property.List.initFromXml(arena, doc, child_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .empty;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(self: List, name: []const u8) ?Value {
|
pub fn get(self: List, name: []const u8) ?Value {
|
||||||
for (self.items) |item| {
|
for (self.items) |item| {
|
||||||
if (std.mem.eql(u8, item.name, name)) {
|
if (std.mem.eql(u8, item.name, name)) {
|
||||||
@ -68,7 +86,18 @@ pub const List = struct {
|
|||||||
|
|
||||||
pub fn getString(self: List, name: []const u8) ?[]const u8 {
|
pub fn getString(self: List, name: []const u8) ?[]const u8 {
|
||||||
if (self.get(name)) |value| {
|
if (self.get(name)) |value| {
|
||||||
return value.string;
|
if (value == .string) {
|
||||||
|
return value.string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getInt(self: List, name: []const u8) ?i32 {
|
||||||
|
if (self.get(name)) |value| {
|
||||||
|
if (value == .int) {
|
||||||
|
return value.int;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -263,6 +263,10 @@ pub const Bounds = struct {
|
|||||||
pub fn height(self: Bounds) u32 {
|
pub fn height(self: Bounds) u32 {
|
||||||
return @intCast(self.max_y - self.min_y + 1);
|
return @intCast(self.max_y - self.min_y + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isInside(self: Bounds, x: i32, y: i32) bool {
|
||||||
|
return (self.min_x <= x and x <= self.max_x) and (self.min_y <= y and y <= self.max_y);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getTileBounds(self: *const Tilemap) Bounds {
|
pub fn getTileBounds(self: *const Tilemap) Bounds {
|
||||||
@ -274,29 +278,21 @@ pub fn getTileBounds(self: *const Tilemap) Bounds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (layer.variant.tile.chunks) |chunk| {
|
for (layer.variant.tile.chunks) |chunk| {
|
||||||
for (0..chunk.height) |oy| {
|
const chunk_bounds = Bounds{
|
||||||
for (0..chunk.width) |ox| {
|
.min_x = chunk.x,
|
||||||
const x = chunk.x + @as(i32, @intCast(ox));
|
.min_y = chunk.y,
|
||||||
const y = chunk.y + @as(i32, @intCast(oy));
|
.max_x = chunk.x + @as(i32, @intCast(chunk.width)),
|
||||||
const gid = layer.variant.tile.get(x, y).?;
|
.max_y = chunk.y + @as(i32, @intCast(chunk.height))
|
||||||
if (gid != 0) {
|
};
|
||||||
if (result) |bounds| {
|
if (result) |bounds| {
|
||||||
result = Bounds{
|
result = Bounds{
|
||||||
.min_x = @min(x, bounds.min_x),
|
.min_x = @min(chunk_bounds.min_x, bounds.min_x),
|
||||||
.min_y = @min(y, bounds.min_y),
|
.min_y = @min(chunk_bounds.min_y, bounds.min_y),
|
||||||
.max_x = @max(x, bounds.max_x),
|
.max_x = @max(chunk_bounds.max_x, bounds.max_x),
|
||||||
.max_y = @max(y, bounds.max_y)
|
.max_y = @max(chunk_bounds.max_y, bounds.max_y)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
result = Bounds{
|
result = chunk_bounds;
|
||||||
.min_x = x,
|
|
||||||
.min_y = y,
|
|
||||||
.max_x = x,
|
|
||||||
.max_y = y
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,6 +300,59 @@ pub fn getTileBounds(self: *const Tilemap) Bounds {
|
|||||||
return result orelse Bounds.zero;
|
return result orelse Bounds.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn isRowEmpty(tile_layer: Layer.TileVariant, x: i32, y: i32, length: u32) bool {
|
||||||
|
for (0..length) |i| {
|
||||||
|
const gid = tile_layer.get(x + @as(i32, @intCast(i)), y) orelse continue;
|
||||||
|
if (gid != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isColumnEmpty(tile_layer: Layer.TileVariant, x: i32, y: i32, length: u32) bool {
|
||||||
|
for (0..length) |i| {
|
||||||
|
const gid = tile_layer.get(x, y + @as(i32, @intCast(i))) orelse continue;
|
||||||
|
if (gid != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trimBoundsByEmptyTiles(self: *const Tilemap, bounds: Bounds) Bounds {
|
||||||
|
var result: Bounds = bounds;
|
||||||
|
|
||||||
|
for (self.layers) |*layer| {
|
||||||
|
if (layer.variant != .tile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const tile_layer = layer.variant.tile;
|
||||||
|
|
||||||
|
// Trim left
|
||||||
|
while (result.min_x < result.max_x and isColumnEmpty(tile_layer, result.min_x, result.min_y, result.height())) {
|
||||||
|
result.min_x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim right
|
||||||
|
while (result.min_x < result.max_x and isColumnEmpty(tile_layer, result.max_x, result.min_y, result.height())) {
|
||||||
|
result.max_x -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim top
|
||||||
|
while (result.min_y < result.max_y and isRowEmpty(tile_layer, result.min_x, result.min_y, result.width())) {
|
||||||
|
result.min_y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim bottom
|
||||||
|
while (result.min_y < result.max_y and isRowEmpty(tile_layer, result.min_x, result.max_y, result.width())) {
|
||||||
|
result.max_y -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Tilemap) void {
|
pub fn deinit(self: *const Tilemap) void {
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,18 +43,7 @@ pub const Tile = struct {
|
|||||||
const tile_attrs = tag.variant.tag.attributes;
|
const tile_attrs = tag.variant.tag.attributes;
|
||||||
|
|
||||||
const id = try tile_attrs.getNumber(u32, "id") orelse return error.MissingId;
|
const id = try tile_attrs.getNumber(u32, "id") orelse return error.MissingId;
|
||||||
|
const properties = try Property.List.initFromXmlContainer(arena, doc, element_id);
|
||||||
var properties: Property.List = .empty;
|
|
||||||
|
|
||||||
var iter = doc.iterChildren(element_id);
|
|
||||||
while (iter.next()) |child_id| {
|
|
||||||
const child = doc.getTag(child_id) orelse continue;
|
|
||||||
const child_name = child.variant.tag.name;
|
|
||||||
|
|
||||||
if (std.mem.eql(u8, child_name, "properties")) {
|
|
||||||
properties = try Property.List.initFromXml(arena, doc, child_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Tile{
|
return Tile{
|
||||||
.id = id,
|
.id = id,
|
||||||
|
|||||||
256
src/app.zig
256
src/app.zig
@ -71,6 +71,17 @@ const Tilemap = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clone(self: Tilemap, gpa: Allocator) !Tilemap {
|
||||||
|
const tiles = try gpa.dupe(Tile, self.tiles);
|
||||||
|
errdefer gpa.free(tiles);
|
||||||
|
|
||||||
|
return Tilemap{
|
||||||
|
.tiles = tiles,
|
||||||
|
.width = self.width,
|
||||||
|
.height = self.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Tilemap, gpa: Allocator) void {
|
pub fn deinit(self: *Tilemap, gpa: Allocator) void {
|
||||||
gpa.free(self.tiles);
|
gpa.free(self.tiles);
|
||||||
}
|
}
|
||||||
@ -114,6 +125,22 @@ const World = struct {
|
|||||||
tilemap: Tilemap,
|
tilemap: Tilemap,
|
||||||
entities: Entity.SlotMap,
|
entities: Entity.SlotMap,
|
||||||
|
|
||||||
|
pub fn clone(self: World, gpa: Allocator) !World {
|
||||||
|
var tilemap = try self.tilemap.clone(gpa);
|
||||||
|
errdefer tilemap.deinit(gpa);
|
||||||
|
|
||||||
|
var entity_slots = try self.entities.slots.clone(gpa);
|
||||||
|
errdefer entity_slots.deinit(gpa);
|
||||||
|
|
||||||
|
var entities = self.entities;
|
||||||
|
entities.slots = entity_slots;
|
||||||
|
|
||||||
|
return World{
|
||||||
|
.tilemap = tilemap,
|
||||||
|
.entities = entities
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn spawnEntity(self: *World, opts: Entity) Entity.Id {
|
fn spawnEntity(self: *World, opts: Entity) Entity.Id {
|
||||||
var e = opts;
|
var e = opts;
|
||||||
e.pos_x = -1;
|
e.pos_x = -1;
|
||||||
@ -186,7 +213,13 @@ const World = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Level = struct {
|
||||||
|
number: i32,
|
||||||
|
world: World,
|
||||||
|
};
|
||||||
|
|
||||||
world: World,
|
world: World,
|
||||||
|
levels: std.ArrayList(Level),
|
||||||
|
|
||||||
roboto_font: Font,
|
roboto_font: Font,
|
||||||
tilesheet: Tilesheet,
|
tilesheet: Tilesheet,
|
||||||
@ -263,99 +296,166 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
.tilesheet = tilesheet,
|
.tilesheet = tilesheet,
|
||||||
.footstep_buffer = footstep_sound,
|
.footstep_buffer = footstep_sound,
|
||||||
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
||||||
.world = .{
|
.world = undefined,
|
||||||
.tilemap = undefined,
|
.levels = .empty,
|
||||||
.entities = try .initCapacity(plt.gpa, 256)
|
};
|
||||||
|
|
||||||
|
self.levels = try self.loadLevels(plt.gpa, plt.assets);
|
||||||
|
self.world = try self.levels.items[0].world.clone(plt.gpa);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadLevels(self: *App, gpa: Allocator, assets: *Platform.Assets) !std.ArrayList(Level) {
|
||||||
|
var xml_parser = try Tiled.xml.Parser.initCapacity(gpa, .{});
|
||||||
|
defer xml_parser.deinit(gpa);
|
||||||
|
|
||||||
|
const tilemap = try Tiled.Tilemap.initFromXml(
|
||||||
|
gpa,
|
||||||
|
try xml_parser.parse(assets.readFile("tiled/map.tmx")),
|
||||||
|
.root
|
||||||
|
);
|
||||||
|
defer tilemap.deinit();
|
||||||
|
|
||||||
|
var tilesets: Tiled.Tileset.List = .empty;
|
||||||
|
defer tilesets.deinit(gpa);
|
||||||
|
|
||||||
|
try tilesets.add(gpa, "tileset.tsx", try Tiled.Tileset.initFromXml(
|
||||||
|
gpa,
|
||||||
|
try xml_parser.parse(assets.readFile("tiled/tileset.tsx")),
|
||||||
|
.root
|
||||||
|
));
|
||||||
|
|
||||||
|
var levels: std.ArrayList(Level) = .empty;
|
||||||
|
|
||||||
|
const level_bounds = tilemap.getLayer("Level bounds").?;
|
||||||
|
for (level_bounds.variant.object.items) |obj| {
|
||||||
|
if (obj.shape != .rectangle) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const level_index = obj.properties.getInt("level") orelse {
|
||||||
|
log.warn("Level bounds doesn't have index", .{});
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
var rect = obj.shape.rectangle;
|
||||||
|
rect.x /= @floatFromInt(tilemap.tile_width);
|
||||||
|
rect.y /= @floatFromInt(tilemap.tile_height);
|
||||||
|
rect.width /= @floatFromInt(tilemap.tile_width);
|
||||||
|
rect.height /= @floatFromInt(tilemap.tile_height);
|
||||||
|
|
||||||
|
var level_bound = Tiled.Tilemap.Bounds{
|
||||||
|
.min_x = @intFromFloat(@floor(rect.x)),
|
||||||
|
.min_y = @intFromFloat(@floor(rect.y)),
|
||||||
|
.max_x = @intFromFloat(@ceil(rect.x + rect.width)),
|
||||||
|
.max_y = @intFromFloat(@ceil(rect.y + rect.height)),
|
||||||
|
};
|
||||||
|
level_bound = tilemap.trimBoundsByEmptyTiles(level_bound);
|
||||||
|
|
||||||
|
var level = try self.loadLevel(gpa, tilemap, tilesets, level_bound);
|
||||||
|
level.number = level_index;
|
||||||
|
try levels.append(gpa, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Context = struct {
|
||||||
|
fn lessThan(_: @This(), lhs: Level, rhs: Level) bool {
|
||||||
|
return lhs.number < rhs.number;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
std.mem.sort(Level, levels.items, Context{}, Context.lessThan);
|
||||||
var xml_parser = try Tiled.xml.Parser.initCapacity(plt.gpa, .{});
|
|
||||||
defer xml_parser.deinit(plt.gpa);
|
|
||||||
|
|
||||||
const tilemap = try Tiled.Tilemap.initFromXml(
|
|
||||||
plt.gpa,
|
|
||||||
try xml_parser.parse(plt.assets.readFile("tiled/map.tmx")),
|
|
||||||
.root
|
|
||||||
);
|
|
||||||
defer tilemap.deinit();
|
|
||||||
|
|
||||||
var tilesets: Tiled.Tileset.List = .empty;
|
return levels;
|
||||||
defer tilesets.deinit(plt.gpa);
|
}
|
||||||
|
|
||||||
try tilesets.add(plt.gpa, "tileset.tsx", try Tiled.Tileset.initFromXml(
|
pub fn loadLevel(
|
||||||
plt.gpa,
|
self: *App,
|
||||||
try xml_parser.parse(plt.assets.readFile("tiled/tileset.tsx")),
|
gpa: Allocator,
|
||||||
.root
|
tilemap: Tiled.Tilemap,
|
||||||
));
|
tilesets: Tiled.Tileset.List,
|
||||||
|
bounds: Tiled.Tilemap.Bounds
|
||||||
|
) !Level {
|
||||||
|
var level = Level{
|
||||||
|
.number = 0,
|
||||||
|
.world = .{
|
||||||
|
.tilemap = try .init(gpa, bounds.width(), bounds.height()),
|
||||||
|
.entities = try .initCapacity(gpa, 256)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const bounds = tilemap.getTileBounds();
|
const ground = tilemap.getLayer("Ground").?;
|
||||||
|
const foreground = tilemap.getLayer("Foreground").?;
|
||||||
|
for (0..bounds.height()) |oy| {
|
||||||
|
for (0..bounds.width()) |ox| {
|
||||||
|
const x = bounds.min_x + @as(i32, @intCast(ox));
|
||||||
|
const y = bounds.min_y + @as(i32, @intCast(oy));
|
||||||
|
|
||||||
self.world.tilemap = try Tilemap.init(plt.gpa, bounds.width(), bounds.height());
|
const tile = level.world.tilemap.get(ox, oy);
|
||||||
|
|
||||||
const ground = tilemap.getLayer("Ground").?;
|
if (tilemap.getTile(ground, tilesets, x, y)) |tiled_tile| {
|
||||||
const foreground = tilemap.getLayer("Foreground").?;
|
const pos = tiled_tile.getPosition();
|
||||||
for (0..bounds.height()) |oy| {
|
tile.ground_sprite = self.tilesheet.get(pos.x, pos.y);
|
||||||
for (0..bounds.width()) |ox| {
|
}
|
||||||
const x = bounds.min_x + @as(i32, @intCast(ox));
|
|
||||||
const y = bounds.min_y + @as(i32, @intCast(oy));
|
|
||||||
|
|
||||||
const tile = self.world.tilemap.get(ox, oy);
|
if (tilemap.getTile(foreground, tilesets, x, y)) |tiled_tile| {
|
||||||
|
const pos = tiled_tile.getPosition();
|
||||||
|
const props = tiled_tile.getProperties();
|
||||||
|
const props_type = props.getString("type") orelse "";
|
||||||
|
|
||||||
if (tilemap.getTile(ground, tilesets, x, y)) |tiled_tile| {
|
var entity_type: ?Entity.Type = null;
|
||||||
const pos = tiled_tile.getPosition();
|
var layer: Entity.Layer = .surface;
|
||||||
tile.ground_sprite = tilesheet.get(pos.x, pos.y);
|
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 (tilemap.getTile(foreground, tilesets, x, y)) |tiled_tile| {
|
if (entity_type != null) {
|
||||||
const pos = tiled_tile.getPosition();
|
_ = level.world.spawnEntity(Entity{
|
||||||
const props = tiled_tile.getProperties();
|
.type = entity_type.?,
|
||||||
const props_type = props.getString("type") orelse "";
|
.layer = layer,
|
||||||
|
.pos_x = @intCast(ox),
|
||||||
var entity_type: ?Entity.Type = null;
|
.pos_y = @intCast(oy),
|
||||||
var layer: Entity.Layer = .surface;
|
.sprite = self.tilesheet.get(pos.x, pos.y)
|
||||||
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);
|
|
||||||
|
|
||||||
_ = self.world.spawnEntity(Entity{
|
|
||||||
.type = .player,
|
|
||||||
.layer = .surface,
|
|
||||||
.pos_x = @intFromFloat(player_pos.x),
|
|
||||||
.pos_y = @intFromFloat(player_pos.y)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
for (tilemap.getLayer("Markers").?.variant.object.items) |obj| {
|
||||||
|
if (obj.shape != .point) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!std.mem.eql(u8, obj.name, "spawn")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = obj.shape.point;
|
||||||
|
position.x /= @floatFromInt(tilemap.tile_width);
|
||||||
|
position.y /= @floatFromInt(tilemap.tile_height);
|
||||||
|
|
||||||
|
const pos_x: i32 = @intFromFloat(position.x);
|
||||||
|
const pos_y: i32 = @intFromFloat(position.y);
|
||||||
|
|
||||||
|
if (bounds.isInside(pos_x, pos_y)) {
|
||||||
|
_ = level.world.spawnEntity(Entity{
|
||||||
|
.type = .player,
|
||||||
|
.layer = .surface,
|
||||||
|
.pos_x = pos_x - bounds.min_x,
|
||||||
|
.pos_y = pos_y - bounds.min_y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||||
@ -478,4 +578,10 @@ pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
|||||||
|
|
||||||
self.world.tilemap.deinit(plt.gpa);
|
self.world.tilemap.deinit(plt.gpa);
|
||||||
self.world.entities.slots.deinit(plt.gpa);
|
self.world.entities.slots.deinit(plt.gpa);
|
||||||
|
|
||||||
|
for (self.levels.items) |*level| {
|
||||||
|
level.world.entities.deinit(plt.gpa);
|
||||||
|
level.world.tilemap.deinit(plt.gpa);
|
||||||
|
}
|
||||||
|
self.levels.deinit(plt.gpa);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user