add entities
This commit is contained in:
parent
330560f79b
commit
8097ff725b
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.12.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="64" tileheight="64" infinite="0" nextlayerid="6" nextobjectid="2">
|
||||
<map version="1.10" tiledversion="1.12.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="64" tileheight="64" infinite="0" nextlayerid="6" nextobjectid="4">
|
||||
<tileset firstgid="1" source="tileset.tsx"/>
|
||||
<layer id="2" name="Ground" width="30" height="20">
|
||||
<data encoding="csv">
|
||||
@ -49,7 +49,7 @@
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<layer id="4" name="Pushable" width="30" height="20">
|
||||
<layer id="4" name="Boxes" width="30" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
||||
@ -247,6 +247,63 @@ pub fn getLayer(self: *const Tilemap, name: []const u8) ?*const Layer {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub const Bounds = struct {
|
||||
min_x: usize,
|
||||
min_y: usize,
|
||||
max_x: usize,
|
||||
max_y: usize,
|
||||
|
||||
const zero = Bounds{
|
||||
.min_x = 0,
|
||||
.min_y = 0,
|
||||
.max_x = 0,
|
||||
.max_y = 0,
|
||||
};
|
||||
|
||||
pub fn width(self: Bounds) usize {
|
||||
return self.max_x - self.min_x + 1;
|
||||
}
|
||||
|
||||
pub fn height(self: Bounds) usize {
|
||||
return self.max_y - self.min_y + 1;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getTileBounds(self: *const Tilemap) Bounds {
|
||||
var result: ?Bounds = null;
|
||||
|
||||
for (self.layers) |*layer| {
|
||||
if (layer.variant != .tile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (0..self.height) |y| {
|
||||
for (0..self.width) |x| {
|
||||
const gid = layer.variant.tile.get(x, y).?;
|
||||
if (gid != 0) {
|
||||
if (result) |bounds| {
|
||||
result = Bounds{
|
||||
.min_x = @min(x, bounds.min_x),
|
||||
.min_y = @min(y, bounds.min_y),
|
||||
.max_x = @max(x, bounds.max_x),
|
||||
.max_y = @max(y, bounds.max_y)
|
||||
};
|
||||
} else {
|
||||
result = Bounds{
|
||||
.min_x = x,
|
||||
.min_y = y,
|
||||
.max_x = x,
|
||||
.max_y = y
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result orelse Bounds.zero;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *const Tilemap) void {
|
||||
self.arena.deinit();
|
||||
}
|
||||
|
||||
216
src/app.zig
216
src/app.zig
@ -78,15 +78,32 @@ const Tilemap = struct {
|
||||
}
|
||||
};
|
||||
|
||||
player_pos: Vec2,
|
||||
const Entity = struct {
|
||||
type: Type,
|
||||
|
||||
pos_x: i32 = 0,
|
||||
pos_y: i32 = 0,
|
||||
sprite: ?Gfx.Sprite.Id = null,
|
||||
|
||||
player_direction: Direction = .down,
|
||||
player_frame_index: u32 = 0,
|
||||
|
||||
const Type = enum {
|
||||
player,
|
||||
box
|
||||
};
|
||||
|
||||
const SlotMap = Platform.SlotMapType(u8, u16, Entity);
|
||||
const Id = SlotMap.Id;
|
||||
};
|
||||
|
||||
roboto_font: Gfx.Font.Id,
|
||||
tilemap: Tilemap,
|
||||
entities: Entity.SlotMap,
|
||||
|
||||
tilesheet: Tilesheet,
|
||||
|
||||
player_sprites: PlayerSprites,
|
||||
player_direction: Direction,
|
||||
player_frame_index: u32,
|
||||
animation_timer: Platform.Nanoseconds,
|
||||
|
||||
footstep_buffer: Audio.BufferId,
|
||||
@ -188,18 +205,18 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
});
|
||||
|
||||
self.* = App{
|
||||
.player_pos = .init(0, 0),
|
||||
.player_sprites = player_sprites,
|
||||
.roboto_font = robot_font,
|
||||
.player_direction = .left,
|
||||
.player_frame_index = 0,
|
||||
.animation_timer = 0,
|
||||
.tilesheet = tilesheet,
|
||||
.footstep_buffer = footstep_sound,
|
||||
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
||||
.tilemap = try Tilemap.init(plt.gpa, 30, 20)
|
||||
.tilemap = undefined,
|
||||
.entities = try .initCapacity(plt.gpa, 256)
|
||||
};
|
||||
|
||||
var player_pos_x: i32 = 0;
|
||||
var player_pos_y: i32 = 0;
|
||||
{
|
||||
var scratch = std.heap.ArenaAllocator.init(plt.gpa);
|
||||
defer scratch.deinit();
|
||||
@ -215,11 +232,18 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
|
||||
try tilesets.add(plt.gpa, "tileset.tsx", try Tiled.Tileset.initFromBuffer(plt.gpa, &scratch, &buffers, plt.assets.readFile("tiled/tileset.tsx")));
|
||||
|
||||
const bounds = tilemap.getTileBounds();
|
||||
|
||||
self.tilemap = try Tilemap.init(plt.gpa, bounds.width(), bounds.height());
|
||||
|
||||
const ground = tilemap.getLayer("Ground").?;
|
||||
const walls = tilemap.getLayer("Walls").?;
|
||||
for (0..tilemap.height) |y| {
|
||||
for (0..tilemap.width) |x| {
|
||||
const tile = self.tilemap.get(x, y);
|
||||
for (0..bounds.height()) |oy| {
|
||||
for (0..bounds.width()) |ox| {
|
||||
const x = bounds.min_x + ox;
|
||||
const y = bounds.min_y + oy;
|
||||
|
||||
const tile = self.tilemap.get(ox, oy);
|
||||
|
||||
if (tilemap.getTile(ground, tilesets, x, y)) |tiled_tile| {
|
||||
const pos = tiled_tile.getPosition();
|
||||
@ -235,100 +259,67 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
|
||||
const markers = &tilemap.getLayer("Markers").?.variant.object;
|
||||
const spawn = markers.getByName("spawn").?;
|
||||
self.player_pos.x = @divFloor(spawn.shape.point.x, @as(f32, @floatFromInt(tilemap.tile_width)));
|
||||
self.player_pos.y = @divFloor(spawn.shape.point.y, @as(f32, @floatFromInt(tilemap.tile_height)));
|
||||
}
|
||||
player_pos_x = @divFloor(@as(i32, @intFromFloat(spawn.shape.point.x)), @as(i32, @intCast(tilemap.tile_width)));
|
||||
player_pos_x -= @intCast(bounds.min_x);
|
||||
player_pos_y = @divFloor(@as(i32, @intFromFloat(spawn.shape.point.y)),@as(i32, @intCast(tilemap.tile_height)));
|
||||
player_pos_y -= @intCast(bounds.min_y);
|
||||
|
||||
{
|
||||
var min_x: usize = self.tilemap.width;
|
||||
var max_x: usize = 0;
|
||||
var min_y: usize = self.tilemap.height;
|
||||
var max_y: usize = 0;
|
||||
for (0..self.tilemap.height) |y| {
|
||||
for (0..self.tilemap.width) |x| {
|
||||
const tile = self.tilemap.get(x, y);
|
||||
if (tile.ground_sprite != null or tile.wall_sprite != null) {
|
||||
min_x = @min(min_x, x);
|
||||
min_y = @min(min_y, y);
|
||||
max_x = @max(max_x, x);
|
||||
max_y = @max(max_y, y);
|
||||
const boxes = tilemap.getLayer("Boxes").?;
|
||||
for (0..bounds.height()) |oy| {
|
||||
for (0..bounds.width()) |ox| {
|
||||
const x = bounds.min_x + ox;
|
||||
const y = bounds.min_y + oy;
|
||||
|
||||
if (tilemap.getTile(boxes, tilesets, x, y)) |tiled_tile| {
|
||||
const pos = tiled_tile.getPosition();
|
||||
_ = try self.spawnBox(@intCast(ox), @intCast(oy), tilesheet.get(pos.x, pos.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const map_width = max_x - min_x + 1;
|
||||
const map_height = max_y - min_y + 1;
|
||||
|
||||
var new_tilemap = try Tilemap.init(plt.gpa, map_width, map_height);
|
||||
for (0..map_height) |y| {
|
||||
for (0..map_width) |x| {
|
||||
new_tilemap.get(x, y).* = self.tilemap.get(min_x + x, min_y + y).*;
|
||||
}
|
||||
}
|
||||
|
||||
self.tilemap.deinit(plt.gpa);
|
||||
self.tilemap = new_tilemap;
|
||||
|
||||
self.player_pos.x -= @floatFromInt(min_x);
|
||||
self.player_pos.y -= @floatFromInt(min_y);
|
||||
}
|
||||
const player_id = try self.spawnPlayer();
|
||||
const player = self.entities.getAssumeExists(player_id);
|
||||
player.pos_x = player_pos_x;
|
||||
player.pos_y = player_pos_y;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn spawnPlayer(self: *App) !Entity.Id {
|
||||
return try self.entities.insert(Entity{
|
||||
.type = .player,
|
||||
});
|
||||
}
|
||||
|
||||
fn spawnBox(self: *App, x: i32, y: i32, sprite: Gfx.Sprite.Id) !Entity.Id {
|
||||
return try self.entities.insert(Entity{
|
||||
.type = .box,
|
||||
.pos_x = x,
|
||||
.pos_y = y,
|
||||
.sprite = sprite
|
||||
});
|
||||
}
|
||||
|
||||
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
const input = plt.input;
|
||||
|
||||
var dir: Vec2 = .init(0, 0);
|
||||
var dir_y: i32 = 0;
|
||||
var dir_x: i32 = 0;
|
||||
if (input.isKeyPressedOrRepeat(.S)) {
|
||||
dir.y += 1;
|
||||
dir_y += 1;
|
||||
}
|
||||
if (input.isKeyPressedOrRepeat(.W)) {
|
||||
dir.y -= 1;
|
||||
dir_y -= 1;
|
||||
}
|
||||
if (input.isKeyPressedOrRepeat(.D)) {
|
||||
dir.x += 1;
|
||||
dir_x += 1;
|
||||
}
|
||||
if (input.isKeyPressedOrRepeat(.A)) {
|
||||
dir.x -= 1;
|
||||
dir_x -= 1;
|
||||
}
|
||||
if (dir.x != 0) {
|
||||
dir.y = 0;
|
||||
}
|
||||
self.player_pos = self.player_pos.add(dir);
|
||||
|
||||
if (dir.x != 0 or dir.y != 0) {
|
||||
self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .bus = self.sfx_bus });
|
||||
}
|
||||
|
||||
var new_direction = self.player_direction;
|
||||
if (dir.x < 0) {
|
||||
new_direction = .left;
|
||||
} else if (dir.x > 0) {
|
||||
new_direction = .right;
|
||||
} else if (dir.y > 0) {
|
||||
new_direction = .down;
|
||||
} else if (dir.y < 0) {
|
||||
new_direction = .up;
|
||||
}
|
||||
|
||||
if (self.player_direction != new_direction) {
|
||||
self.player_frame_index = 0;
|
||||
self.player_direction = new_direction;
|
||||
}
|
||||
|
||||
const frames = self.player_sprites.getDirection(self.player_direction);
|
||||
|
||||
if (dir.x != 0 or dir.y != 0) {
|
||||
self.animation_timer += plt.input.delta_time;
|
||||
const animatin_time = std.time.ns_per_s / 5;
|
||||
while (self.animation_timer >= animatin_time) {
|
||||
self.player_frame_index = (self.player_frame_index + 1) % @as(u32, @intCast(frames.len));
|
||||
self.animation_timer -= animatin_time;
|
||||
}
|
||||
} else {
|
||||
self.animation_timer = 0;
|
||||
self.player_frame_index = 0;
|
||||
if (dir_x != 0) {
|
||||
dir_y = 0;
|
||||
}
|
||||
|
||||
Gfx.setClearColor(.rgb(40, 40, 40));
|
||||
@ -348,9 +339,64 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
}
|
||||
}
|
||||
|
||||
Gfx.drawSprite(frames[self.player_frame_index], self.player_pos.multiply(tile_size), tile_size, .white);
|
||||
var entity_iter = self.entities.iterator();
|
||||
while (entity_iter.next()) |entity_id| {
|
||||
const entity = self.entities.getAssumeExists(entity_id);
|
||||
if (entity.type == .player) {
|
||||
entity.pos_x += dir_x;
|
||||
entity.pos_y += dir_y;
|
||||
|
||||
var new_direction = entity.player_direction;
|
||||
if (dir_x < 0) {
|
||||
new_direction = .left;
|
||||
} else if (dir_x > 0) {
|
||||
new_direction = .right;
|
||||
} else if (dir_y > 0) {
|
||||
new_direction = .down;
|
||||
} else if (dir_y < 0) {
|
||||
new_direction = .up;
|
||||
}
|
||||
|
||||
if (entity.player_direction != new_direction) {
|
||||
entity.player_frame_index = 0;
|
||||
entity.player_direction = new_direction;
|
||||
}
|
||||
|
||||
const frames = self.player_sprites.getDirection(entity.player_direction);
|
||||
|
||||
if (dir_x != 0 or dir_y != 0) {
|
||||
self.animation_timer += plt.input.delta_time;
|
||||
const animatin_time = std.time.ns_per_s / 5;
|
||||
while (self.animation_timer >= animatin_time) {
|
||||
entity.player_frame_index = (entity.player_frame_index + 1) % @as(u32, @intCast(frames.len));
|
||||
self.animation_timer -= animatin_time;
|
||||
}
|
||||
} else {
|
||||
self.animation_timer = 0;
|
||||
entity.player_frame_index = 0;
|
||||
}
|
||||
|
||||
if (dir_x != 0 or dir_y != 0) {
|
||||
self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .bus = self.sfx_bus });
|
||||
}
|
||||
|
||||
entity.sprite = frames[entity.player_frame_index];
|
||||
}
|
||||
|
||||
|
||||
if (entity.sprite) |sprite| {
|
||||
Gfx.drawSprite(
|
||||
sprite,
|
||||
Vec2.initFromInt(i32, entity.pos_x, entity.pos_y).multiply(tile_size),
|
||||
tile_size,
|
||||
.white
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
||||
self.tilemap.deinit(plt.gpa);
|
||||
self.entities.slots.deinit(plt.gpa);
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ pub fn init(io: Io, gpa: std.mem.Allocator, opts: InitOptions) !void {
|
||||
.vorbis_alloc_buffer = vorbis_alloc_buffer,
|
||||
.thread_state = .{
|
||||
.mutex = .init,
|
||||
.sounds = .init(sounds),
|
||||
.sounds = .initBuffer(sounds),
|
||||
.bus_volumes = bus_volumes,
|
||||
}
|
||||
};
|
||||
|
||||
@ -168,16 +168,16 @@ pub fn init(gpa: std.mem.Allocator, logger: sg.Logger) !void {
|
||||
.transforms = .initBuffer(&self.transforms_buffer),
|
||||
|
||||
.textures_buffer = undefined,
|
||||
.textures = .init(&self.textures_buffer),
|
||||
.textures = .initBuffer(&self.textures_buffer),
|
||||
|
||||
.sprites_buffer = undefined,
|
||||
.sprites = .init(&self.sprites_buffer),
|
||||
.sprites = .initBuffer(&self.sprites_buffer),
|
||||
|
||||
.spritesheets_buffer = undefined,
|
||||
.spritesheets = .init(&self.spritesheets_buffer),
|
||||
.spritesheets = .initBuffer(&self.spritesheets_buffer),
|
||||
|
||||
.fonts_buffer = undefined,
|
||||
.fonts = .init(&self.fonts_buffer),
|
||||
.fonts = .initBuffer(&self.fonts_buffer),
|
||||
};
|
||||
|
||||
self.default_spritesheet = initSpritesheet(.{});
|
||||
|
||||
@ -27,6 +27,7 @@ pub const ImGUI = @import("./imgui.zig");
|
||||
pub const Gfx = @import("./graphics.zig");
|
||||
pub const Input = @import("./input.zig");
|
||||
pub const Audio = @import("./audio.zig");
|
||||
pub const SlotMapType = @import("./slot_map.zig").SlotMapType;
|
||||
|
||||
const EmbeddedAssets = @import("embedded_assets");
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
};
|
||||
|
||||
pub fn clearRetainingCapacity(self: *Self) void {
|
||||
self.* = .init(self.slots.items);
|
||||
self.* = .initBuffer(self.slots.items);
|
||||
}
|
||||
|
||||
fn insertHole(self: *Self, index: Index) void {
|
||||
@ -219,11 +219,21 @@ pub fn SlotMapType(Index: type, Generation: type, Value: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(slots: []Slot) Self {
|
||||
pub fn initBuffer(slots: []Slot) Self {
|
||||
var self: Self = .empty;
|
||||
self.slots = .initBuffer(slots);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn initCapacity(gpa: Allocator, capacity: usize) !Self {
|
||||
var self: Self = .empty;
|
||||
self.slots = try .initCapacity(gpa, capacity);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, gpa: Allocator) void {
|
||||
self.slots.deinit(gpa);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user