add tilemap rendering
22
README.md
@ -1,4 +1,12 @@
|
|||||||
# Game template
|
# Gaem
|
||||||
|
|
||||||
|
* Run & gun
|
||||||
|
* Nuclear throne -esque
|
||||||
|
* Single gun type
|
||||||
|
* Single map
|
||||||
|
* Single enemy type
|
||||||
|
* Collect letters to win, up to 7 letters we have 8 character sprites
|
||||||
|
* The word is WINNER
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
@ -16,15 +24,3 @@ Cross-compile for Windows from Linux:
|
|||||||
```sh
|
```sh
|
||||||
zig build -Dtarget=x86_64-windows
|
zig build -Dtarget=x86_64-windows
|
||||||
```
|
```
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
* Use [Skribidi](https://github.com/memononen/Skribidi) instead of fontstash for text rendering
|
|
||||||
* Support for audio formats (Might not need all of them, haven't decided):
|
|
||||||
* QOA, maybe [qoa.h](https://github.com/phoboslab/qoa/blob/master/qoa.h)?
|
|
||||||
* Flac, maybe [dr_flac.h](https://github.com/mackron/dr_libs/blob/master/dr_flac.h)?
|
|
||||||
* Wav, maybe [dr_wav.h](https://github.com/mackron/dr_libs/blob/master/dr_wav.h)?
|
|
||||||
* Mp3, maybe [dr_mp3.h](https://github.com/mackron/dr_libs/blob/master/dr_mp3.h)?
|
|
||||||
* Gamepad support.
|
|
||||||
* WASM Support. Currently a build config isn't provided for this target.
|
|
||||||
* Update build config for other platforms to reduce binary size. All of the video and audio drivers aren't needed, only gamepads
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@ const std = @import("std");
|
|||||||
const sokol = @import("sokol");
|
const sokol = @import("sokol");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
const project_name = "game-2026-01-18";
|
||||||
|
|
||||||
pub fn build(b: *std.Build) !void {
|
pub fn build(b: *std.Build) !void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
@ -105,12 +107,12 @@ pub fn build(b: *std.Build) !void {
|
|||||||
// from here on different handling for native vs wasm builds
|
// from here on different handling for native vs wasm builds
|
||||||
if (target.result.cpu.arch.isWasm()) {
|
if (target.result.cpu.arch.isWasm()) {
|
||||||
try buildWasm(b, .{
|
try buildWasm(b, .{
|
||||||
.name = "sokol_template",
|
.name = project_name,
|
||||||
.mod_main = mod_main,
|
.mod_main = mod_main,
|
||||||
.dep_sokol = dep_sokol,
|
.dep_sokol = dep_sokol,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
try buildNative(b, "sokol_template", mod_main, has_console);
|
try buildNative(b, project_name, mod_main, has_console);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ pub const TileVariant = struct {
|
|||||||
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
||||||
|
|
||||||
} else if (node.isTag("chunk")) {
|
} else if (node.isTag("chunk")) {
|
||||||
const chunk = try initChunkDataFromXml(scratch.allocator(), scratch, lexer, encoding);
|
const chunk = try initChunkDataFromXml(arena, scratch, lexer, encoding);
|
||||||
try temp_chunks.append(scratch.allocator(), chunk);
|
try temp_chunks.append(scratch.allocator(), chunk);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -105,9 +105,16 @@ pub const TileVariant = struct {
|
|||||||
|
|
||||||
try iter.finish("data");
|
try iter.finish("data");
|
||||||
|
|
||||||
return .{
|
if (temp_chunks.items.len > 0) {
|
||||||
.fixed = try arena.dupe(u32, temp_tiles.items)
|
return .{
|
||||||
};
|
.chunks = try arena.dupe(Chunk, temp_chunks.items)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return .{
|
||||||
|
.fixed = try arena.dupe(u32, temp_tiles.items)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseEncoding(
|
fn parseEncoding(
|
||||||
@ -136,13 +143,76 @@ pub const TileVariant = struct {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBounds(self: TileVariant) void {
|
const Bounds = struct {
|
||||||
_ = self; // autofix
|
left: i32,
|
||||||
|
right: i32,
|
||||||
|
top: i32,
|
||||||
|
bottom: i32,
|
||||||
|
|
||||||
|
pub fn width(self: Bounds) u32 {
|
||||||
|
return @intCast(self.right - self.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(self: Bounds) u32 {
|
||||||
|
return @intCast(self.bottom - self.top);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn getBounds(self: TileVariant) Bounds {
|
||||||
|
if (self.data == .fixed) {
|
||||||
|
return Bounds{
|
||||||
|
.left = 0,
|
||||||
|
.right = @intCast(self.width),
|
||||||
|
.top = 0,
|
||||||
|
.bottom = @intCast(self.height),
|
||||||
|
};
|
||||||
|
} else if (self.data == .chunks) {
|
||||||
|
const chunks = self.data.chunks;
|
||||||
|
|
||||||
|
var result = Bounds{
|
||||||
|
.left = 0,
|
||||||
|
.right = 0,
|
||||||
|
.top = 0,
|
||||||
|
.bottom = 0
|
||||||
|
};
|
||||||
|
if (chunks.len > 0) {
|
||||||
|
result.left = chunks[0].x;
|
||||||
|
result.right = chunks[0].x + @as(i32, @intCast(chunks[0].width));
|
||||||
|
result.top = chunks[0].y;
|
||||||
|
result.bottom = chunks[0].y + @as(i32, @intCast(chunks[0].height));
|
||||||
|
for (chunks[1..]) |chunk| {
|
||||||
|
result.left = @min(result.left, chunk.x);
|
||||||
|
result.right = @max(result.right, chunk.x + @as(i32, @intCast(chunk.width)));
|
||||||
|
result.top = @min(result.top, chunk.y);
|
||||||
|
result.bottom = @max(result.bottom, chunk.y + @as(i32, @intCast(chunk.height)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: TileVariant, x: usize, y: usize) ?u32 {
|
pub fn get(self: TileVariant, x: i32, y: i32) ?u32 {
|
||||||
if ((0 <= x and x < self.width) and (0 <= y and y < self.height)) {
|
if (self.data == .fixed) {
|
||||||
return self.data[y * self.width + x];
|
if ((0 <= x and x < self.width) and (0 <= y and y < self.height)) {
|
||||||
|
const x_u32: u32 = @intCast(x);
|
||||||
|
const y_u32: u32 = @intCast(y);
|
||||||
|
return self.data.fixed[y_u32 * self.width + x_u32];
|
||||||
|
}
|
||||||
|
} else if (self.data == .chunks) {
|
||||||
|
for (self.data.chunks) |chunk| {
|
||||||
|
const ox = x - chunk.x;
|
||||||
|
const oy = y - chunk.y;
|
||||||
|
if ((0 <= ox and ox < chunk.width) and (0 <= oy and oy < chunk.height)) {
|
||||||
|
const ox_u32: u32 = @intCast(ox);
|
||||||
|
const oy_u32: u32 = @intCast(oy);
|
||||||
|
return chunk.data[oy_u32 * chunk.width + ox_u32];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -215,7 +215,18 @@ fn getTilesetByGid(self: *const Tilemap, gid: u32) ?TilesetReference {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTile(self: *const Tilemap, layer: *const Layer, tilesets: Tileset.List, x: usize, y: usize) ?Tile {
|
pub fn getTile(self: *const Tilemap, tilesets: Tileset.List, gid: u32) ?Tile {
|
||||||
|
const tileset_ref = self.getTilesetByGid(gid & GlobalTileId.Flag.clear) orelse return null;
|
||||||
|
const tileset = tilesets.get(tileset_ref.source) orelse return null;
|
||||||
|
const id = gid - tileset_ref.first_gid;
|
||||||
|
|
||||||
|
return Tile{
|
||||||
|
.tileset = tileset,
|
||||||
|
.id = id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTileByPosition(self: *const Tilemap, layer: *const Layer, tilesets: Tileset.List, x: usize, y: usize) ?Tile {
|
||||||
assert(layer.variant == .tile);
|
assert(layer.variant == .tile);
|
||||||
const tile_variant = layer.variant.tile;
|
const tile_variant = layer.variant.tile;
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ 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 STBImage = @import("stb_image");
|
||||||
const Gfx = Engine.Graphics;
|
const Gfx = Engine.Graphics;
|
||||||
const Audio = Engine.Audio;
|
const Audio = Engine.Audio;
|
||||||
|
|
||||||
@ -21,6 +22,8 @@ font_id: FontName.EnumArray,
|
|||||||
wood01: Audio.Data.Id,
|
wood01: Audio.Data.Id,
|
||||||
map: tiled.Tilemap,
|
map: tiled.Tilemap,
|
||||||
tilesets: tiled.Tileset.List,
|
tilesets: tiled.Tileset.List,
|
||||||
|
tileset_texture: Gfx.TextureId,
|
||||||
|
tile_size: Engine.Vec2,
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) !Assets {
|
pub fn init(gpa: std.mem.Allocator) !Assets {
|
||||||
const font_id_array: FontName.EnumArray = .init(.{
|
const font_id_array: FontName.EnumArray = .init(.{
|
||||||
@ -57,11 +60,24 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
|||||||
var tilesets: tiled.Tileset.List = .empty;
|
var tilesets: tiled.Tileset.List = .empty;
|
||||||
try tilesets.add(gpa, "tileset.tsx", tileset);
|
try tilesets.add(gpa, "tileset.tsx", tileset);
|
||||||
|
|
||||||
|
|
||||||
|
const tileset_image = try STBImage.load(@embedFile("assets/kenney_desert-shooter-pack_1.0/PNG/Tiles/tilemap_packed.png"));
|
||||||
|
defer tileset_image.deinit();
|
||||||
|
const tileset_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = tileset_image.width,
|
||||||
|
.height = tileset_image.height,
|
||||||
|
.rgba = tileset_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return Assets{
|
return Assets{
|
||||||
.font_id = font_id_array,
|
.font_id = font_id_array,
|
||||||
.wood01 = wood01,
|
.wood01 = wood01,
|
||||||
.map = map,
|
.map = map,
|
||||||
.tilesets = tilesets
|
.tilesets = tilesets,
|
||||||
|
.tileset_texture = tileset_texture,
|
||||||
|
.tile_size = .init(16, 16)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
"scaleInEditor": 1
|
"scaleInEditor": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"last.imagePath": "/home/rokas/code/games/game-2026-01-18/src/assets/kenney_desert-shooter-pack_1.0/PNG/Tiles/Tilemap",
|
"last.imagePath": "/home/rokas/code/games/game-2026-01-18/src/assets/kenney_desert-shooter-pack_1.0/PNG/Tiles",
|
||||||
"map.fixedSize": false,
|
"map.fixedSize": false,
|
||||||
"map.lastUsedFormat": "tmx",
|
"map.lastUsedFormat": "tmx",
|
||||||
"map.tileHeight": 16,
|
"map.tileHeight": 16,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 159 B |
|
Before Width: | Height: | Size: 139 B |
|
Before Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 139 B |
|
Before Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 183 B |
|
Before Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 163 B |
|
Before Width: | Height: | Size: 113 B |
|
Before Width: | Height: | Size: 111 B |
|
Before Width: | Height: | Size: 152 B |
|
Before Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 127 B |
|
Before Width: | Height: | Size: 133 B |
|
Before Width: | Height: | Size: 136 B |
|
Before Width: | Height: | Size: 136 B |
|
Before Width: | Height: | Size: 132 B |
|
Before Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 118 B |
|
Before Width: | Height: | Size: 121 B |
|
Before Width: | Height: | Size: 136 B |
|
Before Width: | Height: | Size: 132 B |
|
Before Width: | Height: | Size: 110 B |
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 110 B |
|
Before Width: | Height: | Size: 116 B |
|
Before Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 110 B |
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 110 B |
|
Before Width: | Height: | Size: 207 B |
|
Before Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 209 B |
|
Before Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 127 B |
|
Before Width: | Height: | Size: 207 B |
|
Before Width: | Height: | Size: 143 B |
|
Before Width: | Height: | Size: 202 B |
|
Before Width: | Height: | Size: 186 B |
|
Before Width: | Height: | Size: 127 B |
|
Before Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 195 B |
|
Before Width: | Height: | Size: 194 B |
|
Before Width: | Height: | Size: 187 B |
|
Before Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 150 B |
|
Before Width: | Height: | Size: 150 B |
|
Before Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 157 B |
|
Before Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 195 B |
|
Before Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 168 B |
|
Before Width: | Height: | Size: 168 B |
|
Before Width: | Height: | Size: 182 B |
|
Before Width: | Height: | Size: 190 B |
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 131 B |
|
Before Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 139 B |
|
Before Width: | Height: | Size: 187 B |
|
Before Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 156 B |
|
Before Width: | Height: | Size: 126 B |
|
Before Width: | Height: | Size: 158 B |
|
Before Width: | Height: | Size: 207 B |
|
Before Width: | Height: | Size: 204 B |
|
Before Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 163 B |
|
Before Width: | Height: | Size: 158 B |
|
Before Width: | Height: | Size: 217 B |
|
Before Width: | Height: | Size: 177 B |
|
Before Width: | Height: | Size: 166 B |
|
Before Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 204 B |
|
Before Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 114 B |
|
Before Width: | Height: | Size: 136 B |
|
Before Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 145 B |