Compare commits
10 Commits
8d5e7da6a6
...
a5d824817c
| Author | SHA1 | Date | |
|---|---|---|---|
| a5d824817c | |||
| f96a8b4b78 | |||
| 0b3f4486c0 | |||
| a249dc3cf9 | |||
| a4d803fc57 | |||
| beeacdc701 | |||
| d2ecfcafe9 | |||
| 11be4f21ac | |||
| c9543c72ad | |||
| ba264d7bc5 |
22
build.zig
@ -13,6 +13,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const has_console = b.option(bool, "console", "Show console (Window only)") orelse (optimize == .Debug);
|
const has_console = b.option(bool, "console", "Show console (Window only)") orelse (optimize == .Debug);
|
||||||
|
|
||||||
const isWasm = target.result.cpu.arch.isWasm();
|
const isWasm = target.result.cpu.arch.isWasm();
|
||||||
|
const isWindows = target.result.os.tag == .windows;
|
||||||
|
|
||||||
if (isWasm) {
|
if (isWasm) {
|
||||||
has_tracy = false;
|
has_tracy = false;
|
||||||
@ -25,7 +26,12 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.link_libc = true,
|
.link_libc = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dep_sokol = b.dependency("sokol", .{ .target = target, .optimize = optimize, .with_sokol_imgui = has_imgui, .vulkan = true });
|
const dep_sokol = b.dependency("sokol", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.with_sokol_imgui = has_imgui,
|
||||||
|
.vulkan = if (isWasm or isWindows) null else true
|
||||||
|
});
|
||||||
mod_main.linkLibrary(dep_sokol.artifact("sokol_clib"));
|
mod_main.linkLibrary(dep_sokol.artifact("sokol_clib"));
|
||||||
mod_main.addImport("sokol", dep_sokol.module("sokol"));
|
mod_main.addImport("sokol", dep_sokol.module("sokol"));
|
||||||
|
|
||||||
@ -62,7 +68,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
{
|
{
|
||||||
var cflags_buffer: [64][]const u8 = undefined;
|
var cflags_buffer: [64][]const u8 = undefined;
|
||||||
var cflags = std.ArrayListUnmanaged([]const u8).initBuffer(&cflags_buffer);
|
var cflags = std.ArrayListUnmanaged([]const u8).initBuffer(&cflags_buffer);
|
||||||
switch (sokol.resolveSokolBackend(.vulkan, target.result)) {
|
const backend: sokol.SokolBackend = if (isWasm or isWindows) .auto else .vulkan;
|
||||||
|
switch (sokol.resolveSokolBackend(backend, target.result)) {
|
||||||
.d3d11 => try cflags.appendBounded("-DSOKOL_D3D11"),
|
.d3d11 => try cflags.appendBounded("-DSOKOL_D3D11"),
|
||||||
.metal => try cflags.appendBounded("-DSOKOL_METAL"),
|
.metal => try cflags.appendBounded("-DSOKOL_METAL"),
|
||||||
.gl => try cflags.appendBounded("-DSOKOL_GLCORE"),
|
.gl => try cflags.appendBounded("-DSOKOL_GLCORE"),
|
||||||
@ -118,8 +125,8 @@ fn buildNative(b: *std.Build, name: []const u8, mod: *std.Build.Module, has_cons
|
|||||||
.root_source_file = b.path("tools/png-to-icon.zig"),
|
.root_source_file = b.path("tools/png-to-icon.zig"),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const dep_stb_image = b.dependency("stb_image", .{});
|
const dep_stb = b.dependency("stb", .{});
|
||||||
png_to_icon_tool.root_module.addImport("stb_image", dep_stb_image.module("stb_image"));
|
png_to_icon_tool.root_module.addImport("stb_image", dep_stb.module("stb_image"));
|
||||||
|
|
||||||
const png_to_icon_step = b.addRunArtifact(png_to_icon_tool);
|
const png_to_icon_step = b.addRunArtifact(png_to_icon_tool);
|
||||||
png_to_icon_step.addFileArg(b.path("src/assets/icon.png"));
|
png_to_icon_step.addFileArg(b.path("src/assets/icon.png"));
|
||||||
@ -209,7 +216,11 @@ fn buildWasm(b: *std.Build, opts: BuildWasmOptions) !void {
|
|||||||
|
|
||||||
const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});
|
const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});
|
||||||
|
|
||||||
patchWasmIncludeDirs(opts.mod_main, dep_emsdk.path("upstream/emscripten/cache/sysroot/include"), &(opts.dep_sokol.artifact("sokol_clib").step));
|
patchWasmIncludeDirs(
|
||||||
|
opts.mod_main,
|
||||||
|
dep_emsdk.path("upstream/emscripten/cache/sysroot/include"),
|
||||||
|
&(opts.dep_sokol.artifact("sokol_clib").step)
|
||||||
|
);
|
||||||
|
|
||||||
// create a build step which invokes the Emscripten linker
|
// create a build step which invokes the Emscripten linker
|
||||||
const link_step = try sokol.emLinkStep(b, .{
|
const link_step = try sokol.emLinkStep(b, .{
|
||||||
@ -221,6 +232,7 @@ fn buildWasm(b: *std.Build, opts: BuildWasmOptions) !void {
|
|||||||
.use_emmalloc = true,
|
.use_emmalloc = true,
|
||||||
.use_filesystem = false,
|
.use_filesystem = false,
|
||||||
.shell_file_path = b.path("src/engine/shell.html"),
|
.shell_file_path = b.path("src/engine/shell.html"),
|
||||||
|
.extra_args = &.{ "-sASSERTIONS=1", "-sALLOW_MEMORY_GROWTH=1" }
|
||||||
});
|
});
|
||||||
// attach to default target
|
// attach to default target
|
||||||
b.getInstallStep().dependOn(&link_step.step);
|
b.getInstallStep().dependOn(&link_step.step);
|
||||||
|
|||||||
@ -136,6 +136,7 @@ pub const TileVariant = struct {
|
|||||||
const encoded_tiles = try lexer.nextExpectText();
|
const encoded_tiles = try lexer.nextExpectText();
|
||||||
const tiles = try parseEncoding(encoding, scratch.allocator(), encoded_tiles);
|
const tiles = try parseEncoding(encoding, scratch.allocator(), encoded_tiles);
|
||||||
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
||||||
|
continue;
|
||||||
|
|
||||||
} else if (node.isTag("chunk")) {
|
} else if (node.isTag("chunk")) {
|
||||||
const chunk = try initChunkDataFromXml(arena, scratch, lexer, encoding);
|
const chunk = try initChunkDataFromXml(arena, scratch, lexer, encoding);
|
||||||
@ -158,7 +159,6 @@ pub const TileVariant = struct {
|
|||||||
.fixed = try arena.dupe(u32, temp_tiles.items)
|
.fixed = try arena.dupe(u32, temp_tiles.items)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseEncoding(
|
fn parseEncoding(
|
||||||
|
|||||||
@ -73,6 +73,9 @@ pub const TilesetReference = struct {
|
|||||||
pub const Tile = struct {
|
pub const Tile = struct {
|
||||||
tileset: *const Tileset,
|
tileset: *const Tileset,
|
||||||
id: u32,
|
id: u32,
|
||||||
|
flip_horizontal: bool,
|
||||||
|
flip_vertical: bool,
|
||||||
|
flip_diagonal: bool,
|
||||||
|
|
||||||
pub fn getProperties(self: Tile) Property.List {
|
pub fn getProperties(self: Tile) Property.List {
|
||||||
return self.tileset.getTileProperties(self.id) orelse .empty;
|
return self.tileset.getTileProperties(self.id) orelse .empty;
|
||||||
@ -216,13 +219,19 @@ fn getTilesetByGid(self: *const Tilemap, gid: u32) ?TilesetReference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTile(self: *const Tilemap, tilesets: Tileset.List, gid: u32) ?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 Flag = GlobalTileId.Flag;
|
||||||
|
|
||||||
|
const gid_without_flags = gid & Flag.clear;
|
||||||
|
const tileset_ref = self.getTilesetByGid(gid_without_flags) orelse return null;
|
||||||
const tileset = tilesets.get(tileset_ref.source) orelse return null;
|
const tileset = tilesets.get(tileset_ref.source) orelse return null;
|
||||||
const id = gid - tileset_ref.first_gid;
|
const id = gid_without_flags - tileset_ref.first_gid;
|
||||||
|
|
||||||
return Tile{
|
return Tile{
|
||||||
.tileset = tileset,
|
.tileset = tileset,
|
||||||
.id = id
|
.id = id,
|
||||||
|
.flip_horizontal = (gid & @intFromEnum(Flag.flipped_horizontally)) > 0,
|
||||||
|
.flip_vertical = (gid & @intFromEnum(Flag.flipped_vertically)) > 0,
|
||||||
|
.flip_diagonal = (gid & @intFromEnum(Flag.flipped_diagonally)) > 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
177
src/assets.zig
@ -24,7 +24,6 @@ pub const Tilemap = struct {
|
|||||||
texture: Gfx.TextureId,
|
texture: Gfx.TextureId,
|
||||||
tile_size: Engine.Vec2,
|
tile_size: Engine.Vec2,
|
||||||
|
|
||||||
|
|
||||||
pub fn getTileUV(self: Tilemap, tile_x: f32, tile_y: f32) Rect {
|
pub fn getTileUV(self: Tilemap, tile_x: f32, tile_y: f32) Rect {
|
||||||
const texture_info = Engine.Graphics.getTextureInfo(self.texture);
|
const texture_info = Engine.Graphics.getTextureInfo(self.texture);
|
||||||
const tilemap_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
const tilemap_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
||||||
@ -39,14 +38,19 @@ pub const Tilemap = struct {
|
|||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
|
|
||||||
font_id: FontName.EnumArray,
|
font_id: FontName.EnumArray,
|
||||||
wood01: Audio.Data.Id,
|
pistol_mask: Gfx.TextureId,
|
||||||
|
bomb_mask: Gfx.TextureId,
|
||||||
|
laser_mask: Gfx.TextureId,
|
||||||
|
bullet: Gfx.TextureId,
|
||||||
|
shadow: Gfx.TextureId,
|
||||||
|
dungeon_tilemap: Tilemap,
|
||||||
|
|
||||||
|
skeleton: Gfx.Sprite,
|
||||||
|
snake: Gfx.Sprite,
|
||||||
|
fire_spirit: Gfx.Sprite,
|
||||||
|
|
||||||
map: tiled.Tilemap,
|
map: tiled.Tilemap,
|
||||||
tilesets: tiled.Tileset.List,
|
tilesets: tiled.Tileset.List,
|
||||||
move_sound: []Audio.Data.Id,
|
|
||||||
|
|
||||||
terrain_tilemap: Tilemap,
|
|
||||||
players_tilemap: Tilemap,
|
|
||||||
weapons_tilemap: Tilemap,
|
|
||||||
|
|
||||||
pub fn init(gpa: std.mem.Allocator) !Assets {
|
pub fn init(gpa: std.mem.Allocator) !Assets {
|
||||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
@ -58,11 +62,88 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
|||||||
.italic = try Gfx.addFont("italic", @embedFile("assets/roboto-font/Roboto-Italic.ttf")),
|
.italic = try Gfx.addFont("italic", @embedFile("assets/roboto-font/Roboto-Italic.ttf")),
|
||||||
});
|
});
|
||||||
|
|
||||||
const wood01 = try Audio.load(.{
|
const pistol_mask_image = try STBImage.load(@embedFile("assets/pistol-mask.png"));
|
||||||
.format = .vorbis,
|
defer pistol_mask_image.deinit();
|
||||||
.data = @embedFile("assets/wood01.ogg"),
|
const pistol_mask_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = pistol_mask_image.width,
|
||||||
|
.height = pistol_mask_image.height,
|
||||||
|
.rgba = pistol_mask_image.rgba8_pixels
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const bomb_mask_image = try STBImage.load(@embedFile("assets/bomb-mask.png"));
|
||||||
|
defer bomb_mask_image.deinit();
|
||||||
|
const bomb_mask_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = bomb_mask_image.width,
|
||||||
|
.height = bomb_mask_image.height,
|
||||||
|
.rgba = bomb_mask_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const laser_mask_image = try STBImage.load(@embedFile("assets/laser-mask.png"));
|
||||||
|
defer laser_mask_image.deinit();
|
||||||
|
const laser_mask_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = laser_mask_image.width,
|
||||||
|
.height = laser_mask_image.height,
|
||||||
|
.rgba = laser_mask_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const skeleton_image = try STBImage.load(@embedFile("assets/skeleton.png"));
|
||||||
|
defer skeleton_image.deinit();
|
||||||
|
const skeleton_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = skeleton_image.width,
|
||||||
|
.height = skeleton_image.height,
|
||||||
|
.rgba = skeleton_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const snake_image = try STBImage.load(@embedFile("assets/snake.png"));
|
||||||
|
defer snake_image.deinit();
|
||||||
|
const snake_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = snake_image.width,
|
||||||
|
.height = snake_image.height,
|
||||||
|
.rgba = snake_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fire_spirit_image = try STBImage.load(@embedFile("assets/fire-spirit.png"));
|
||||||
|
defer fire_spirit_image.deinit();
|
||||||
|
const fire_spirit_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = fire_spirit_image.width,
|
||||||
|
.height = fire_spirit_image.height,
|
||||||
|
.rgba = fire_spirit_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const bullet_image = try STBImage.load(@embedFile("assets/bullet.png"));
|
||||||
|
defer bullet_image.deinit();
|
||||||
|
const bullet_texture = try Gfx.addTexture(&.{
|
||||||
|
.{
|
||||||
|
.width = bullet_image.width,
|
||||||
|
.height = bullet_image.height,
|
||||||
|
.rgba = bullet_image.rgba8_pixels
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const snake = Gfx.Sprite{
|
||||||
|
.texture = snake_texture,
|
||||||
|
.uv = .unit
|
||||||
|
};
|
||||||
|
const skeleton = Gfx.Sprite{
|
||||||
|
.texture = skeleton_texture,
|
||||||
|
.uv = .unit
|
||||||
|
};
|
||||||
|
const fire_spirit = Gfx.Sprite{
|
||||||
|
.texture = fire_spirit_texture,
|
||||||
|
.uv = .unit
|
||||||
|
};
|
||||||
|
|
||||||
var scratch = std.heap.ArenaAllocator.init(gpa);
|
var scratch = std.heap.ArenaAllocator.init(gpa);
|
||||||
defer scratch.deinit();
|
defer scratch.deinit();
|
||||||
|
|
||||||
@ -80,76 +161,54 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
|||||||
gpa,
|
gpa,
|
||||||
&scratch,
|
&scratch,
|
||||||
&xml_buffers,
|
&xml_buffers,
|
||||||
@embedFile("assets/tileset.tsx")
|
@embedFile("assets/dungeon.tsx")
|
||||||
);
|
);
|
||||||
|
|
||||||
var tilesets: tiled.Tileset.List = .empty;
|
var tilesets: tiled.Tileset.List = .empty;
|
||||||
try tilesets.add(gpa, "tilemap.tsx", tileset);
|
try tilesets.add(gpa, "dungeon.tsx", tileset);
|
||||||
|
|
||||||
const players_image = try STBImage.load(@embedFile("assets/kenney_desert-shooter-pack_1.0/PNG/Players/tilemap_packed.png"));
|
const dungeon_image = try STBImage.load(@embedFile("assets/tiny-dungeon/tilemap_packed.png"));
|
||||||
defer players_image.deinit();
|
defer dungeon_image.deinit();
|
||||||
const players_texture = try Gfx.addTexture(&.{
|
const dungeon_texture = try Gfx.addTexture(&.{
|
||||||
.{
|
.{
|
||||||
.width = players_image.width,
|
.width = dungeon_image.width,
|
||||||
.height = players_image.height,
|
.height = dungeon_image.height,
|
||||||
.rgba = players_image.rgba8_pixels
|
.rgba = dungeon_image.rgba8_pixels
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const tileset_image = try STBImage.load(@embedFile("assets/kenney_desert-shooter-pack_1.0/PNG/Tiles/tilemap_packed.png"));
|
const shadow_image = try STBImage.load(@embedFile("assets/shadow.png"));
|
||||||
defer tileset_image.deinit();
|
defer shadow_image.deinit();
|
||||||
const tileset_texture = try Gfx.addTexture(&.{
|
const shadow_texture = try Gfx.addTexture(&.{
|
||||||
.{
|
.{
|
||||||
.width = tileset_image.width,
|
.width = shadow_image.width,
|
||||||
.height = tileset_image.height,
|
.height = shadow_image.height,
|
||||||
.rgba = tileset_image.rgba8_pixels
|
.rgba = shadow_image.rgba8_pixels
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const weapons_tileset = try STBImage.load(@embedFile("assets/kenney_desert-shooter-pack_1.0/PNG/Weapons/tilemap_packed.png"));
|
|
||||||
defer weapons_tileset.deinit();
|
|
||||||
const weapons_texture = try Gfx.addTexture(&.{
|
|
||||||
.{
|
|
||||||
.width = weapons_tileset.width,
|
|
||||||
.height = weapons_tileset.height,
|
|
||||||
.rgba = weapons_tileset.rgba8_pixels
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const move_c = try Audio.load(.{
|
|
||||||
.data = @embedFile("assets/kenney_desert-shooter-pack_1.0/Sounds/move-c.ogg"),
|
|
||||||
.format = .vorbis,
|
|
||||||
});
|
|
||||||
const move_d = try Audio.load(.{
|
|
||||||
.data = @embedFile("assets/kenney_desert-shooter-pack_1.0/Sounds/move-d.ogg"),
|
|
||||||
.format = .vorbis,
|
|
||||||
});
|
|
||||||
const move_sound = try arena.allocator().dupe(Audio.Data.Id, &.{ move_c, move_d });
|
|
||||||
|
|
||||||
return Assets{
|
return Assets{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.font_id = font_id_array,
|
.font_id = font_id_array,
|
||||||
.wood01 = wood01,
|
.pistol_mask = pistol_mask_texture,
|
||||||
|
.bomb_mask = bomb_mask_texture,
|
||||||
|
.laser_mask = laser_mask_texture,
|
||||||
|
.snake = snake,
|
||||||
|
.skeleton = skeleton,
|
||||||
|
.fire_spirit = fire_spirit,
|
||||||
.map = map,
|
.map = map,
|
||||||
.tilesets = tilesets,
|
.tilesets = tilesets,
|
||||||
.move_sound = move_sound,
|
.bullet = bullet_texture,
|
||||||
.terrain_tilemap = .{
|
.shadow = shadow_texture,
|
||||||
.texture = tileset_texture,
|
.dungeon_tilemap = .{
|
||||||
.tile_size = .initFromInt(u32, tileset.tile_width, tileset.tile_height)
|
.texture = dungeon_texture,
|
||||||
},
|
.tile_size = .init(16, 16)
|
||||||
.players_tilemap = .{
|
}
|
||||||
.texture = players_texture,
|
|
||||||
.tile_size = .init(24, 24)
|
|
||||||
},
|
|
||||||
.weapons_tilemap = .{
|
|
||||||
.texture = weapons_texture,
|
|
||||||
.tile_size = .init(24, 24)
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Assets, gpa: std.mem.Allocator) void {
|
pub fn deinit(self: *Assets, gpa: std.mem.Allocator) void {
|
||||||
self.map.deinit();
|
|
||||||
self.tilesets.deinit(gpa);
|
self.tilesets.deinit(gpa);
|
||||||
|
self.map.deinit();
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/assets/bomb-mask.png
Normal file
|
After Width: | Height: | Size: 529 B |
BIN
src/assets/bullet.png
Normal file
|
After Width: | Height: | Size: 279 B |
4
src/assets/dungeon.tsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tileset version="1.10" tiledversion="1.11.2" name="dungeon" tilewidth="16" tileheight="16" tilecount="132" columns="12">
|
||||||
|
<image source="tiny-dungeon/tilemap_packed.png" width="192" height="176"/>
|
||||||
|
</tileset>
|
||||||
BIN
src/assets/fire-spirit.png
Normal file
|
After Width: | Height: | Size: 320 B |
14
src/assets/game.tiled-project
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"automappingRulesFile": "",
|
||||||
|
"commands": [
|
||||||
|
],
|
||||||
|
"compatibilityVersion": 1100,
|
||||||
|
"extensionsPath": "extensions",
|
||||||
|
"folders": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
],
|
||||||
|
"propertyTypes": [
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
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
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
@ -1,9 +0,0 @@
|
|||||||
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
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,9 +0,0 @@
|
|||||||
Tilesheet information:
|
|
||||||
|
|
||||||
Tile size • 16px × 16px
|
|
||||||
Space between tiles • 1px × 1px
|
|
||||||
---
|
|
||||||
Total tiles (horizontal) • 18 tiles
|
|
||||||
Total tiles (vertical) • 13 tiles
|
|
||||||
---
|
|
||||||
Total tiles in sheet • 234 tiles
|
|
||||||
|
Before Width: | Height: | Size: 6.3 KiB |
@ -1,9 +0,0 @@
|
|||||||
Tilesheet information:
|
|
||||||
|
|
||||||
Tile size • 24px × 24px
|
|
||||||
Space between tiles • 1px × 1px
|
|
||||||
---
|
|
||||||
Total tiles (horizontal) • 10 tiles
|
|
||||||
Total tiles (vertical) • 4 tiles
|
|
||||||
---
|
|
||||||
Total tiles in sheet • 40 tiles
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/laser-mask.png
Normal file
|
After Width: | Height: | Size: 557 B |
@ -1,225 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="16" tileheight="16" infinite="1" nextlayerid="5" nextobjectid="2">
|
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="20" height="15" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||||
<tileset firstgid="1" source="tilemap.tsx"/>
|
<tileset firstgid="1" source="dungeon.tsx"/>
|
||||||
<layer id="1" name="ground" width="30" height="20">
|
<layer id="1" name="Tile Layer 1" width="20" height="15">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
<chunk x="-32" y="-32" width="16" height="16">
|
2147483701,51,51,51,52,52,51,51,51,51,51,52,52,52,51,51,51,51,51,53,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
536870963,49,49,49,49,49,49,49,49,50,50,50,50,50,49,49,49,49,49,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,49,43,43,49,49,49,49,49,50,50,50,50,50,49,49,43,43,49,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,49,43,43,49,49,50,49,49,49,50,50,50,50,49,49,43,43,50,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,50,50,49,49,49,50,50,49,49,49,49,49,49,49,49,49,50,50,3758096436,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,50,3758096436,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,49,49,49,49,49,49,50,50,50,50,49,49,50,49,49,49,49,49,3758096436,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
536870963,49,49,49,49,49,49,49,50,50,50,50,50,50,49,49,49,49,49,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
536870963,49,50,50,49,49,49,49,49,49,50,50,50,50,49,49,49,50,50,3758096436,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
536870963,49,50,50,49,49,49,49,49,49,49,49,49,49,49,49,50,50,50,3758096436,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,50,50,49,49,49,49,50,50,49,49,49,49,49,49,50,50,50,49,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
1610612788,49,43,43,49,49,50,50,50,50,50,49,49,49,49,50,43,43,49,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
536870963,49,43,43,49,50,50,50,49,49,49,49,49,49,49,50,43,43,49,3758096436,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
536870963,49,49,49,49,50,50,49,49,49,49,49,49,49,49,49,49,49,49,2684354611,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,
|
3221225525,1073741875,1073741875,1073741875,1073741875,1073741876,1073741876,1073741875,1073741875,1073741875,1073741875,1073741875,1073741875,1073741876,1073741876,1073741875,1073741875,1073741875,1073741876,1073741877
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,
|
</data>
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109
|
|
||||||
</chunk>
|
|
||||||
<chunk x="-16" y="-32" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,65,65,0,0,0,0,0,0,
|
|
||||||
92,92,92,92,92,92,92,93,65,65,0,0,0,0,0,0,
|
|
||||||
110,20,110,110,110,110,110,112,110,65,0,0,0,0,0,0,
|
|
||||||
110,110,110,110,20,110,110,110,110,65,65,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
<chunk x="-32" y="-16" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
<chunk x="-16" y="-16" width="16" height="16">
|
|
||||||
110,110,20,110,110,110,110,94,110,65,65,0,0,0,65,0,
|
|
||||||
110,20,110,110,110,110,20,111,65,65,65,0,0,0,65,0,
|
|
||||||
128,128,128,128,128,128,128,129,65,65,65,0,65,65,65,0,
|
|
||||||
0,0,0,65,65,65,65,65,65,65,65,65,195,65,65,0,
|
|
||||||
0,0,0,65,65,65,65,65,65,65,65,65,65,65,65,0,
|
|
||||||
0,0,65,65,65,65,65,65,65,65,65,65,66,65,65,65,
|
|
||||||
0,0,65,65,65,65,66,65,65,66,65,65,65,65,65,65,
|
|
||||||
0,0,0,65,65,65,65,65,65,65,66,65,65,65,65,65,
|
|
||||||
0,0,0,65,65,195,65,65,65,65,65,65,65,65,65,65,
|
|
||||||
0,0,0,65,65,65,65,66,65,65,65,65,65,65,65,65,
|
|
||||||
0,0,0,65,65,65,65,65,65,66,65,65,195,65,65,65,
|
|
||||||
0,0,0,65,65,65,65,65,65,65,65,65,65,65,66,65,
|
|
||||||
0,65,65,65,65,65,66,65,65,65,65,65,65,65,65,65,
|
|
||||||
0,0,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
<chunk x="0" y="-16" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,65,65,65,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,65,65,65,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,65,65,65,65,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,65,65,65,65,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,65,65,65,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,65,65,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,65,65,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
</data>
|
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="3" name="walls" width="30" height="20">
|
|
||||||
<properties>
|
|
||||||
<property name="solid" type="bool" value="true"/>
|
|
||||||
</properties>
|
|
||||||
<data encoding="csv">
|
|
||||||
<chunk x="-16" y="-32" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,1,2,2,2,2,3,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,19,110,20,110,20,21,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,19,110,110,20,20,21,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,37,38,38,38,38,39,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,73,56,174,174,174,57,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,73,174,174,56,174,57,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,73,174,174,174,174,57,0,0
|
|
||||||
</chunk>
|
|
||||||
<chunk x="-16" y="-16" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,73,174,56,56,174,57,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,73,174,174,174,56,57,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,73,74,74,74,74,75,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
</data>
|
|
||||||
</layer>
|
|
||||||
<layer id="4" name="walls 2" width="30" height="20">
|
|
||||||
<properties>
|
|
||||||
<property name="solid" type="bool" value="true"/>
|
|
||||||
</properties>
|
|
||||||
<data encoding="csv">
|
|
||||||
<chunk x="-16" y="-32" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,37,38,38
|
|
||||||
</chunk>
|
|
||||||
<chunk x="0" y="-32" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
2,2,2,3,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
38,38,38,39,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
<chunk x="-16" y="-16" width="16" height="16">
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,73,174,174,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,73,174,174,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,73,56,174,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,73,56,56,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,74,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
<chunk x="0" y="-16" width="16" height="16">
|
|
||||||
56,56,174,75,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
174,174,174,75,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
174,174,56,75,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
174,56,56,75,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
74,74,74,75,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</chunk>
|
|
||||||
</data>
|
|
||||||
</layer>
|
|
||||||
<objectgroup id="2" name="Object Layer 1">
|
|
||||||
<object id="1" name="spawnpoint" x="-118" y="-120.5">
|
|
||||||
<point/>
|
|
||||||
</object>
|
|
||||||
</objectgroup>
|
|
||||||
</map>
|
</map>
|
||||||
|
|||||||
BIN
src/assets/pistol-mask.png
Normal file
|
After Width: | Height: | Size: 552 B |
BIN
src/assets/shadow.png
Normal file
|
After Width: | Height: | Size: 234 B |
BIN
src/assets/skeleton.png
Normal file
|
After Width: | Height: | Size: 413 B |
BIN
src/assets/snake.png
Normal file
|
After Width: | Height: | Size: 406 B |
@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<tileset version="1.10" tiledversion="1.11.2" name="tilemap" tilewidth="16" tileheight="16" tilecount="234" columns="18">
|
|
||||||
<image source="kenney_desert-shooter-pack_1.0/PNG/Tiles/tilemap_packed.png" width="288" height="208"/>
|
|
||||||
</tileset>
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<tileset version="1.10" tiledversion="1.11.2" name="tilemap" tilewidth="16" tileheight="16" tilecount="234" columns="18">
|
|
||||||
<image source="kenney_desert-shooter-pack_1.0/PNG/Tiles/Tilemap/tilemap_packed.png" width="288" height="208"/>
|
|
||||||
</tileset>
|
|
||||||
23
src/assets/tiny-creatures/License.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Tiny Creatures (1.0)
|
||||||
|
|
||||||
|
Created by Clint Bellanger (clintbellanger.net)
|
||||||
|
Creation date: 03-18-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 my work by crediting Clint Bellanger (this is not mandatory)
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
This set is an expansion of Kenney's Tiny Dungeon and Tiny Town:
|
||||||
|
https://kenney.nl/assets/tiny-dungeon
|
||||||
|
https://kenney.nl/assets/tiny-town
|
||||||
|
The included sample Tiled map and example images contain works by Kenney from these sets.
|
||||||
|
|
||||||
|
Made with Kenney's permission
|
||||||
13
src/assets/tiny-creatures/Tilesheet.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Tilesheet information:
|
||||||
|
|
||||||
|
Tile size • 16px × 16px
|
||||||
|
Space between tiles • 1px × 1px
|
||||||
|
---
|
||||||
|
Total tiles (horizontal) • 10 tiles
|
||||||
|
Total tiles (vertical) • 18 tiles
|
||||||
|
---
|
||||||
|
Total tiles in sheet • 180 tiles
|
||||||
|
|
||||||
|
|
||||||
|
Note: I've set these creatures to all face right (except where symmetrical).
|
||||||
|
You may choose to horizonally-flip these sprites when creatures are facing left.
|
||||||
BIN
src/assets/tiny-creatures/tilemap_packed.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@ -1,10 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
Desert Shooter Pack (1.0)
|
Tiny Dungeon (1.0)
|
||||||
|
|
||||||
Created/distributed by Kenney (www.kenney.nl)
|
Created/distributed by Kenney (www.kenney.nl)
|
||||||
Sponsored by: GameMaker (www.gamemaker.io)
|
Creation date: 05-07-2022
|
||||||
Creation date: 24-04-2024
|
|
||||||
|
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
@ -3,7 +3,7 @@ Tilesheet information:
|
|||||||
Tile size • 16px × 16px
|
Tile size • 16px × 16px
|
||||||
Space between tiles • 1px × 1px
|
Space between tiles • 1px × 1px
|
||||||
---
|
---
|
||||||
Total tiles (horizontal) • 18 tiles
|
Total tiles (horizontal) • 12 tiles
|
||||||
Total tiles (vertical) • 11 tiles
|
Total tiles (vertical) • 11 tiles
|
||||||
---
|
---
|
||||||
Total tiles in sheet • 198 tiles
|
Total tiles in sheet • 132 tiles
|
||||||
BIN
src/assets/tiny-dungeon/tilemap_packed.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
@ -230,6 +230,16 @@ pub fn popScissor(self: *Frame) void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drawCircle(self: *Frame, center: Vec2, radius: f32, color: Vec4) void {
|
||||||
|
self.pushGraphicsCommand(.{
|
||||||
|
.draw_circle = .{
|
||||||
|
.center = center,
|
||||||
|
.radius = radius,
|
||||||
|
.color = color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn drawRectangle(self: *Frame, opts: GraphicsCommand.DrawRectangle) void {
|
pub fn drawRectangle(self: *Frame, opts: GraphicsCommand.DrawRectangle) void {
|
||||||
self.pushGraphicsCommand(.{ .draw_rectangle = opts });
|
self.pushGraphicsCommand(.{ .draw_rectangle = opts });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ const simgui = sokol.imgui;
|
|||||||
const sgl = sokol.gl;
|
const sgl = sokol.gl;
|
||||||
|
|
||||||
const Math = @import("./math.zig");
|
const Math = @import("./math.zig");
|
||||||
|
const Line = Math.Line;
|
||||||
const Vec2 = Math.Vec2;
|
const Vec2 = Math.Vec2;
|
||||||
const Vec4 = Math.Vec4;
|
const Vec4 = Math.Vec4;
|
||||||
const rgb = Math.rgb;
|
const rgb = Math.rgb;
|
||||||
@ -45,6 +46,15 @@ pub const Command = union(enum) {
|
|||||||
sprite: ?Sprite = null,
|
sprite: ?Sprite = null,
|
||||||
rotation: f32 = 0,
|
rotation: f32 = 0,
|
||||||
origin: Vec2 = .init(0, 0),
|
origin: Vec2 = .init(0, 0),
|
||||||
|
uv_flip_diagonal: bool = false,
|
||||||
|
uv_flip_horizontal: bool = false,
|
||||||
|
uv_flip_vertical: bool = false
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DrawCircle = struct {
|
||||||
|
center: Vec2,
|
||||||
|
radius: f32,
|
||||||
|
color: Vec4,
|
||||||
};
|
};
|
||||||
|
|
||||||
set_scissor: Rect,
|
set_scissor: Rect,
|
||||||
@ -59,6 +69,7 @@ pub const Command = union(enum) {
|
|||||||
},
|
},
|
||||||
push_transformation: struct { translation: Vec2, scale: Vec2 },
|
push_transformation: struct { translation: Vec2, scale: Vec2 },
|
||||||
pop_transformation: void,
|
pop_transformation: void,
|
||||||
|
draw_circle: DrawCircle
|
||||||
};
|
};
|
||||||
|
|
||||||
const Texture = struct {
|
const Texture = struct {
|
||||||
@ -80,6 +91,23 @@ pub const TextureInfo = Texture.Info;
|
|||||||
pub const Sprite = struct {
|
pub const Sprite = struct {
|
||||||
texture: TextureId,
|
texture: TextureId,
|
||||||
uv: Rect,
|
uv: Rect,
|
||||||
|
|
||||||
|
pub fn flipHorizontal(self: Sprite) Sprite {
|
||||||
|
var uv = self.uv;
|
||||||
|
uv.pos.x += uv.size.x;
|
||||||
|
uv.size.x *= -1;
|
||||||
|
|
||||||
|
return Sprite{
|
||||||
|
.texture = self.texture,
|
||||||
|
.uv = uv
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getSize(self: Sprite) Vec2 {
|
||||||
|
const texture_info = getTextureInfo(self.texture);
|
||||||
|
const texture_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
||||||
|
return self.uv.size.multiply(texture_size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var gpa: std.mem.Allocator = undefined;
|
var gpa: std.mem.Allocator = undefined;
|
||||||
@ -205,6 +233,25 @@ pub fn drawCommand(command: Command) void {
|
|||||||
font_context.setColor(color);
|
font_context.setColor(color);
|
||||||
font_context.drawText(opts.pos.x * font_resolution_scale.x, opts.pos.y * font_resolution_scale.y, opts.text);
|
font_context.drawText(opts.pos.x * font_resolution_scale.x, opts.pos.y * font_resolution_scale.y, opts.text);
|
||||||
},
|
},
|
||||||
|
.draw_circle => |opts| {
|
||||||
|
sgl.beginTriangleStrip();
|
||||||
|
defer sgl.end();
|
||||||
|
|
||||||
|
const angle_step: f32 = std.math.pi * 2.0 / 32.0;
|
||||||
|
|
||||||
|
sgl.c4f(opts.color.x, opts.color.y, opts.color.z, opts.color.w);
|
||||||
|
|
||||||
|
sgl.v2f(opts.center.x, opts.center.y);
|
||||||
|
var angle: f32 = 0;
|
||||||
|
while (angle < std.math.pi * 2) {
|
||||||
|
const point_on_circle = Vec2.initAngle(angle).multiplyScalar(opts.radius).add(opts.center);
|
||||||
|
sgl.v2f(point_on_circle.x, point_on_circle.y);
|
||||||
|
sgl.v2f(opts.center.x, opts.center.y);
|
||||||
|
|
||||||
|
angle += angle_step;
|
||||||
|
}
|
||||||
|
sgl.v2f(opts.center.x + opts.radius, opts.center.y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +353,41 @@ fn drawRectangle(opts: Command.DrawRectangle) void {
|
|||||||
|
|
||||||
if (opts.sprite) |sprite| {
|
if (opts.sprite) |sprite| {
|
||||||
const uv = sprite.uv;
|
const uv = sprite.uv;
|
||||||
const quad = [4]Vertex{ .{ .pos = pos.add(top_left), .uv = .init(uv.left(), uv.top()) }, .{ .pos = pos.add(top_right), .uv = .init(uv.right(), uv.top()) }, .{ .pos = pos.add(bottom_right), .uv = .init(uv.right(), uv.bottom()) }, .{ .pos = pos.add(bottom_left), .uv = .init(uv.left(), uv.bottom()) } };
|
var uv_top_left = Vec2.init(uv.left(), uv.top());
|
||||||
|
var uv_top_right = Vec2.init(uv.right(), uv.top());
|
||||||
|
var uv_bottom_right = Vec2.init(uv.right(), uv.bottom());
|
||||||
|
var uv_bottom_left = Vec2.init(uv.left(), uv.bottom());
|
||||||
|
|
||||||
|
if (opts.uv_flip_diagonal) {
|
||||||
|
std.mem.swap(Vec2, &uv_bottom_left, &uv_top_right);
|
||||||
|
}
|
||||||
|
if (opts.uv_flip_horizontal) {
|
||||||
|
std.mem.swap(Vec2, &uv_top_left, &uv_top_right);
|
||||||
|
std.mem.swap(Vec2, &uv_bottom_left, &uv_bottom_right);
|
||||||
|
}
|
||||||
|
if (opts.uv_flip_vertical) {
|
||||||
|
std.mem.swap(Vec2, &uv_top_left, &uv_bottom_left);
|
||||||
|
std.mem.swap(Vec2, &uv_top_right, &uv_bottom_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
const quad = [4]Vertex{
|
||||||
|
.{
|
||||||
|
.pos = pos.add(top_left),
|
||||||
|
.uv = uv_top_left
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.pos = pos.add(top_right),
|
||||||
|
.uv = uv_top_right,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.pos = pos.add(bottom_right),
|
||||||
|
.uv = uv_bottom_right
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.pos = pos.add(bottom_left),
|
||||||
|
.uv = uv_bottom_left
|
||||||
|
}
|
||||||
|
};
|
||||||
drawQuad(quad, opts.color, sprite.texture);
|
drawQuad(quad, opts.color, sprite.texture);
|
||||||
} else {
|
} else {
|
||||||
const quad = .{ pos.add(top_left), pos.add(top_right), pos.add(bottom_right), pos.add(bottom_left) };
|
const quad = .{ pos.add(top_left), pos.add(top_right), pos.add(bottom_right), pos.add(bottom_left) };
|
||||||
@ -315,14 +396,22 @@ fn drawRectangle(opts: Command.DrawRectangle) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn drawLine(from: Vec2, to: Vec2, color: Vec4, width: f32) void {
|
fn drawLine(from: Vec2, to: Vec2, color: Vec4, width: f32) void {
|
||||||
const step = to.sub(from).normalized().multiplyScalar(width / 2);
|
const line = Line{
|
||||||
|
.p0 = from,
|
||||||
|
.p1 = to,
|
||||||
|
};
|
||||||
|
|
||||||
const top_left = from.add(step.rotateLeft90());
|
const quad = line.getQuad(width);
|
||||||
const bottom_left = from.add(step.rotateRight90());
|
|
||||||
const top_right = to.add(step.rotateLeft90());
|
|
||||||
const bottom_right = to.add(step.rotateRight90());
|
|
||||||
|
|
||||||
drawQuadNoUVs(.{ top_right, top_left, bottom_left, bottom_right }, color);
|
drawQuadNoUVs(
|
||||||
|
.{
|
||||||
|
quad.top_right,
|
||||||
|
quad.top_left,
|
||||||
|
quad.bottom_left,
|
||||||
|
quad.bottom_right
|
||||||
|
},
|
||||||
|
color
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addFont(name: [*c]const u8, data: []const u8) !Font.Id {
|
pub fn addFont(name: [*c]const u8, data: []const u8) !Font.Id {
|
||||||
@ -378,3 +467,8 @@ pub fn getTextureInfo(id: TextureId) TextureInfo {
|
|||||||
const texture = textures.items[@intFromEnum(id)];
|
const texture = textures.items[@intFromEnum(id)];
|
||||||
return texture.info;
|
return texture.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getTextureSize(id: TextureId) Vec2 {
|
||||||
|
const texture_info = getTextureInfo(id);
|
||||||
|
return Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
||||||
|
}
|
||||||
|
|||||||
@ -368,6 +368,11 @@ pub const Rect = struct {
|
|||||||
pos: Vec2,
|
pos: Vec2,
|
||||||
size: Vec2,
|
size: Vec2,
|
||||||
|
|
||||||
|
pub const unit = Rect{
|
||||||
|
.pos = .zero,
|
||||||
|
.size = .init(1, 1),
|
||||||
|
};
|
||||||
|
|
||||||
pub const zero = Rect{
|
pub const zero = Rect{
|
||||||
.pos = Vec2.zero,
|
.pos = Vec2.zero,
|
||||||
.size = Vec2.zero
|
.size = Vec2.zero
|
||||||
@ -397,6 +402,33 @@ pub const Rect = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getTopEdge(self: Rect) Line {
|
||||||
|
return Line{
|
||||||
|
.p0 = .init(self.left(), self.top()),
|
||||||
|
.p1 = .init(self.right(), self.top()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn getBottomEdge(self: Rect) Line {
|
||||||
|
return Line{
|
||||||
|
.p0 = .init(self.left(), self.bottom()),
|
||||||
|
.p1 = .init(self.right(), self.bottom()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getLeftEdge(self: Rect) Line {
|
||||||
|
return Line{
|
||||||
|
.p0 = .init(self.left(), self.top()),
|
||||||
|
.p1 = .init(self.left(), self.bottom()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getRightEdge(self: Rect) Line {
|
||||||
|
return Line{
|
||||||
|
.p0 = .init(self.right(), self.top()),
|
||||||
|
.p1 = .init(self.right(), self.bottom()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn left(self: Rect) f32 {
|
pub fn left(self: Rect) f32 {
|
||||||
return self.pos.x;
|
return self.pos.x;
|
||||||
}
|
}
|
||||||
@ -431,12 +463,57 @@ pub const Rect = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isInside(self: Rect, pos: Vec2) bool {
|
pub fn isPointInside(self: Rect, pos: Vec2) bool {
|
||||||
const x_overlap = self.pos.x <= pos.x and pos.x < self.pos.x + self.size.x;
|
const x_overlap = self.pos.x <= pos.x and pos.x < self.pos.x + self.size.x;
|
||||||
const y_overlap = self.pos.y <= pos.y and pos.y < self.pos.y + self.size.y;
|
const y_overlap = self.pos.y <= pos.y and pos.y < self.pos.y + self.size.y;
|
||||||
return x_overlap and y_overlap;
|
return x_overlap and y_overlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn checkEdgeLineOverlap(self: Rect, line: Line) bool {
|
||||||
|
const left_overlap = line.hasOverlap(self.getLeftEdge());
|
||||||
|
const right_overlap = line.hasOverlap(self.getRightEdge());
|
||||||
|
const top_overlap = line.hasOverlap(self.getTopEdge());
|
||||||
|
const bottom_overlap = line.hasOverlap(self.getBottomEdge());
|
||||||
|
return left_overlap or right_overlap or top_overlap or bottom_overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkCircleOverlap(self: Rect, circle_center: Vec2, circle_radius: f32) bool {
|
||||||
|
const cx = circle_center.x;
|
||||||
|
const cy = circle_center.y;
|
||||||
|
const rx = self.pos.x;
|
||||||
|
const ry = self.pos.y;
|
||||||
|
const rw = self.size.x;
|
||||||
|
const rh = self.size.y;
|
||||||
|
|
||||||
|
// temporary variables to set edges for testing
|
||||||
|
var testX = cx;
|
||||||
|
var testY = cy;
|
||||||
|
|
||||||
|
// which edge is closest?
|
||||||
|
if (cx < rx) {
|
||||||
|
testX = rx; // test left edge
|
||||||
|
} else if (cx > rx+rw) {
|
||||||
|
testX = rx+rw; // right edge
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cy < ry) {
|
||||||
|
testY = ry; // top edge
|
||||||
|
} else if (cy > ry+rh) {
|
||||||
|
testY = ry+rh; // bottom edge
|
||||||
|
}
|
||||||
|
|
||||||
|
// get distance from closest edges
|
||||||
|
const distX = cx-testX;
|
||||||
|
const distY = cy-testY;
|
||||||
|
const distance = @sqrt( (distX*distX) + (distY*distY) );
|
||||||
|
|
||||||
|
// if the distance is less than the radius, collision!
|
||||||
|
if (distance <= circle_radius) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hasOverlap(lhs: Rect, rhs: Rect) bool {
|
pub fn hasOverlap(lhs: Rect, rhs: Rect) bool {
|
||||||
return (lhs.left() < rhs.right() and lhs.right() > rhs.left()) and
|
return (lhs.left() < rhs.right() and lhs.right() > rhs.left()) and
|
||||||
(lhs.top() < rhs.bottom() and lhs.bottom() > rhs.top());
|
(lhs.top() < rhs.bottom() and lhs.bottom() > rhs.top());
|
||||||
@ -461,9 +538,133 @@ pub const Rect = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Quad = struct {
|
||||||
|
top_left: Vec2,
|
||||||
|
bottom_left: Vec2,
|
||||||
|
top_right: Vec2,
|
||||||
|
bottom_right: Vec2,
|
||||||
|
|
||||||
|
pub fn isRectOverlap(self: Quad, rect: Rect) bool {
|
||||||
|
const vertices = [4]Vec2{
|
||||||
|
self.top_right,
|
||||||
|
self.top_left,
|
||||||
|
self.bottom_left,
|
||||||
|
self.bottom_right,
|
||||||
|
};
|
||||||
|
const polygon = Polygon{
|
||||||
|
.vertices = &vertices
|
||||||
|
};
|
||||||
|
return polygon.isRectOverlap(rect);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Polygon = struct {
|
||||||
|
vertices: []const Vec2,
|
||||||
|
|
||||||
|
pub fn isPointInside(self: Polygon, point: Vec2) bool {
|
||||||
|
var collision = false;
|
||||||
|
|
||||||
|
const py = point.y;
|
||||||
|
const px = point.x;
|
||||||
|
|
||||||
|
for (0..self.vertices.len) |i| {
|
||||||
|
const next_i = @mod(i + 1, self.vertices.len);
|
||||||
|
// get the PVectors at our current position
|
||||||
|
// this makes our if statement a little cleaner
|
||||||
|
const vc = self.vertices[i]; // c for "current"
|
||||||
|
const vn = self.vertices[next_i]; // n for "next"
|
||||||
|
|
||||||
|
// compare position, flip 'collision' variable
|
||||||
|
// back and forth
|
||||||
|
if (
|
||||||
|
((vc.y > py and vn.y < py) or (vc.y < py and vn.y > py))
|
||||||
|
and
|
||||||
|
(px < (vn.x-vc.x)*(py-vc.y) / (vn.y-vc.y)+vc.x)
|
||||||
|
) {
|
||||||
|
collision = !collision;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return collision;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isRectOverlap(self: Polygon, rect: Rect) bool {
|
||||||
|
// go through each of the vertices, plus the next
|
||||||
|
// vertex in the list
|
||||||
|
for (0..self.vertices.len) |i| {
|
||||||
|
const next_i = @mod(i + 1, self.vertices.len);
|
||||||
|
|
||||||
|
// get the PVectors at our current position
|
||||||
|
// this makes our if statement a little cleaner
|
||||||
|
const vc = self.vertices[i]; // c for "current"
|
||||||
|
const vn = self.vertices[next_i]; // n for "next"
|
||||||
|
|
||||||
|
const polygon_edge = Line{
|
||||||
|
.p0 = vc,
|
||||||
|
.p1 = vn,
|
||||||
|
};
|
||||||
|
|
||||||
|
// check against all four sides of the rectangle
|
||||||
|
if (rect.checkEdgeLineOverlap(polygon_edge)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional: test if the rectangle is INSIDE the polygon
|
||||||
|
// note that this iterates all sides of the polygon
|
||||||
|
// again, so only use this if you need to
|
||||||
|
if (self.isPointInside(rect.pos)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const Line = struct {
|
pub const Line = struct {
|
||||||
p0: Vec2,
|
p0: Vec2,
|
||||||
p1: Vec2
|
p1: Vec2,
|
||||||
|
|
||||||
|
pub fn hasOverlap(lhs: Line, rhs: Line) bool {
|
||||||
|
const x1 = lhs.p0.x;
|
||||||
|
const y1 = lhs.p0.y;
|
||||||
|
const x2 = lhs.p1.x;
|
||||||
|
const y2 = lhs.p1.y;
|
||||||
|
const x3 = rhs.p0.x;
|
||||||
|
const y3 = rhs.p0.y;
|
||||||
|
const x4 = rhs.p1.x;
|
||||||
|
const y4 = rhs.p1.y;
|
||||||
|
|
||||||
|
// calculate the direction of the lines
|
||||||
|
const uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
|
||||||
|
const uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
|
||||||
|
|
||||||
|
// if uA and uB are between 0-1, lines are colliding
|
||||||
|
if (uA >= 0 and uA <= 1 and uB >= 0 and uB <= 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getQuad(self: Line, width: f32) Quad {
|
||||||
|
const to = self.p1;
|
||||||
|
const from = self.p0;
|
||||||
|
|
||||||
|
const step = to.sub(from).normalized().multiplyScalar(width / 2);
|
||||||
|
|
||||||
|
const top_left = from.add(step.rotateLeft90());
|
||||||
|
const bottom_left = from.add(step.rotateRight90());
|
||||||
|
const top_right = to.add(step.rotateLeft90());
|
||||||
|
const bottom_right = to.add(step.rotateRight90());
|
||||||
|
|
||||||
|
return Quad{
|
||||||
|
.top_left = top_left,
|
||||||
|
.bottom_left = bottom_left,
|
||||||
|
.top_right = top_right,
|
||||||
|
.bottom_right = bottom_right
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn isInsideRect(rect_pos: Vec2, rect_size: Vec2, pos: Vec2) bool {
|
pub fn isInsideRect(rect_pos: Vec2, rect_size: Vec2, pos: Vec2) bool {
|
||||||
@ -471,7 +672,7 @@ pub fn isInsideRect(rect_pos: Vec2, rect_size: Vec2, pos: Vec2) bool {
|
|||||||
.pos = rect_pos,
|
.pos = rect_pos,
|
||||||
.size = rect_size
|
.size = rect_size
|
||||||
};
|
};
|
||||||
return rect.isInside(pos);
|
return rect.isPointInside(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rgba(r: u8, g: u8, b: u8, a: f32) Vec4 {
|
pub fn rgba(r: u8, g: u8, b: u8, a: f32) Vec4 {
|
||||||
|
|||||||
13
src/game.zig
@ -124,14 +124,14 @@ pub fn debug(self: *Game) !void {
|
|||||||
}
|
}
|
||||||
defer imgui.endWindow();
|
defer imgui.endWindow();
|
||||||
|
|
||||||
if (imgui.button("Spawn enemy")) {
|
|
||||||
try self.combat_screen.spawnEnemy();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imgui.button("Restart")) {
|
if (imgui.button("Restart")) {
|
||||||
try self.restartAndShowCombatScreen();
|
try self.restartAndShowCombatScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imgui.button("Toggle colliders")) {
|
||||||
|
self.combat_screen.show_colliders = !self.combat_screen.show_colliders;
|
||||||
|
}
|
||||||
|
|
||||||
if (self.show_shop) {
|
if (self.show_shop) {
|
||||||
if (imgui.button("Swap to combat")) {
|
if (imgui.button("Swap to combat")) {
|
||||||
self.show_shop = false;
|
self.show_shop = false;
|
||||||
@ -144,10 +144,7 @@ pub fn debug(self: *Game) !void {
|
|||||||
|
|
||||||
const screen = &self.combat_screen;
|
const screen = &self.combat_screen;
|
||||||
|
|
||||||
const time_left_til_pickup = screen.next_pickup_spawn_at - screen.wave_timer;
|
|
||||||
|
|
||||||
imgui.textFmt("Waves: {}\n", .{screen.waves.items.len});
|
imgui.textFmt("Waves: {}\n", .{screen.waves.items.len});
|
||||||
imgui.textFmt("Bullets: {}\n", .{screen.bullets.items.len});
|
imgui.textFmt("Bullets: {}\n", .{screen.bullets.items.len});
|
||||||
imgui.textFmt("Enemies: {}\n", .{screen.enemies.items.len});
|
imgui.textFmt("Enemies: {}\n", .{screen.enemies.count});
|
||||||
imgui.textFmt("Time until next pickup: {d:.2}s\n", .{@as(f32, @floatFromInt(time_left_til_pickup)) / std.time.ns_per_s});
|
|
||||||
}
|
}
|
||||||
|
|||||||
480
src/generational_array_list.zig
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const tracy = @import("tracy");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const Index = u24;
|
||||||
|
const Generation = u8;
|
||||||
|
|
||||||
|
pub fn GenerationalArrayList(Item: type) type {
|
||||||
|
assert(@bitSizeOf(Generation) % 8 == 0);
|
||||||
|
assert(@bitSizeOf(Index) % 8 == 0);
|
||||||
|
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
items: [*]Item,
|
||||||
|
generations: [*]Generation,
|
||||||
|
unused: [*]u8,
|
||||||
|
|
||||||
|
len: u32,
|
||||||
|
capacity: u32,
|
||||||
|
|
||||||
|
count: u32,
|
||||||
|
|
||||||
|
pub const empty = Self{
|
||||||
|
.items = &[_]Item{},
|
||||||
|
.generations = &[_]Generation{},
|
||||||
|
.unused = &[_]u8{},
|
||||||
|
.capacity = 0,
|
||||||
|
.len = 0,
|
||||||
|
.count = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Id = packed struct {
|
||||||
|
generation: Generation,
|
||||||
|
index: Index,
|
||||||
|
|
||||||
|
// TODO: Maybe `Id.Optional` type should be created to ensure .wrap() and .toOptional()
|
||||||
|
pub const none = Id{
|
||||||
|
.generation = std.math.maxInt(Generation),
|
||||||
|
.index = std.math.maxInt(Index),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn format(self: Id, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||||
|
if (self == Id.none) {
|
||||||
|
try writer.print("Id({s}){{ .none }}", .{ @typeName(Item) });
|
||||||
|
} else {
|
||||||
|
try writer.print("Id({s}){{ {}, {} }}", .{ @typeName(Item), self.index, self.generation });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asInt(self: Id) u32 {
|
||||||
|
return @bitCast(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ItemWithId = struct {
|
||||||
|
id: Id,
|
||||||
|
item: *Item,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Iterator = struct {
|
||||||
|
array_list: *Self,
|
||||||
|
index: Index,
|
||||||
|
|
||||||
|
pub fn nextId(self: *Iterator) ?Id {
|
||||||
|
while (self.index < self.array_list.len) {
|
||||||
|
const index = self.index;
|
||||||
|
self.index += 1;
|
||||||
|
|
||||||
|
// TODO: Inline the `byte_index` calculate for better speed.
|
||||||
|
// Probably not needed. Idk
|
||||||
|
if (self.array_list.isUnused(index)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Id{
|
||||||
|
.index = @intCast(index),
|
||||||
|
.generation = self.array_list.generations[index]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nextItem(self: *Iterator) ?*Item {
|
||||||
|
if (self.nextId()) |id| {
|
||||||
|
return &self.array_list.items[id.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: *Iterator) ?ItemWithId {
|
||||||
|
if (self.nextId()) |id| {
|
||||||
|
return ItemWithId{
|
||||||
|
.id = id,
|
||||||
|
.item = &self.array_list.items[id.index]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Metadata = extern struct {
|
||||||
|
len: u32,
|
||||||
|
count: u32
|
||||||
|
};
|
||||||
|
|
||||||
|
fn divCeilGeneration(num: u32) u32 {
|
||||||
|
return std.math.divCeil(u32, num, @bitSizeOf(Generation)) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn divFloorGeneration(num: u32) u32 {
|
||||||
|
return @divFloor(num, @bitSizeOf(Generation));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: u32) !void {
|
||||||
|
if (new_capacity > std.math.maxInt(Index)) {
|
||||||
|
return error.OutOfIndexSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Shrinking is not supported
|
||||||
|
assert(new_capacity >= self.capacity);
|
||||||
|
|
||||||
|
const unused_bit_array_len = divCeilGeneration(self.capacity);
|
||||||
|
const new_unused_bit_array_len = divCeilGeneration(new_capacity);
|
||||||
|
|
||||||
|
// TODO: Handle allocation failure case
|
||||||
|
const new_unused = try allocator.realloc(self.unused[0..unused_bit_array_len], new_unused_bit_array_len);
|
||||||
|
const new_items = try allocator.realloc(self.items[0..self.capacity], new_capacity);
|
||||||
|
const new_generations = try allocator.realloc(self.generations[0..self.capacity], new_capacity);
|
||||||
|
|
||||||
|
self.unused = new_unused.ptr;
|
||||||
|
self.items = new_items.ptr;
|
||||||
|
self.generations = new_generations.ptr;
|
||||||
|
self.capacity = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn growCapacity(current: u32, minimum: u32) u32 {
|
||||||
|
const init_capacity = @as(comptime_int, @max(1, std.atomic.cache_line / @sizeOf(Item)));
|
||||||
|
|
||||||
|
var new = current;
|
||||||
|
while (true) {
|
||||||
|
new +|= new / 2 + init_capacity;
|
||||||
|
if (new >= minimum) {
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: u32) !void {
|
||||||
|
if (self.capacity >= new_capacity) return;
|
||||||
|
|
||||||
|
const better_capacity = Self.growCapacity(self.capacity, new_capacity);
|
||||||
|
try self.ensureTotalCapacityPrecise(allocator, better_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clearRetainingCapacity(self: *Self) void {
|
||||||
|
self.count = 0;
|
||||||
|
self.len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensureUnusedCapacity(self: *Self, allocator: Allocator, unused_capacity: u32) !void {
|
||||||
|
try self.ensureTotalCapacity(allocator, self.len + unused_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findFirstUnused(self: *Self) ?Index {
|
||||||
|
for (0..divCeilGeneration(self.len)) |byte_index| {
|
||||||
|
if (self.unused[byte_index] != 0) {
|
||||||
|
const found = @ctz(self.unused[byte_index]) + byte_index * @bitSizeOf(Generation);
|
||||||
|
if (found < self.len) {
|
||||||
|
return @intCast(found);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn markUnused(self: *Self, index: Index, unused: bool) void {
|
||||||
|
assert(index < self.len);
|
||||||
|
|
||||||
|
const byte_index = divFloorGeneration(index);
|
||||||
|
const bit_index = @mod(index, @bitSizeOf(Generation));
|
||||||
|
const bit_flag = @as(u8, 1) << @intCast(bit_index);
|
||||||
|
if (unused) {
|
||||||
|
self.unused[byte_index] |= bit_flag;
|
||||||
|
} else {
|
||||||
|
self.unused[byte_index] &= ~bit_flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isUnused(self: *Self, index: Index) bool {
|
||||||
|
assert(index < self.len);
|
||||||
|
|
||||||
|
const byte_index = divFloorGeneration(index);
|
||||||
|
const bit_index = @mod(index, @bitSizeOf(Generation));
|
||||||
|
const bit_flag = @as(u8, 1) << @intCast(bit_index);
|
||||||
|
return (self.unused[byte_index] & bit_flag) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insertUndefined(self: *Self, allocator: Allocator) !Id {
|
||||||
|
var unused_index: Index = undefined;
|
||||||
|
|
||||||
|
if (self.findFirstUnused()) |index| {
|
||||||
|
unused_index = index;
|
||||||
|
} else {
|
||||||
|
try self.ensureUnusedCapacity(allocator, 1);
|
||||||
|
|
||||||
|
unused_index = @intCast(self.len);
|
||||||
|
self.len += 1;
|
||||||
|
self.generations[unused_index] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.markUnused(unused_index, false);
|
||||||
|
self.count += 1;
|
||||||
|
|
||||||
|
const id = Id{
|
||||||
|
.index = @intCast(unused_index),
|
||||||
|
.generation = self.generations[unused_index]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(id != Id.none);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(self: *Self, allocator: Allocator, item: Item) !Id {
|
||||||
|
const id = try self.insertUndefined(allocator);
|
||||||
|
|
||||||
|
const new_item_ptr = self.getAssumeExists(id);
|
||||||
|
new_item_ptr.* = item;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exists(self: *Self, id: Id) bool {
|
||||||
|
if (id.index >= self.len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.isUnused(id.index)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.generations[id.index] != id.generation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeAssumeExists(self: *Self, id: Id) void {
|
||||||
|
assert(self.exists(id));
|
||||||
|
|
||||||
|
self.markUnused(id.index, true);
|
||||||
|
// TODO: Maybe a log should be shown when a wrap-around occurs?
|
||||||
|
self.generations[id.index] +%= 1;
|
||||||
|
self.count -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(self: *Self, id: Id) bool {
|
||||||
|
if (!self.exists(id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.removeAssumeExists(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getAssumeExists(self: *Self, id: Id) *Item {
|
||||||
|
assert(self.exists(id));
|
||||||
|
|
||||||
|
return &self.items[id.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *Self, id: Id) ?*Item {
|
||||||
|
if (self.exists(id)) {
|
||||||
|
return self.getAssumeExists(id);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterator(self: *Self) Iterator {
|
||||||
|
return Iterator{
|
||||||
|
.array_list = self,
|
||||||
|
.index = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||||
|
allocator.free(self.unused[0..divCeilGeneration(self.capacity)]);
|
||||||
|
allocator.free(self.generations[0..self.capacity]);
|
||||||
|
allocator.free(self.items[0..self.capacity]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clone(self: *Self, allocator: Allocator) !Self {
|
||||||
|
const items = try allocator.dupe(Item, self.items[0..self.capacity]);
|
||||||
|
errdefer allocator.free(items);
|
||||||
|
|
||||||
|
const generations = try allocator.dupe(Generation, self.generations[0..self.capacity]);
|
||||||
|
errdefer allocator.free(generations);
|
||||||
|
|
||||||
|
const unused = try allocator.dupe(u8, self.unused[0..divCeilGeneration(self.capacity)]);
|
||||||
|
errdefer allocator.free(unused);
|
||||||
|
|
||||||
|
return Self{
|
||||||
|
.items = items.ptr,
|
||||||
|
.generations = generations.ptr,
|
||||||
|
.unused = unused.ptr,
|
||||||
|
.len = self.len,
|
||||||
|
.count = self.count,
|
||||||
|
.capacity = self.capacity
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMetadata(self: *Self) Metadata {
|
||||||
|
return Metadata{
|
||||||
|
.len = self.len,
|
||||||
|
.count = self.count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(self: *Self, writer: *std.Io.Writer, endian: std.builtin.Endian) !void {
|
||||||
|
const zone = tracy.beginZone(@src(), .{ .name = "gen array list write" });
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
|
try writer.writeSliceEndian(Item, self.items[0..self.len], endian);
|
||||||
|
try writer.writeSliceEndian(Generation, self.generations[0..self.len], endian);
|
||||||
|
try writer.writeAll(self.unused[0..divCeilGeneration(self.len)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(
|
||||||
|
self: *Self,
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: *std.Io.Reader,
|
||||||
|
endian: std.builtin.Endian,
|
||||||
|
metadata: Metadata
|
||||||
|
) !void {
|
||||||
|
const zone = tracy.beginZone(@src(), .{ .name = "gen array list read" });
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
|
try self.ensureTotalCapacity(allocator, metadata.len);
|
||||||
|
|
||||||
|
try reader.readSliceEndian(Item, self.items[0..metadata.len], endian);
|
||||||
|
try reader.readSliceEndian(Generation, self.generations[0..metadata.len], endian);
|
||||||
|
try reader.readSliceAll(self.unused[0..divCeilGeneration(metadata.len)]);
|
||||||
|
|
||||||
|
self.len = metadata.len;
|
||||||
|
self.count = metadata.count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const TestArray = GenerationalArrayList(u32);
|
||||||
|
|
||||||
|
test "insert & remove" {
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const gpa = std.testing.allocator;
|
||||||
|
|
||||||
|
var array_list: TestArray = .empty;
|
||||||
|
defer array_list.deinit(gpa);
|
||||||
|
|
||||||
|
const id1 = try array_list.insert(gpa, 10);
|
||||||
|
try expect(array_list.exists(id1));
|
||||||
|
try expect(array_list.remove(id1));
|
||||||
|
try expect(!array_list.exists(id1));
|
||||||
|
try expect(!array_list.remove(id1));
|
||||||
|
|
||||||
|
const id2 = try array_list.insert(gpa, 10);
|
||||||
|
try expect(array_list.exists(id2));
|
||||||
|
try expect(!array_list.exists(id1));
|
||||||
|
try expect(id1.index == id2.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "generation wrap around" {
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const gpa = std.testing.allocator;
|
||||||
|
|
||||||
|
var array_list: TestArray = .empty;
|
||||||
|
defer array_list.deinit(gpa);
|
||||||
|
|
||||||
|
// Grow array list so that at least 1 slot exists
|
||||||
|
const id1 = try array_list.insert(gpa, 10);
|
||||||
|
array_list.removeAssumeExists(id1);
|
||||||
|
|
||||||
|
// Artificially increase generation count
|
||||||
|
array_list.generations[id1.index] = std.math.maxInt(Generation);
|
||||||
|
|
||||||
|
// Check if generation wraps around
|
||||||
|
const id2 = try array_list.insert(gpa, 10);
|
||||||
|
array_list.removeAssumeExists(id2);
|
||||||
|
try expectEqual(id1.index, id2.index);
|
||||||
|
try expectEqual(0, array_list.generations[id1.index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "iterator" {
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const gpa = std.testing.allocator;
|
||||||
|
|
||||||
|
var array_list: TestArray = .empty;
|
||||||
|
defer array_list.deinit(gpa);
|
||||||
|
|
||||||
|
// Create array which has a hole
|
||||||
|
const id1 = try array_list.insert(gpa, 1);
|
||||||
|
const id2 = try array_list.insert(gpa, 2);
|
||||||
|
const id3 = try array_list.insert(gpa, 3);
|
||||||
|
|
||||||
|
array_list.removeAssumeExists(id2);
|
||||||
|
|
||||||
|
var iter = array_list.iterator();
|
||||||
|
try expectEqual(
|
||||||
|
TestArray.ItemWithId{
|
||||||
|
.id = id1,
|
||||||
|
.item = array_list.getAssumeExists(id1)
|
||||||
|
},
|
||||||
|
iter.next().?
|
||||||
|
);
|
||||||
|
try expectEqual(
|
||||||
|
TestArray.ItemWithId{
|
||||||
|
.id = id3,
|
||||||
|
.item = array_list.getAssumeExists(id3)
|
||||||
|
},
|
||||||
|
iter.next().?
|
||||||
|
);
|
||||||
|
try expectEqual(null, iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "read & write" {
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const gpa = std.testing.allocator;
|
||||||
|
|
||||||
|
var array_list1: TestArray = .empty;
|
||||||
|
defer array_list1.deinit(gpa);
|
||||||
|
|
||||||
|
var array_list2: TestArray = .empty;
|
||||||
|
defer array_list2.deinit(gpa);
|
||||||
|
|
||||||
|
const id1 = try array_list1.insert(gpa, 1);
|
||||||
|
const id2 = try array_list1.insert(gpa, 2);
|
||||||
|
const id3 = try array_list1.insert(gpa, 3);
|
||||||
|
|
||||||
|
var buffer: [1024]u8 = undefined;
|
||||||
|
var writer = std.Io.Writer.fixed(&buffer);
|
||||||
|
const native_endian = builtin.cpu.arch.endian();
|
||||||
|
|
||||||
|
try array_list1.write(&writer, native_endian);
|
||||||
|
|
||||||
|
var reader = std.Io.Reader.fixed(writer.buffered());
|
||||||
|
try array_list2.read(gpa, &reader, native_endian, array_list1.getMetadata());
|
||||||
|
|
||||||
|
try expectEqual(array_list1.getAssumeExists(id1).*, array_list2.getAssumeExists(id1).*);
|
||||||
|
try expectEqual(array_list1.getAssumeExists(id2).*, array_list2.getAssumeExists(id2).*);
|
||||||
|
try expectEqual(array_list1.getAssumeExists(id3).*, array_list2.getAssumeExists(id3).*);
|
||||||
|
try expectEqual(array_list1.count, array_list2.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "clear retaining capacity" {
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const gpa = std.testing.allocator;
|
||||||
|
|
||||||
|
var array_list: TestArray = .empty;
|
||||||
|
defer array_list.deinit(gpa);
|
||||||
|
|
||||||
|
const id1 = try array_list.insert(gpa, 10);
|
||||||
|
try expect(array_list.exists(id1));
|
||||||
|
array_list.clearRetainingCapacity();
|
||||||
|
|
||||||
|
const id2 = try array_list.insert(gpa, 10);
|
||||||
|
try expect(array_list.exists(id2));
|
||||||
|
|
||||||
|
try expectEqual(id1, id2);
|
||||||
|
}
|
||||||
@ -134,7 +134,7 @@ pub fn tick(self: *ShopScreen, state: *State, frame: *Frame) !TickResult {
|
|||||||
for (self.nodes.items) |*node| {
|
for (self.nodes.items) |*node| {
|
||||||
const node_rect = Rect.initCentered(node.pos.x, node.pos.y, node_size.x, node_size.y);
|
const node_rect = Rect.initCentered(node.pos.x, node.pos.y, node_size.x, node_size.y);
|
||||||
|
|
||||||
const is_mouse_inside = mouse != null and node_rect.isInside(mouse.?);
|
const is_mouse_inside = mouse != null and node_rect.isPointInside(mouse.?);
|
||||||
const has_enough_money = state.money >= node.money_cost;
|
const has_enough_money = state.money >= node.money_cost;
|
||||||
|
|
||||||
if (has_enough_money and is_mouse_inside and frame.isMousePressed(.left)) {
|
if (has_enough_money and is_mouse_inside and frame.isMousePressed(.left)) {
|
||||||
@ -173,7 +173,7 @@ pub fn tick(self: *ShopScreen, state: *State, frame: *Frame) !TickResult {
|
|||||||
.color = rgb(255, 255, 255)
|
.color = rgb(255, 255, 255)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (frame.input.mouse_position != null and back_rect.isInside(frame.input.mouse_position.?) and frame.isMousePressed(.left)) {
|
if (frame.input.mouse_position != null and back_rect.isPointInside(frame.input.mouse_position.?) and frame.isMousePressed(.left)) {
|
||||||
result.back_to_combat = true;
|
result.back_to_combat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||