add collision detection
This commit is contained in:
parent
94dc7fef0e
commit
e317e21cfe
190
src/app.zig
190
src/app.zig
@ -44,21 +44,22 @@ const PlayerSprites = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Tile = struct {
|
||||||
|
ground_sprite: ?Gfx.Sprite.Id,
|
||||||
|
|
||||||
|
entity: Entity.Id,
|
||||||
|
|
||||||
|
const empty = Tile{
|
||||||
|
.ground_sprite = null,
|
||||||
|
.entity = .nil
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const Tilemap = struct {
|
const Tilemap = struct {
|
||||||
tiles: []Tile,
|
tiles: []Tile,
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
|
|
||||||
const Tile = struct {
|
|
||||||
ground_sprite: ?Gfx.Sprite.Id,
|
|
||||||
wall_sprite: ?Gfx.Sprite.Id,
|
|
||||||
|
|
||||||
const empty = Tile{
|
|
||||||
.ground_sprite = null,
|
|
||||||
.wall_sprite = null
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, width: usize, height: usize) !Tilemap {
|
pub fn init(gpa: Allocator, width: usize, height: usize) !Tilemap {
|
||||||
const tiles = try gpa.alloc(Tile, width * height);
|
const tiles = try gpa.alloc(Tile, width * height);
|
||||||
@memset(tiles, .empty);
|
@memset(tiles, .empty);
|
||||||
@ -84,8 +85,9 @@ const Tilemap = struct {
|
|||||||
const Entity = struct {
|
const Entity = struct {
|
||||||
type: Type,
|
type: Type,
|
||||||
|
|
||||||
pos_x: i32 = 0,
|
pos_x: i32 = -1,
|
||||||
pos_y: i32 = 0,
|
pos_y: i32 = -1,
|
||||||
|
visual_pos: Vec2 = .init(0, 0),
|
||||||
sprite: ?Gfx.Sprite.Id = null,
|
sprite: ?Gfx.Sprite.Id = null,
|
||||||
|
|
||||||
player_direction: Direction = .down,
|
player_direction: Direction = .down,
|
||||||
@ -93,17 +95,83 @@ const Entity = struct {
|
|||||||
|
|
||||||
const Type = enum {
|
const Type = enum {
|
||||||
player,
|
player,
|
||||||
box
|
box,
|
||||||
|
wall
|
||||||
};
|
};
|
||||||
|
|
||||||
const SlotMap = Platform.SlotMapType(u8, u16, Entity);
|
const SlotMap = Platform.SlotMapType(u16, u8, Entity);
|
||||||
const Id = SlotMap.Id;
|
const Id = SlotMap.Id;
|
||||||
};
|
};
|
||||||
|
|
||||||
roboto_font: Font,
|
const World = struct {
|
||||||
tilemap: Tilemap,
|
tilemap: Tilemap,
|
||||||
entities: Entity.SlotMap,
|
entities: Entity.SlotMap,
|
||||||
|
|
||||||
|
fn spawnPlayer(self: *World) !Entity.Id {
|
||||||
|
return try self.entities.insert(Entity{
|
||||||
|
.type = .player,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawnBox(self: *World, sprite: Gfx.Sprite.Id) !Entity.Id {
|
||||||
|
return try self.entities.insert(Entity{
|
||||||
|
.type = .box,
|
||||||
|
.sprite = sprite
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawnWall(self: *World, sprite: Gfx.Sprite.Id) !Entity.Id {
|
||||||
|
return try self.entities.insert(Entity{
|
||||||
|
.type = .wall,
|
||||||
|
.sprite = sprite
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getTile(self: *World, x: i32, y: i32) ?*Tile {
|
||||||
|
const width: i32 = @intCast(self.tilemap.width);
|
||||||
|
const height: i32 = @intCast(self.tilemap.height);
|
||||||
|
if (0 <= x and x < width and 0 <= y and y < height) {
|
||||||
|
return &self.tilemap.tiles[@intCast(x + y * width)];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn moveEntity(self: *World, id: Entity.Id, x: i32, y: i32) bool {
|
||||||
|
const e = self.entities.get(id) orelse return false;
|
||||||
|
const destination_tile = self.getTile(x, y) orelse return false;
|
||||||
|
|
||||||
|
if (self.entities.exists(destination_tile.entity)) {
|
||||||
|
// Cna't overwrite entity
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
destination_tile.entity = id;
|
||||||
|
|
||||||
|
if (self.getTile(e.pos_x, e.pos_y)) |tile| {
|
||||||
|
tile.entity = .nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.pos_x = x;
|
||||||
|
e.pos_y = y;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn movePlayer(self: *World, id: Entity.Id, dir_x: i32, dir_y: i32) bool {
|
||||||
|
const e = self.entities.get(id) orelse return false;
|
||||||
|
|
||||||
|
const next_x = e.pos_x+dir_x;
|
||||||
|
const next_y = e.pos_y+dir_y;
|
||||||
|
if (!self.moveEntity(id, next_x, next_y)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
world: World,
|
||||||
|
|
||||||
|
roboto_font: Font,
|
||||||
tilesheet: Tilesheet,
|
tilesheet: Tilesheet,
|
||||||
|
|
||||||
player_sprites: PlayerSprites,
|
player_sprites: PlayerSprites,
|
||||||
@ -167,12 +235,13 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
.tilesheet = tilesheet,
|
.tilesheet = tilesheet,
|
||||||
.footstep_buffer = footstep_sound,
|
.footstep_buffer = footstep_sound,
|
||||||
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
||||||
|
.world = .{
|
||||||
.tilemap = undefined,
|
.tilemap = undefined,
|
||||||
.entities = try .initCapacity(plt.gpa, 256)
|
.entities = try .initCapacity(plt.gpa, 256)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var player_pos_x: i32 = 0;
|
var player_pos: Vec2 = .zero;
|
||||||
var player_pos_y: i32 = 0;
|
|
||||||
{
|
{
|
||||||
var scratch = std.heap.ArenaAllocator.init(plt.gpa);
|
var scratch = std.heap.ArenaAllocator.init(plt.gpa);
|
||||||
defer scratch.deinit();
|
defer scratch.deinit();
|
||||||
@ -190,7 +259,7 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
|
|
||||||
const bounds = tilemap.getTileBounds();
|
const bounds = tilemap.getTileBounds();
|
||||||
|
|
||||||
self.tilemap = try Tilemap.init(plt.gpa, bounds.width(), bounds.height());
|
self.world.tilemap = try Tilemap.init(plt.gpa, bounds.width(), bounds.height());
|
||||||
|
|
||||||
const ground = tilemap.getLayer("Ground").?;
|
const ground = tilemap.getLayer("Ground").?;
|
||||||
const walls = tilemap.getLayer("Walls").?;
|
const walls = tilemap.getLayer("Walls").?;
|
||||||
@ -199,7 +268,7 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
const x = bounds.min_x + ox;
|
const x = bounds.min_x + ox;
|
||||||
const y = bounds.min_y + oy;
|
const y = bounds.min_y + oy;
|
||||||
|
|
||||||
const tile = self.tilemap.get(ox, oy);
|
const tile = self.world.tilemap.get(ox, oy);
|
||||||
|
|
||||||
if (tilemap.getTile(ground, tilesets, x, y)) |tiled_tile| {
|
if (tilemap.getTile(ground, tilesets, x, y)) |tiled_tile| {
|
||||||
const pos = tiled_tile.getPosition();
|
const pos = tiled_tile.getPosition();
|
||||||
@ -208,17 +277,18 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
|
|
||||||
if (tilemap.getTile(walls, tilesets, x, y)) |tiled_tile| {
|
if (tilemap.getTile(walls, tilesets, x, y)) |tiled_tile| {
|
||||||
const pos = tiled_tile.getPosition();
|
const pos = tiled_tile.getPosition();
|
||||||
tile.wall_sprite = tilesheet.get(pos.x, pos.y);
|
const wall_id = try self.world.spawnWall(tilesheet.get(pos.x, pos.y));
|
||||||
|
_ = self.world.moveEntity(wall_id, @intCast(ox), @intCast(oy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const markers = &tilemap.getLayer("Markers").?.variant.object;
|
const markers = &tilemap.getLayer("Markers").?.variant.object;
|
||||||
const spawn = markers.getByName("spawn").?;
|
const spawn = markers.getByName("spawn").?;
|
||||||
player_pos_x = @divFloor(@as(i32, @intFromFloat(spawn.shape.point.x)), @as(i32, @intCast(tilemap.tile_width)));
|
player_pos.x = @divFloor(spawn.shape.point.x, @as(f32, @floatFromInt(tilemap.tile_width)));
|
||||||
player_pos_x -= @intCast(bounds.min_x);
|
player_pos.x -= @floatFromInt(bounds.min_x);
|
||||||
player_pos_y = @divFloor(@as(i32, @intFromFloat(spawn.shape.point.y)),@as(i32, @intCast(tilemap.tile_height)));
|
player_pos.y = @divFloor(spawn.shape.point.y, @as(f32, @floatFromInt(tilemap.tile_height)));
|
||||||
player_pos_y -= @intCast(bounds.min_y);
|
player_pos.y -= @floatFromInt(bounds.min_y);
|
||||||
|
|
||||||
const boxes = tilemap.getLayer("Boxes").?;
|
const boxes = tilemap.getLayer("Boxes").?;
|
||||||
for (0..bounds.height()) |oy| {
|
for (0..bounds.height()) |oy| {
|
||||||
@ -228,35 +298,19 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
|
|
||||||
if (tilemap.getTile(boxes, tilesets, x, y)) |tiled_tile| {
|
if (tilemap.getTile(boxes, tilesets, x, y)) |tiled_tile| {
|
||||||
const pos = tiled_tile.getPosition();
|
const pos = tiled_tile.getPosition();
|
||||||
_ = try self.spawnBox(@intCast(ox), @intCast(oy), tilesheet.get(pos.x, pos.y));
|
const box_id = try self.world.spawnBox(tilesheet.get(pos.x, pos.y));
|
||||||
|
_ = self.world.moveEntity(box_id, @intCast(ox), @intCast(oy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const player_id = try self.spawnPlayer();
|
const player_id = try self.world.spawnPlayer();
|
||||||
const player = self.entities.getAssumeExists(player_id);
|
_ = self.world.moveEntity(player_id, @intFromFloat(player_pos.x), @intFromFloat(player_pos.y));
|
||||||
player.pos_x = player_pos_x;
|
|
||||||
player.pos_y = player_pos_y;
|
|
||||||
|
|
||||||
return null;
|
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 {
|
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||||
const input = plt.input;
|
const input = plt.input;
|
||||||
|
|
||||||
@ -283,32 +337,26 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
|
|
||||||
const tile_size = Vec2.init(48, 48);
|
const tile_size = Vec2.init(48, 48);
|
||||||
var canvas = CanvasScaler{
|
var canvas = CanvasScaler{
|
||||||
.size = Vec2.initFromInt(usize, self.tilemap.width, self.tilemap.height).multiply(tile_size)
|
.size = Vec2.initFromInt(usize, self.world.tilemap.width, self.world.tilemap.height).multiply(tile_size)
|
||||||
};
|
};
|
||||||
canvas.push();
|
canvas.push();
|
||||||
defer canvas.pop(clear_color);
|
defer canvas.pop(clear_color);
|
||||||
|
|
||||||
for (0..self.tilemap.height) |y| {
|
for (0..self.world.tilemap.height) |y| {
|
||||||
for (0..self.tilemap.width) |x| {
|
for (0..self.world.tilemap.width) |x| {
|
||||||
const tile = self.tilemap.get(x, y);
|
const tile = self.world.tilemap.get(x, y);
|
||||||
|
|
||||||
if (tile.ground_sprite) |sprite| {
|
if (tile.ground_sprite) |sprite| {
|
||||||
Gfx.drawSprite(sprite, Vec2.initFromInt(usize, x, y).multiply(tile_size), tile_size, .white);
|
Gfx.drawSprite(sprite, Vec2.initFromInt(usize, x, y).multiply(tile_size), tile_size, .white);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile.wall_sprite) |sprite| {
|
|
||||||
Gfx.drawSprite(sprite, Vec2.initFromInt(usize, x, y).multiply(tile_size), tile_size, .white);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var entity_iter = self.entities.iterator();
|
var entity_iter = self.world.entities.iterator();
|
||||||
while (entity_iter.next()) |entity_id| {
|
while (entity_iter.next()) |entity_id| {
|
||||||
const entity = self.entities.getAssumeExists(entity_id);
|
const entity = self.world.entities.getAssumeExists(entity_id);
|
||||||
if (entity.type == .player) {
|
if (entity.type == .player) {
|
||||||
entity.pos_x += dir_x;
|
if ((dir_x != 0 or dir_y != 0) and self.world.movePlayer(entity_id, dir_x, dir_y)) {
|
||||||
entity.pos_y += dir_y;
|
|
||||||
|
|
||||||
var new_direction = entity.player_direction;
|
var new_direction = entity.player_direction;
|
||||||
if (dir_x < 0) {
|
if (dir_x < 0) {
|
||||||
new_direction = .left;
|
new_direction = .left;
|
||||||
@ -325,6 +373,9 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
entity.player_direction = new_direction;
|
entity.player_direction = new_direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .bus = self.sfx_bus });
|
||||||
|
}
|
||||||
|
|
||||||
const frames = self.player_sprites.getDirection(entity.player_direction);
|
const frames = self.player_sprites.getDirection(entity.player_direction);
|
||||||
|
|
||||||
if (dir_x != 0 or dir_y != 0) {
|
if (dir_x != 0 or dir_y != 0) {
|
||||||
@ -339,35 +390,32 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
entity.player_frame_index = 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];
|
entity.sprite = frames[entity.player_frame_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity.visual_pos = .initFromInt(i32, entity.pos_x, entity.pos_y);
|
||||||
|
|
||||||
if (entity.sprite) |sprite| {
|
if (entity.sprite) |sprite| {
|
||||||
Gfx.drawSprite(
|
Gfx.drawSprite(
|
||||||
sprite,
|
sprite,
|
||||||
Vec2.initFromInt(i32, entity.pos_x, entity.pos_y).multiply(tile_size),
|
entity.visual_pos.multiply(tile_size),
|
||||||
tile_size,
|
tile_size,
|
||||||
.white
|
.white
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.roboto_font.drawText(.{
|
// self.roboto_font.drawText(.{
|
||||||
.text = try std.fmt.allocPrint(plt.frame, "Hello {:.0}!", .{plt.time()}),
|
// .text = try std.fmt.allocPrint(plt.frame, "Hello {:.0}!", .{plt.time()}),
|
||||||
.pos = .init(0, 0),
|
// .pos = .init(0, 0),
|
||||||
.height = 32,
|
// .height = 32,
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
||||||
self.roboto_font.deinit(plt.gpa);
|
self.roboto_font.deinit(plt.gpa);
|
||||||
Gfx.deinitSpritesheet(self.roboto_font.spritesheet);
|
Gfx.deinitSpritesheet(self.roboto_font.spritesheet);
|
||||||
|
|
||||||
self.tilemap.deinit(plt.gpa);
|
self.world.tilemap.deinit(plt.gpa);
|
||||||
self.entities.slots.deinit(plt.gpa);
|
self.world.entities.slots.deinit(plt.gpa);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user