add background
This commit is contained in:
parent
beeacdc701
commit
a4d803fc57
@ -136,6 +136,7 @@ pub const TileVariant = struct {
|
||||
const encoded_tiles = try lexer.nextExpectText();
|
||||
const tiles = try parseEncoding(encoding, scratch.allocator(), encoded_tiles);
|
||||
try temp_tiles.appendSlice(scratch.allocator(), tiles.items);
|
||||
continue;
|
||||
|
||||
} else if (node.isTag("chunk")) {
|
||||
const chunk = try initChunkDataFromXml(arena, scratch, lexer, encoding);
|
||||
@ -158,7 +159,6 @@ pub const TileVariant = struct {
|
||||
.fixed = try arena.dupe(u32, temp_tiles.items)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn parseEncoding(
|
||||
|
||||
@ -73,6 +73,9 @@ pub const TilesetReference = struct {
|
||||
pub const Tile = struct {
|
||||
tileset: *const Tileset,
|
||||
id: u32,
|
||||
flip_horizontal: bool,
|
||||
flip_vertical: bool,
|
||||
flip_diagonal: bool,
|
||||
|
||||
pub fn getProperties(self: Tile) Property.List {
|
||||
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 {
|
||||
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 id = gid - tileset_ref.first_gid;
|
||||
const id = gid_without_flags - tileset_ref.first_gid;
|
||||
|
||||
return Tile{
|
||||
.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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
166
src/assets.zig
166
src/assets.zig
@ -24,7 +24,6 @@ pub const Tilemap = struct {
|
||||
texture: Gfx.TextureId,
|
||||
tile_size: Engine.Vec2,
|
||||
|
||||
|
||||
pub fn getTileUV(self: Tilemap, tile_x: f32, tile_y: f32) Rect {
|
||||
const texture_info = Engine.Graphics.getTextureInfo(self.texture);
|
||||
const tilemap_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
||||
@ -39,14 +38,17 @@ pub const Tilemap = struct {
|
||||
arena: std.heap.ArenaAllocator,
|
||||
|
||||
font_id: FontName.EnumArray,
|
||||
wood01: Audio.Data.Id,
|
||||
pistol_mask: Gfx.TextureId,
|
||||
bomb_mask: Gfx.TextureId,
|
||||
laser_mask: Gfx.TextureId,
|
||||
dungeon_tilemap: Tilemap,
|
||||
|
||||
skeleton: Gfx.Sprite,
|
||||
snake: Gfx.Sprite,
|
||||
fire_spirit: Gfx.Sprite,
|
||||
|
||||
map: tiled.Tilemap,
|
||||
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 {
|
||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||
@ -58,11 +60,83 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
||||
.italic = try Gfx.addFont("italic", @embedFile("assets/roboto-font/Roboto-Italic.ttf")),
|
||||
});
|
||||
|
||||
const wood01 = try Audio.load(.{
|
||||
.format = .vorbis,
|
||||
.data = @embedFile("assets/wood01.ogg"),
|
||||
const pistol_mask_image = try STBImage.load(@embedFile("assets/pistol-mask.png"));
|
||||
defer pistol_mask_image.deinit();
|
||||
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 creatures_image = try STBImage.load(@embedFile("assets/tiny-creatures/tilemap_packed.png"));
|
||||
defer creatures_image.deinit();
|
||||
const creatures_texture = try Gfx.addTexture(&.{
|
||||
.{
|
||||
.width = creatures_image.width,
|
||||
.height = creatures_image.height,
|
||||
.rgba = creatures_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 creatures_tilemap = Tilemap{
|
||||
.texture = creatures_texture,
|
||||
.tile_size = .init(16, 16)
|
||||
};
|
||||
const snake = Gfx.Sprite{
|
||||
.texture = snake_texture,
|
||||
.uv = .unit
|
||||
};
|
||||
const skeleton = Gfx.Sprite{
|
||||
.texture = creatures_texture,
|
||||
.uv = creatures_tilemap.getTileUV(1, 0)
|
||||
};
|
||||
const fire_spirit = Gfx.Sprite{
|
||||
.texture = fire_spirit_texture,
|
||||
.uv = .unit
|
||||
};
|
||||
|
||||
var scratch = std.heap.ArenaAllocator.init(gpa);
|
||||
defer scratch.deinit();
|
||||
|
||||
@ -80,76 +154,42 @@ pub fn init(gpa: std.mem.Allocator) !Assets {
|
||||
gpa,
|
||||
&scratch,
|
||||
&xml_buffers,
|
||||
@embedFile("assets/tileset.tsx")
|
||||
@embedFile("assets/dungeon.tsx")
|
||||
);
|
||||
|
||||
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"));
|
||||
defer players_image.deinit();
|
||||
const players_texture = try Gfx.addTexture(&.{
|
||||
const dungeon_image = try STBImage.load(@embedFile("assets/tiny-dungeon/tilemap_packed.png"));
|
||||
defer dungeon_image.deinit();
|
||||
const dungeon_texture = try Gfx.addTexture(&.{
|
||||
.{
|
||||
.width = players_image.width,
|
||||
.height = players_image.height,
|
||||
.rgba = players_image.rgba8_pixels
|
||||
.width = dungeon_image.width,
|
||||
.height = dungeon_image.height,
|
||||
.rgba = dungeon_image.rgba8_pixels
|
||||
}
|
||||
});
|
||||
|
||||
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
|
||||
}
|
||||
});
|
||||
|
||||
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{
|
||||
.arena = arena,
|
||||
.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,
|
||||
.tilesets = tilesets,
|
||||
.move_sound = move_sound,
|
||||
.terrain_tilemap = .{
|
||||
.texture = tileset_texture,
|
||||
.tile_size = .initFromInt(u32, tileset.tile_width, tileset.tile_height)
|
||||
},
|
||||
.players_tilemap = .{
|
||||
.texture = players_texture,
|
||||
.tile_size = .init(24, 24)
|
||||
},
|
||||
.weapons_tilemap = .{
|
||||
.texture = weapons_texture,
|
||||
.tile_size = .init(24, 24)
|
||||
},
|
||||
.dungeon_tilemap = .{
|
||||
.texture = dungeon_texture,
|
||||
.tile_size = .init(16, 16)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Assets, gpa: std.mem.Allocator) void {
|
||||
self.map.deinit();
|
||||
self.tilesets.deinit(gpa);
|
||||
self.map.deinit();
|
||||
self.arena.deinit();
|
||||
}
|
||||
|
||||
4
src/assets/dungeon.tsx
Normal file
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
BIN
src/assets/fire-spirit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 320 B |
14
src/assets/game.tiled-project
Normal file
14
src/assets/game.tiled-project
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"automappingRulesFile": "",
|
||||
"commands": [
|
||||
],
|
||||
"compatibilityVersion": 1100,
|
||||
"extensionsPath": "extensions",
|
||||
"folders": [
|
||||
"."
|
||||
],
|
||||
"properties": [
|
||||
],
|
||||
"propertyTypes": [
|
||||
]
|
||||
}
|
||||
23
src/assets/map.tmx
Normal file
23
src/assets/map.tmx
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="dungeon.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="20" height="15">
|
||||
<data encoding="csv">
|
||||
2147483701,51,51,51,52,52,51,51,51,51,51,52,52,52,51,51,51,51,51,53,
|
||||
536870963,49,49,49,49,49,49,49,49,50,50,50,50,50,49,49,49,49,49,2684354611,
|
||||
1610612788,49,43,43,49,49,49,49,49,50,50,50,50,50,49,49,43,43,49,2684354611,
|
||||
1610612788,49,43,43,49,49,50,49,49,49,50,50,50,50,49,49,43,43,50,2684354611,
|
||||
1610612788,50,50,49,49,49,50,50,49,49,49,49,49,49,49,49,49,50,50,3758096436,
|
||||
1610612788,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,50,3758096436,
|
||||
1610612788,49,49,49,49,49,49,50,50,50,50,49,49,50,49,49,49,49,49,3758096436,
|
||||
536870963,49,49,49,49,49,49,49,50,50,50,50,50,50,49,49,49,49,49,2684354611,
|
||||
536870963,49,50,50,49,49,49,49,49,49,50,50,50,50,49,49,49,50,50,3758096436,
|
||||
536870963,49,50,50,49,49,49,49,49,49,49,49,49,49,49,49,50,50,50,3758096436,
|
||||
1610612788,50,50,49,49,49,49,50,50,49,49,49,49,49,49,50,50,50,49,2684354611,
|
||||
1610612788,49,43,43,49,49,50,50,50,50,50,49,49,49,49,50,43,43,49,2684354611,
|
||||
536870963,49,43,43,49,50,50,50,49,49,49,49,49,49,49,50,43,43,49,3758096436,
|
||||
536870963,49,49,49,49,50,50,49,49,49,49,49,49,49,49,49,49,49,49,2684354611,
|
||||
3221225525,1073741875,1073741875,1073741875,1073741875,1073741876,1073741876,1073741875,1073741875,1073741875,1073741875,1073741875,1073741875,1073741876,1073741876,1073741875,1073741875,1073741875,1073741876,1073741877
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
BIN
src/assets/snake.png
Normal file
BIN
src/assets/snake.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 406 B |
22
src/assets/tiny-dungeon/License.txt
Normal file
22
src/assets/tiny-dungeon/License.txt
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
Tiny Dungeon (1.0)
|
||||
|
||||
Created/distributed by Kenney (www.kenney.nl)
|
||||
Creation date: 05-07-2022
|
||||
|
||||
------------------------------
|
||||
|
||||
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
|
||||
9
src/assets/tiny-dungeon/Tilesheet.txt
Normal file
9
src/assets/tiny-dungeon/Tilesheet.txt
Normal file
@ -0,0 +1,9 @@
|
||||
Tilesheet information:
|
||||
|
||||
Tile size • 16px × 16px
|
||||
Space between tiles • 1px × 1px
|
||||
---
|
||||
Total tiles (horizontal) • 12 tiles
|
||||
Total tiles (vertical) • 11 tiles
|
||||
---
|
||||
Total tiles in sheet • 132 tiles
|
||||
BIN
src/assets/tiny-dungeon/tilemap_packed.png
Normal file
BIN
src/assets/tiny-dungeon/tilemap_packed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@ -10,6 +10,7 @@ const GenerationalArrayList = @import("./generational_array_list.zig").Generatio
|
||||
const Engine = @import("./engine/root.zig");
|
||||
const Nanoseconds = Engine.Nanoseconds;
|
||||
const Vec2 = Engine.Vec2;
|
||||
const Sprite = Engine.Graphics.Sprite;
|
||||
const Line = Engine.Math.Line;
|
||||
const Rect = Engine.Math.Rect;
|
||||
const Range = Engine.Math.Range;
|
||||
@ -55,10 +56,11 @@ const Player = struct {
|
||||
max_health: u32 = 0,
|
||||
last_shot_at: ?Nanoseconds = null,
|
||||
invincible_until: ?Nanoseconds = null,
|
||||
gun: ?Gun = null,
|
||||
gun: Gun = .pistol,
|
||||
|
||||
pub fn getRect(self: Player) Rect {
|
||||
return getCenteredRect(self.kinetic.pos, 16);
|
||||
const pos = self.kinetic.pos;
|
||||
return Rect.initCentered(pos.x, pos.y, 16, 24);
|
||||
}
|
||||
};
|
||||
|
||||
@ -90,6 +92,8 @@ const Enemy = struct {
|
||||
kinetic: Kinetic,
|
||||
speed: f32,
|
||||
size: f32,
|
||||
sprite: Sprite,
|
||||
|
||||
target: ?Vec2 = null,
|
||||
distance_to_target: ?f32 = null,
|
||||
|
||||
@ -147,18 +151,8 @@ const Wave = struct {
|
||||
};
|
||||
};
|
||||
|
||||
const Pickup = struct {
|
||||
const Kind = enum {
|
||||
money
|
||||
};
|
||||
|
||||
pos: Vec2,
|
||||
kind: Kind,
|
||||
};
|
||||
|
||||
const world_size = Vec2.init(20 * 16, 15 * 16);
|
||||
const invincibility_duration_s = 0.5;
|
||||
const pickup_spawn_duration_s = Range.init(1, 5);
|
||||
const wave_infos = [_]Wave.Info{
|
||||
.{
|
||||
.kind = .regular,
|
||||
@ -196,24 +190,15 @@ bullets: std.ArrayList(Bullet) = .empty,
|
||||
lasers: std.ArrayList(Laser) = .empty,
|
||||
bombs: std.ArrayList(Bomb) = .empty,
|
||||
|
||||
pickups: std.ArrayList(Pickup) = .empty,
|
||||
next_pickup_spawn_at: Nanoseconds,
|
||||
|
||||
wave_timer: Nanoseconds = 0,
|
||||
|
||||
waves: std.ArrayList(Wave) = .empty,
|
||||
spawned_waves: std.ArrayList(usize) = .empty,
|
||||
|
||||
pub fn init(gpa: Allocator, seed: u64, assets: *Assets, state: State) CombatScreen {
|
||||
var rng = RNGState.init(seed);
|
||||
|
||||
const next_pickup_spawn_at_s = pickup_spawn_duration_s.random(rng.random());
|
||||
const next_pickup_spawn_at: Nanoseconds = @intFromFloat(next_pickup_spawn_at_s * std.time.ns_per_s);
|
||||
|
||||
return CombatScreen{
|
||||
.gpa = gpa,
|
||||
.assets = assets,
|
||||
.next_pickup_spawn_at = next_pickup_spawn_at,
|
||||
.player = .{
|
||||
.kinetic = .{
|
||||
.pos = world_size.divideScalar(2)
|
||||
@ -222,7 +207,7 @@ pub fn init(gpa: Allocator, seed: u64, assets: *Assets, state: State) CombatScre
|
||||
.health = state.max_health,
|
||||
.max_health = state.max_health,
|
||||
},
|
||||
.rng = rng
|
||||
.rng = RNGState.init(seed)
|
||||
};
|
||||
}
|
||||
|
||||
@ -235,7 +220,6 @@ pub fn deinit(self: *CombatScreen) void {
|
||||
self.bullets.deinit(self.gpa);
|
||||
self.enemies.deinit(self.gpa);
|
||||
self.waves.deinit(self.gpa);
|
||||
self.pickups.deinit(self.gpa);
|
||||
self.spawned_waves.deinit(self.gpa);
|
||||
self.lasers.deinit(self.gpa);
|
||||
self.bombs.deinit(self.gpa);
|
||||
@ -244,6 +228,7 @@ pub fn deinit(self: *CombatScreen) void {
|
||||
|
||||
const EnemyOptions = struct {
|
||||
pos: ?Vec2 = null,
|
||||
sprite: Sprite,
|
||||
size: f32 = 20
|
||||
};
|
||||
|
||||
@ -290,18 +275,8 @@ pub fn spawnEnemy(self: *CombatScreen, opts: EnemyOptions) !Enemy.Id {
|
||||
return try self.enemies.insert(self.gpa, Enemy{
|
||||
.kinetic = .{ .pos = pos },
|
||||
.speed = 50,
|
||||
.size = opts.size
|
||||
});
|
||||
}
|
||||
|
||||
pub fn spawnPickup(self: *CombatScreen) !void {
|
||||
const margin = 10;
|
||||
const spawn_area = (Rect{ .pos = .zero, .size = world_size }).grow(-margin);
|
||||
const pos = Vec2.initRandomRect(self.rng.random(), spawn_area);
|
||||
|
||||
try self.pickups.append(self.gpa, Pickup{
|
||||
.pos = pos,
|
||||
.kind = .money
|
||||
.size = opts.size,
|
||||
.sprite = opts.sprite
|
||||
});
|
||||
}
|
||||
|
||||
@ -310,7 +285,49 @@ const TickResult = struct {
|
||||
player_finished: bool
|
||||
};
|
||||
|
||||
fn drawMap(self: *CombatScreen, frame: *Engine.Frame) void {
|
||||
const tilemap = self.assets.dungeon_tilemap;
|
||||
const texture_info = Engine.Graphics.getTextureInfo(tilemap.texture);
|
||||
const tilemap_size = Vec2.initFromInt(u32, texture_info.width, texture_info.height);
|
||||
|
||||
for (self.assets.map.layers) |layer| {
|
||||
if (layer.variant != .tile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const tile_layer = layer.variant.tile;
|
||||
for (0..tile_layer.height) |y| {
|
||||
for (0..tile_layer.width) |x| {
|
||||
const tile_gid = tile_layer.get(@intCast(x), @intCast(y)) orelse continue;
|
||||
if (tile_gid == 0) continue;
|
||||
|
||||
const tile = self.assets.map.getTile(self.assets.tilesets, tile_gid) orelse continue;
|
||||
const tile_id_f32: f32 = @floatFromInt(tile.id);
|
||||
const width_in_tiles = tilemap_size.x / tilemap.tile_size.x;
|
||||
const tile_x = @rem(tile_id_f32, width_in_tiles);
|
||||
const tile_y = @divFloor(tile_id_f32, width_in_tiles);
|
||||
|
||||
frame.drawRectangle(.{
|
||||
.rect = .{
|
||||
.pos = Vec2.initFromInt(usize, x, y).multiply(tilemap.tile_size),
|
||||
.size = tilemap.tile_size
|
||||
},
|
||||
.color = rgb(255, 255, 255),
|
||||
.sprite = .{
|
||||
.texture = tilemap.texture,
|
||||
.uv = tilemap.getTileUV(tile_x, tile_y)
|
||||
},
|
||||
.uv_flip_diagonal = tile.flip_diagonal,
|
||||
.uv_flip_vertical = tile.flip_vertical,
|
||||
.uv_flip_horizontal = tile.flip_horizontal,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResult {
|
||||
|
||||
const dt = frame.deltaTime();
|
||||
|
||||
var result = TickResult{
|
||||
@ -357,7 +374,9 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
while (wave.enemies_spawned < expected_enemies) {
|
||||
switch (wave.kind) {
|
||||
.regular => {
|
||||
_ = try self.spawnEnemy(.{});
|
||||
_ = try self.spawnEnemy(.{
|
||||
.sprite = self.assets.skeleton
|
||||
});
|
||||
},
|
||||
.snake => {
|
||||
var arena = std.heap.ArenaAllocator.init(self.gpa);
|
||||
@ -367,7 +386,9 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
const rand = self.rng.random();
|
||||
const snake_length = rand.intRangeAtMost(u32, wave.min_group_size, wave.max_group_size);
|
||||
|
||||
const head_id = try self.spawnEnemy(.{ });
|
||||
const head_id = try self.spawnEnemy(.{
|
||||
.sprite = self.assets.snake
|
||||
});
|
||||
try enemies.append(arena.allocator(), head_id);
|
||||
|
||||
const head = self.enemies.getAssumeExists(head_id);
|
||||
@ -379,6 +400,7 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
for (0..snake_length) |i| {
|
||||
const tail_pos = head_pos.sub(dir_to_center.multiplyScalar(@floatFromInt(i * gap)));
|
||||
const tail_id = try self.spawnEnemy(.{
|
||||
.sprite = self.assets.snake,
|
||||
.pos = tail_pos
|
||||
});
|
||||
try enemies.append(arena.allocator(), tail_id);
|
||||
@ -407,6 +429,7 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
|
||||
const enemy_id = try self.spawnEnemy(.{
|
||||
.pos = center.add(Vec2.initAngle(angle).multiplyScalar(distance)),
|
||||
.sprite = self.assets.fire_spirit,
|
||||
.size = 10
|
||||
});
|
||||
try enemies.append(arena.allocator(), enemy_id);
|
||||
@ -434,19 +457,9 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
}
|
||||
}
|
||||
|
||||
if (self.wave_timer >= self.next_pickup_spawn_at) {
|
||||
const next_pickup_spawn_at_s = pickup_spawn_duration_s.random(self.rng.random());
|
||||
const next_pickup_spawn_at: Nanoseconds = @intFromFloat(next_pickup_spawn_at_s * std.time.ns_per_s);
|
||||
self.next_pickup_spawn_at = self.wave_timer + next_pickup_spawn_at;
|
||||
try self.spawnPickup();
|
||||
}
|
||||
|
||||
frame.graphics.canvas_size = world_size;
|
||||
|
||||
frame.drawRectangle(.{
|
||||
.rect = .init(0, 0, world_size.x, world_size.y),
|
||||
.color = rgb(20, 20, 20)
|
||||
});
|
||||
self.drawMap(frame);
|
||||
|
||||
var dir = Vec2.init(0, 0);
|
||||
if (frame.isKeyDown(.W)) {
|
||||
@ -500,8 +513,7 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
if (frame.isMouseDown(.left) and cooldown_complete) {
|
||||
self.player.last_shot_at = frame.time_ns;
|
||||
|
||||
if (self.player.gun) |gun| {
|
||||
switch (gun) {
|
||||
switch (self.player.gun) {
|
||||
.pistol => {
|
||||
try self.bullets.append(self.gpa, .{
|
||||
.kinetic = .{
|
||||
@ -534,11 +546,19 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
frame.drawRectangle(.{
|
||||
.rect = self.player.getRect(),
|
||||
.color = rgb(255, 255, 255)
|
||||
.color = rgb(255, 255, 255),
|
||||
.sprite = .{
|
||||
.texture = switch (self.player.gun) {
|
||||
.pistol => self.assets.pistol_mask,
|
||||
.bomb => self.assets.bomb_mask,
|
||||
.laser => self.assets.laser_mask,
|
||||
},
|
||||
.uv = .unit
|
||||
}
|
||||
});
|
||||
|
||||
for (self.bullets.items) |*bullet| {
|
||||
@ -775,40 +795,19 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
}
|
||||
|
||||
enemy.kinetic.update(dt, .{});
|
||||
|
||||
frame.drawRectangle(.{
|
||||
.rect = enemy_rect,
|
||||
.color = rgb(20, 200, 20)
|
||||
.color = rgba(20, 20, 200, 0.2),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var index: usize = 0;
|
||||
while (index < self.pickups.items.len) {
|
||||
var destroy: bool = false;
|
||||
const pickup = self.pickups.items[index];
|
||||
|
||||
const pickup_rect = Rect.initCentered(pickup.pos.x, pickup.pos.y, 10, 10);
|
||||
|
||||
if (pickup_rect.hasOverlap(self.player.getRect())) {
|
||||
switch (pickup.kind) {
|
||||
.money => {
|
||||
state.money += 1;
|
||||
}
|
||||
}
|
||||
destroy = true;
|
||||
}
|
||||
|
||||
const pos = enemy.kinetic.pos;
|
||||
const sprite_size = enemy.sprite.getSize();
|
||||
frame.drawRectangle(.{
|
||||
.rect = pickup_rect,
|
||||
.color = rgb(20, 20, 200)
|
||||
.rect = Rect.initCentered(pos.x, pos.y, sprite_size.x, sprite_size.y),
|
||||
.color = rgb(255, 255, 255),
|
||||
.sprite = enemy.sprite
|
||||
});
|
||||
|
||||
if (destroy) {
|
||||
_ = self.pickups.swapRemove(index);
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -842,7 +841,7 @@ pub fn tick(self: *CombatScreen, state: *State, frame: *Engine.Frame) !TickResul
|
||||
|
||||
frame.drawTextFormat(.init(10, 30), text_opts, "{d}", .{ state.money });
|
||||
frame.drawTextFormat(.init(10, 50), text_opts, "{d}/{d}", .{ self.player.health, self.player.max_health });
|
||||
frame.drawTextFormat(.init(10, 70), text_opts, "{?}", .{ self.player.gun });
|
||||
frame.drawTextFormat(.init(10, 70), text_opts, "{}", .{ self.player.gun });
|
||||
|
||||
result.player_died = (self.player.health == 0);
|
||||
if (self.enemies.count == 0 and self.waves.items.len == 0 and self.spawned_waves.items.len == wave_infos.len) {
|
||||
|
||||
@ -46,6 +46,9 @@ pub const Command = union(enum) {
|
||||
sprite: ?Sprite = null,
|
||||
rotation: f32 = 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 {
|
||||
@ -88,6 +91,12 @@ pub const TextureInfo = Texture.Info;
|
||||
pub const Sprite = struct {
|
||||
texture: TextureId,
|
||||
uv: Rect,
|
||||
|
||||
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;
|
||||
@ -333,7 +342,41 @@ fn drawRectangle(opts: Command.DrawRectangle) void {
|
||||
|
||||
if (opts.sprite) |sprite| {
|
||||
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);
|
||||
} else {
|
||||
const quad = .{ pos.add(top_left), pos.add(top_right), pos.add(bottom_right), pos.add(bottom_left) };
|
||||
|
||||
@ -368,6 +368,11 @@ pub const Rect = struct {
|
||||
pos: Vec2,
|
||||
size: Vec2,
|
||||
|
||||
pub const unit = Rect{
|
||||
.pos = .zero,
|
||||
.size = .init(1, 1),
|
||||
};
|
||||
|
||||
pub const zero = Rect{
|
||||
.pos = Vec2.zero,
|
||||
.size = Vec2.zero
|
||||
|
||||
@ -124,10 +124,6 @@ pub fn debug(self: *Game) !void {
|
||||
}
|
||||
defer imgui.endWindow();
|
||||
|
||||
if (imgui.button("Spawn enemy")) {
|
||||
_ = try self.combat_screen.spawnEnemy(.{});
|
||||
}
|
||||
|
||||
if (imgui.button("Restart")) {
|
||||
try self.restartAndShowCombatScreen();
|
||||
}
|
||||
@ -144,10 +140,7 @@ pub fn debug(self: *Game) !void {
|
||||
|
||||
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("Bullets: {}\n", .{screen.bullets.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});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user