partial progress on chunked tilemap
@ -9,38 +9,135 @@ const Position = @import("./position.zig");
|
|||||||
const Layer = @This();
|
const Layer = @This();
|
||||||
|
|
||||||
pub const TileVariant = struct {
|
pub const TileVariant = struct {
|
||||||
|
pub const Chunk = struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
data: []u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Data = union(enum) {
|
||||||
|
fixed: []u32,
|
||||||
|
chunks: []Chunk
|
||||||
|
};
|
||||||
|
|
||||||
|
const Encoding = enum {
|
||||||
|
csv,
|
||||||
|
|
||||||
|
const map: std.StaticStringMap(Encoding) = .initComptime(.{
|
||||||
|
.{ "csv", .csv },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
data: []u32,
|
data: Data,
|
||||||
|
|
||||||
|
fn initChunkDataFromXml(
|
||||||
|
arena: std.mem.Allocator,
|
||||||
|
scratch: *std.heap.ArenaAllocator,
|
||||||
|
lexer: *xml.Lexer,
|
||||||
|
encoding: Encoding
|
||||||
|
) !Chunk {
|
||||||
|
var iter = xml.TagParser.init(lexer);
|
||||||
|
const attrs = try iter.begin("chunk");
|
||||||
|
|
||||||
|
const x = try attrs.getNumber(i32, "x") orelse return error.MissingAttribute;
|
||||||
|
const y = try attrs.getNumber(i32, "y") orelse return error.MissingAttribute;
|
||||||
|
const width = try attrs.getNumber(u32, "width") orelse return error.MissingAttribute;
|
||||||
|
const height = try attrs.getNumber(u32, "height") orelse return error.MissingAttribute;
|
||||||
|
|
||||||
|
var temp_tiles: std.ArrayList(u32) = .empty;
|
||||||
|
|
||||||
|
while (try iter.next()) |node| {
|
||||||
|
if (node == .text) {
|
||||||
|
const encoded_tiles = try lexer.nextExpectText();
|
||||||
|
const tiles = try parseEncoding(encoding, scratch.allocator(), encoded_tiles);
|
||||||
|
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try iter.skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
try iter.finish("chunk");
|
||||||
|
|
||||||
|
return Chunk{
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.data = try arena.dupe(u32, temp_tiles.items)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn initDataFromXml(
|
fn initDataFromXml(
|
||||||
arena: std.mem.Allocator,
|
arena: std.mem.Allocator,
|
||||||
scratch: *std.heap.ArenaAllocator,
|
scratch: *std.heap.ArenaAllocator,
|
||||||
lexer: *xml.Lexer,
|
lexer: *xml.Lexer,
|
||||||
) ![]u32 {
|
) !Data {
|
||||||
var iter = xml.TagParser.init(lexer);
|
var iter = xml.TagParser.init(lexer);
|
||||||
const attrs = try iter.begin("data");
|
const attrs = try iter.begin("data");
|
||||||
|
|
||||||
const encoding = attrs.get("encoding") orelse "csv";
|
const encoding = try attrs.getEnum(Encoding, "encoding", Encoding.map) orelse .csv;
|
||||||
// TODO: compression
|
// TODO: compression
|
||||||
|
|
||||||
|
var temp_chunks: std.ArrayList(Chunk) = .empty;
|
||||||
var temp_tiles: std.ArrayList(u32) = .empty;
|
var temp_tiles: std.ArrayList(u32) = .empty;
|
||||||
|
|
||||||
if (std.mem.eql(u8, encoding, "csv")) {
|
while (try iter.next()) |node| {
|
||||||
const text = try lexer.nextExpectText();
|
if (node == .text) {
|
||||||
var split_iter = std.mem.splitScalar(u8, text, ',');
|
const encoded_tiles = try lexer.nextExpectText();
|
||||||
while (split_iter.next()) |raw_tile_id| {
|
const tiles = try parseEncoding(encoding, scratch.allocator(), encoded_tiles);
|
||||||
const tile_id_str = std.mem.trim(u8, raw_tile_id, &std.ascii.whitespace);
|
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
||||||
const tile_id = try std.fmt.parseInt(u32, tile_id_str, 10);
|
|
||||||
try temp_tiles.append(scratch.allocator(), tile_id);
|
} else if (node.isTag("chunk")) {
|
||||||
|
const chunk = try initChunkDataFromXml(scratch.allocator(), scratch, lexer, encoding);
|
||||||
|
try temp_chunks.append(scratch.allocator(), chunk);
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return error.UnknownEncodingType;
|
try iter.skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
try iter.finish("data");
|
try iter.finish("data");
|
||||||
|
|
||||||
return try arena.dupe(u32, temp_tiles.items);
|
return .{
|
||||||
|
.fixed = try arena.dupe(u32, temp_tiles.items)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseEncoding(
|
||||||
|
encoding: Encoding,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
text: []const u8
|
||||||
|
) !std.ArrayList(u32) {
|
||||||
|
return switch (encoding) {
|
||||||
|
.csv => try parseCSVEncoding(allocator, text)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseCSVEncoding(
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
text: []const u8
|
||||||
|
) !std.ArrayList(u32) {
|
||||||
|
var result: std.ArrayList(u32) = .empty;
|
||||||
|
|
||||||
|
var split_iter = std.mem.splitScalar(u8, text, ',');
|
||||||
|
while (split_iter.next()) |raw_tile_id| {
|
||||||
|
const tile_id_str = std.mem.trim(u8, raw_tile_id, &std.ascii.whitespace);
|
||||||
|
const tile_id = try std.fmt.parseInt(u32, tile_id_str, 10);
|
||||||
|
try result.append(allocator, tile_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getBounds(self: TileVariant) void {
|
||||||
|
_ = self; // autofix
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: TileVariant, x: usize, y: usize) ?u32 {
|
pub fn get(self: TileVariant, x: usize, y: usize) ?u32 {
|
||||||
@ -181,7 +278,7 @@ pub fn initFromXml(
|
|||||||
.tile = TileVariant{
|
.tile = TileVariant{
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
.data = &[0]u32{}
|
.data = .{ .fixed = &[0]u32{} }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const tiled = @import("tiled");
|
||||||
|
|
||||||
const Math = @import("./engine/math.zig");
|
const Math = @import("./engine/math.zig");
|
||||||
const Engine = @import("./engine/root.zig");
|
const Engine = @import("./engine/root.zig");
|
||||||
const Gfx = Engine.Graphics;
|
const Gfx = Engine.Graphics;
|
||||||
@ -16,11 +18,11 @@ const FontName = enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
font_id: FontName.EnumArray,
|
font_id: FontName.EnumArray,
|
||||||
|
|
||||||
wood01: Audio.Data.Id,
|
wood01: Audio.Data.Id,
|
||||||
|
map: tiled.Tilemap,
|
||||||
|
tilesets: tiled.Tileset.List,
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) !Assets {
|
pub fn init(gpa: std.mem.Allocator) !Assets {
|
||||||
_ = gpa; // autofix
|
|
||||||
const font_id_array: FontName.EnumArray = .init(.{
|
const font_id_array: FontName.EnumArray = .init(.{
|
||||||
.regular = try Gfx.addFont("regular", @embedFile("assets/roboto-font/Roboto-Regular.ttf")),
|
.regular = try Gfx.addFont("regular", @embedFile("assets/roboto-font/Roboto-Regular.ttf")),
|
||||||
.bold = try Gfx.addFont("bold", @embedFile("assets/roboto-font/Roboto-Bold.ttf")),
|
.bold = try Gfx.addFont("bold", @embedFile("assets/roboto-font/Roboto-Bold.ttf")),
|
||||||
@ -32,13 +34,38 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
|||||||
.data = @embedFile("assets/wood01.ogg"),
|
.data = @embedFile("assets/wood01.ogg"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var scratch = std.heap.ArenaAllocator.init(gpa);
|
||||||
|
defer scratch.deinit();
|
||||||
|
|
||||||
|
var xml_buffers = tiled.xml.Lexer.Buffers.init(gpa);
|
||||||
|
defer xml_buffers.deinit();
|
||||||
|
|
||||||
|
const map = try tiled.Tilemap.initFromBuffer(
|
||||||
|
gpa,
|
||||||
|
&scratch,
|
||||||
|
&xml_buffers,
|
||||||
|
@embedFile("assets/map.tmx")
|
||||||
|
);
|
||||||
|
|
||||||
|
const tileset = try tiled.Tileset.initFromBuffer(
|
||||||
|
gpa,
|
||||||
|
&scratch,
|
||||||
|
&xml_buffers,
|
||||||
|
@embedFile("assets/tileset.tsx")
|
||||||
|
);
|
||||||
|
|
||||||
|
var tilesets: tiled.Tileset.List = .empty;
|
||||||
|
try tilesets.add(gpa, "tileset.tsx", tileset);
|
||||||
|
|
||||||
return Assets{
|
return Assets{
|
||||||
.font_id = font_id_array,
|
.font_id = font_id_array,
|
||||||
.wood01 = wood01
|
.wood01 = wood01,
|
||||||
|
.map = map,
|
||||||
|
.tilesets = tilesets
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Assets, gpa: std.mem.Allocator) void {
|
pub fn deinit(self: *Assets, gpa: std.mem.Allocator) void {
|
||||||
_ = self; // autofix
|
self.map.deinit();
|
||||||
_ = gpa; // autofix
|
self.tilesets.deinit(gpa);
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/assets/game-2026-01-18.tiled-project
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"automappingRulesFile": "",
|
||||||
|
"commands": [
|
||||||
|
],
|
||||||
|
"compatibilityVersion": 1100,
|
||||||
|
"extensionsPath": "extensions",
|
||||||
|
"folders": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
],
|
||||||
|
"propertyTypes": [
|
||||||
|
]
|
||||||
|
}
|
||||||
50
src/assets/game-2026-01-18.tiled-session
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"Map/SizeTest": {
|
||||||
|
"height": 4300,
|
||||||
|
"width": 2
|
||||||
|
},
|
||||||
|
"activeFile": "map.tmx",
|
||||||
|
"expandedProjectPaths": [
|
||||||
|
],
|
||||||
|
"fileStates": {
|
||||||
|
"map.tmx": {
|
||||||
|
"scale": 1.5,
|
||||||
|
"selectedLayer": 0,
|
||||||
|
"viewCenter": {
|
||||||
|
"x": 49.33333333333337,
|
||||||
|
"y": 182
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tilemap.tsx": {
|
||||||
|
"dynamicWrapping": false,
|
||||||
|
"scaleInDock": 1.5,
|
||||||
|
"scaleInEditor": 5.5
|
||||||
|
},
|
||||||
|
"tiles.tsx": {
|
||||||
|
"dynamicWrapping": true,
|
||||||
|
"scaleInDock": 1,
|
||||||
|
"scaleInEditor": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"last.imagePath": "/home/rokas/code/games/game-2026-01-18/src/assets/kenney_desert-shooter-pack_1.0/PNG/Tiles/Tilemap",
|
||||||
|
"map.fixedSize": false,
|
||||||
|
"map.lastUsedFormat": "tmx",
|
||||||
|
"map.tileHeight": 16,
|
||||||
|
"map.tileWidth": 16,
|
||||||
|
"openFiles": [
|
||||||
|
"tilemap.tsx",
|
||||||
|
"map.tmx"
|
||||||
|
],
|
||||||
|
"project": "game-2026-01-18.tiled-project",
|
||||||
|
"recentFiles": [
|
||||||
|
"tilemap.tsx",
|
||||||
|
"map.tmx",
|
||||||
|
"tiles.tsx"
|
||||||
|
],
|
||||||
|
"tileset.lastUsedFormat": "tsx",
|
||||||
|
"tileset.tileSize": {
|
||||||
|
"height": 16,
|
||||||
|
"width": 16
|
||||||
|
},
|
||||||
|
"tileset.type": 0
|
||||||
|
}
|
||||||
23
src/assets/kenney_desert-shooter-pack_1.0/License.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Desert Shooter Pack (1.0)
|
||||||
|
|
||||||
|
Created/distributed by Kenney (www.kenney.nl)
|
||||||
|
Sponsored by: GameMaker (www.gamemaker.io)
|
||||||
|
Creation date: 24-04-2024
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
License: (Creative Commons Zero, CC0)
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
This content is free to use in personal, educational and commercial projects.
|
||||||
|
Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Donate: http://support.kenney.nl
|
||||||
|
Patreon: http://patreon.com/kenney/
|
||||||
|
|
||||||
|
Follow on Twitter for updates:
|
||||||
|
http://twitter.com/KenneyNL
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 216 B |
|
After Width: | Height: | Size: 232 B |
|
After Width: | Height: | Size: 189 B |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 242 B |
|
After Width: | Height: | Size: 244 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 223 B |
|
After Width: | Height: | Size: 236 B |
|
After Width: | Height: | Size: 208 B |
|
After Width: | Height: | Size: 243 B |
|
After Width: | Height: | Size: 256 B |
|
After Width: | Height: | Size: 259 B |
|
After Width: | Height: | Size: 227 B |
@ -0,0 +1,9 @@
|
|||||||
|
Tilesheet information:
|
||||||
|
|
||||||
|
Tile size • 24px × 24px
|
||||||
|
Space between tiles • 1px × 1px
|
||||||
|
---
|
||||||
|
Total tiles (horizontal) • 4 tiles
|
||||||
|
Total tiles (vertical) • 4 tiles
|
||||||
|
---
|
||||||
|
Total tiles in sheet • 16 tiles
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 181 B |
|
After Width: | Height: | Size: 187 B |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 151 B |
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 145 B |
|
After Width: | Height: | Size: 120 B |
|
After Width: | Height: | Size: 148 B |
|
After Width: | Height: | Size: 182 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 181 B |
|
After Width: | Height: | Size: 176 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 176 B |
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 119 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 119 B |
|
After Width: | Height: | Size: 125 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 119 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 119 B |
|
After Width: | Height: | Size: 186 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 186 B |
|
After Width: | Height: | Size: 151 B |
|
After Width: | Height: | Size: 143 B |
|
After Width: | Height: | Size: 151 B |
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 122 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 143 B |
|
After Width: | Height: | Size: 129 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 187 B |
|
After Width: | Height: | Size: 122 B |
|
After Width: | Height: | Size: 185 B |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 174 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 114 B |
|
After Width: | Height: | Size: 110 B |
|
After Width: | Height: | Size: 115 B |
|
After Width: | Height: | Size: 149 B |
|
After Width: | Height: | Size: 157 B |