189 lines
5.5 KiB
C
189 lines
5.5 KiB
C
#include "townengine/game_api.h"
|
|
|
|
#include "world.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <tgmath.h>
|
|
|
|
|
|
static void update_tiles(struct world *world) {
|
|
for (size_t row = 0; row < world->tilemap_height; ++row) {
|
|
for (size_t col = 0; col < world->tilemap_width; ++col) {
|
|
world->tiles[(row * world->tilemap_width) + col] = (struct tile) {
|
|
.rect = (t_rect) {
|
|
.x = (int)col * world->tile_size,
|
|
.y = (int)row * world->tile_size,
|
|
.w = world->tile_size,
|
|
.h = world->tile_size,
|
|
},
|
|
.type = world->tilemap[row][col],
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static t_vec2 to_grid_location(struct world *world, float x, float y) {
|
|
return (t_vec2) {
|
|
.x = (int)floor(x / (float)world->tile_size),
|
|
.y = (int)floor(y / (float)world->tile_size),
|
|
};
|
|
}
|
|
|
|
|
|
static void drawdef_debug(struct world *world) {
|
|
if (!ctx.debug) return;
|
|
|
|
for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) {
|
|
if (world->tiles[i].type == TILE_TYPE_VOID) continue;
|
|
|
|
push_rectangle(to_frect(world->tiles[i].rect),
|
|
(t_color) { 255, 0, 255, 128 });
|
|
}
|
|
}
|
|
|
|
|
|
struct world *world_create(void) {
|
|
struct world *world = cmalloc(sizeof *world);
|
|
|
|
*world = (struct world) {
|
|
.tiles = NULL,
|
|
.tile_size = 42,
|
|
.tilemap_width = 20,
|
|
.tilemap_height = 12,
|
|
.gravity = 1,
|
|
};
|
|
|
|
/* create the tilemap */
|
|
/* it simply stores what's in each tile as a 2d array */
|
|
/* on its own, it's entirely unrelated to drawing or logic */
|
|
world->tilemap = cmalloc(sizeof *world->tilemap * world->tilemap_height);
|
|
for (size_t i = 0; i < world->tilemap_height; ++i) {
|
|
world->tilemap[i] = cmalloc(sizeof **world->tilemap * world->tilemap_width);
|
|
|
|
for (size_t j = 0; j < world->tilemap_width; ++j) {
|
|
world->tilemap[i][j] = TILE_TYPE_VOID;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < 12; ++i) {
|
|
world->tilemap[world->tilemap_height-2][2+i] = TILE_TYPE_SOLID;
|
|
}
|
|
world->tilemap[world->tilemap_height-3][8] = TILE_TYPE_SOLID;
|
|
world->tilemap[world->tilemap_height-4][8] = TILE_TYPE_SOLID;
|
|
world->tilemap[world->tilemap_height-5][10] = TILE_TYPE_SOLID;
|
|
world->tilemap[world->tilemap_height-6][10] = TILE_TYPE_SOLID;
|
|
for (size_t i = 0; i < 7; ++i) {
|
|
world->tilemap[world->tilemap_height-6][12+i] = TILE_TYPE_SOLID;
|
|
}
|
|
|
|
/* the tiles array contains data meant to be used by other logic */
|
|
/* most importantly, it is used to draw the tiles */
|
|
const size_t tile_count = world->tilemap_height * world->tilemap_width;
|
|
world->tiles = cmalloc(sizeof *world->tiles * tile_count);
|
|
update_tiles(world);
|
|
|
|
return world;
|
|
}
|
|
|
|
|
|
void world_destroy(struct world *world) {
|
|
free(world->tiles);
|
|
|
|
for (size_t i = 0; i < world->tilemap_height; ++i) {
|
|
free(world->tilemap[i]);
|
|
}
|
|
free(world->tilemap);
|
|
|
|
free(world);
|
|
}
|
|
|
|
|
|
void world_drawdef(struct world *world) {
|
|
for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) {
|
|
if (world->tiles[i].type == TILE_TYPE_VOID)
|
|
continue;
|
|
|
|
m_sprite("/assets/white.png", to_frect(world->tiles[i].rect));
|
|
}
|
|
|
|
drawdef_debug(world);
|
|
}
|
|
|
|
|
|
bool world_find_intersect_frect(struct world *world, t_frect rect, t_frect *intersection) {
|
|
bool is_intersecting = false;
|
|
|
|
const size_t tile_count = world->tilemap_height * world->tilemap_width;
|
|
for (size_t i = 0; i < tile_count; ++i) {
|
|
if (world->tiles[i].type == TILE_TYPE_VOID)
|
|
continue;
|
|
|
|
t_frect tile_frect = {
|
|
.x = (float)(world->tiles[i].rect.x),
|
|
.y = (float)(world->tiles[i].rect.y),
|
|
.w = (float)(world->tiles[i].rect.w),
|
|
.h = (float)(world->tiles[i].rect.h),
|
|
};
|
|
|
|
if (intersection == NULL) {
|
|
t_frect temp;
|
|
is_intersecting = intersect_frect(&rect, &tile_frect, &temp);
|
|
} else {
|
|
is_intersecting = intersect_frect(&rect, &tile_frect, intersection);
|
|
}
|
|
|
|
if (is_intersecting)
|
|
break;
|
|
}
|
|
|
|
return is_intersecting;
|
|
}
|
|
|
|
|
|
bool world_find_intersect_rect(struct world *world, t_rect rect, t_rect *intersection) {
|
|
bool is_intersecting = false;
|
|
|
|
const size_t tile_count = world->tilemap_height * world->tilemap_width;
|
|
for (size_t i = 0; i < tile_count; ++i) {
|
|
if (world->tiles[i].type == TILE_TYPE_VOID)
|
|
continue;
|
|
|
|
t_rect *tile_rect = &world->tiles[i].rect;
|
|
|
|
if (intersection == NULL) {
|
|
t_rect temp;
|
|
is_intersecting = intersect_rect(&rect, tile_rect, &temp);
|
|
} else {
|
|
is_intersecting = intersect_rect(&rect, tile_rect, intersection);
|
|
}
|
|
|
|
if (is_intersecting)
|
|
break;
|
|
}
|
|
|
|
return is_intersecting;
|
|
}
|
|
|
|
|
|
bool world_is_tile_at(struct world *world, float x, float y) {
|
|
t_vec2 position_in_grid = to_grid_location(world, x, y);
|
|
return world->tilemap[position_in_grid.y][position_in_grid.x] != TILE_TYPE_VOID;
|
|
}
|
|
|
|
|
|
void world_place_tile(struct world *world, float x, float y) {
|
|
t_vec2 position_in_grid = to_grid_location(world, x, y);
|
|
world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_SOLID;
|
|
update_tiles(world);
|
|
}
|
|
|
|
|
|
void world_remove_tile(struct world *world, float x, float y) {
|
|
t_vec2 position_in_grid = to_grid_location(world, x, y);
|
|
world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_VOID;
|
|
update_tiles(world);
|
|
}
|