townengine/apps/testgame/world.c

189 lines
5.5 KiB
C
Raw Normal View History

#include "twn_game_api.h"
2024-07-08 00:44:20 +00:00
2024-08-21 13:55:34 +00:00
#include "world.h"
2024-07-08 00:44:20 +00:00
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <tgmath.h>
static void update_tiles(struct World *world) {
2024-07-08 00:44:20 +00:00
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 = (Recti) {
2024-07-08 00:44:20 +00:00
.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 Vec2i to_grid_location(struct World *world, float x, float y) {
return (Vec2i) {
2024-07-08 00:44:20 +00:00
.x = (int)floor(x / (float)world->tile_size),
.y = (int)floor(y / (float)world->tile_size),
};
}
static void drawdef_debug(struct World *world) {
2024-07-08 00:44:20 +00:00
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),
(Color) { 255, 0, 255, 128 });
2024-07-08 00:44:20 +00:00
}
}
struct World *world_create(void) {
struct World *world = cmalloc(sizeof *world);
2024-07-08 00:44:20 +00:00
*world = (struct World) {
2024-07-08 00:44:20 +00:00
.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) {
2024-07-08 00:44:20 +00:00
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) {
2024-07-08 00:44:20 +00:00
for (size_t i = 0; i < world->tilemap_height * world->tilemap_width; ++i) {
if (world->tiles[i].type == TILE_TYPE_VOID)
continue;
2024-07-30 12:30:35 +00:00
m_sprite("/assets/white.png", to_frect(world->tiles[i].rect));
2024-07-08 00:44:20 +00:00
}
drawdef_debug(world);
}
bool world_find_intersect_frect(struct World *world, Rect rect, Rect *intersection) {
2024-07-08 00:44:20 +00:00
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;
Rect tile_frect = {
2024-07-08 00:44:20 +00:00
.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) {
Rect temp;
is_intersecting = overlap_frect(&rect, &tile_frect, &temp);
2024-07-08 00:44:20 +00:00
} else {
is_intersecting = overlap_frect(&rect, &tile_frect, intersection);
2024-07-08 00:44:20 +00:00
}
if (is_intersecting)
break;
}
return is_intersecting;
}
bool world_find_intersect_rect(struct World *world, Recti rect, Recti *intersection) {
2024-07-08 00:44:20 +00:00
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;
Recti *tile_rect = &world->tiles[i].rect;
2024-07-08 00:44:20 +00:00
if (intersection == NULL) {
Recti temp;
is_intersecting = overlap_rect(&rect, tile_rect, &temp);
2024-07-08 00:44:20 +00:00
} else {
is_intersecting = overlap_rect(&rect, tile_rect, intersection);
2024-07-08 00:44:20 +00:00
}
if (is_intersecting)
break;
}
return is_intersecting;
}
bool world_is_tile_at(struct World *world, float x, float y) {
Vec2i position_in_grid = to_grid_location(world, x, y);
2024-07-08 00:44:20 +00:00
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) {
Vec2i position_in_grid = to_grid_location(world, x, y);
2024-07-08 00:44:20 +00:00
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) {
Vec2i position_in_grid = to_grid_location(world, x, y);
2024-07-08 00:44:20 +00:00
world->tilemap[position_in_grid.y][position_in_grid.x] = TILE_TYPE_VOID;
update_tiles(world);
}