#include "map/map.hpp" #include #include #include #include #include "building/building_data.hpp" #include "resource/resource.hpp" #include "building/building.hpp" #include "game/game.hpp" #include "farm/farm.hpp" #include "bird/bird.hpp" namespace Map { // save_MapTiles std::string save_path = "saves/save.map"; std::string save_collission_path = "saves/save.collissions"; bool setting_offset = false; SDL_Point offset_to_set = {0, 0}; SDL_Point offset = {0, 0}; SDL_Point size = {160, 100}; // map size in tiles... SDL_Point boundaries = {63, 39}; // JEee fucked up the size, // to much work to resize (i have an outer cage which fucks the path finding) std::vector tile_map; std::vector tile_collission_map; int frame_water = 0; float global_frame_time = 0.0f; float global_frame_time_max = 0.6f; int frame_meadow = 0; float frame_meadow_time = 0.0f; float frame_meadow_time_max = 0.6f; void Init() { tile_map.resize(static_cast(Map::size.x * Map::size.y)); for (int y = 0; y < Map::size.y; ++y) { for (int x = 0; x < Map::size.x; ++x) { bool is_border = (x == 0) || (y == 0) || (x == Map::size.x - 1) || (y == Map::size.y - 1); size_t index = static_cast(y * Map::size.x + x); tile_map[index].background = { 0, SIZE_MAX, TILE_GROUND, {is_border ? 17 : 0, 0} }; //tile_map[index].overlay = { SIZE_MAX, SIZE_MAX, TILE_OVERLAY_CHARACTER, {0, 0} }; } } } void init_Collider() { tile_collission_map.clear(); // init map_colliders const size_t cells_per_tile_map = (Tile::tile_size / Tile::tile_collider_size)*(Tile::tile_size / Tile::tile_collider_size); for (size_t i = 0; i < tile_map.size(); i++) { for (size_t j = 0; j < cells_per_tile_map; j++) tile_collission_map.push_back(false); } } void Reset() { tile_map.clear(); Init(); init_Collider(); } void set_CollisionForTile(const TileMap &tile_map_item, size_t map_tile_x, size_t map_tile_y) { const size_t cells_per_tile = Tile::tile_size / Tile::tile_collider_size; const size_t map_width_cells = static_cast(Map::size.x) * cells_per_tile; const Tile_s &tile = tile_map_item.background; const SDL_Point position = tile.set_position; const TileSet &tileset = Tile::get_TilesetFromMapTile(tile); const size_t ts_width = static_cast(tileset.size.x) * cells_per_tile; size_t map_cell_origin_x = map_tile_x * cells_per_tile; size_t map_cell_origin_y = map_tile_y * cells_per_tile; for (size_t y = 0; y < cells_per_tile; ++y) { for (size_t x = 0; x < cells_per_tile; ++x) { size_t ts_index = (static_cast(position.y) * cells_per_tile + y) * ts_width + (static_cast(position.x) * cells_per_tile + x); if (ts_index >= tileset.collission_map.size()) continue; size_t map_x = map_cell_origin_x + x; size_t map_y = map_cell_origin_y + y; size_t map_index = map_y * map_width_cells + map_x; if (map_index < tile_collission_map.size()) tile_collission_map[map_index] = tileset.collission_map[ts_index]; } } } void set_CollissionFromTileset() { for (int tile_index = 0; tile_index < static_cast(tile_map.size()); ++tile_index) { int map_tile_x = tile_index % Map::size.x; int map_tile_y = tile_index / Map::size.x; set_TileCollissionForObjects({map_tile_x, map_tile_y}); } } void set_ObjectCollisionOnTilemap(size_t object_id, SDL_Point map_tile) { Object* object = Object::get_ObjectById(object_id); object->print_CollisionMap(); const std::vector& collision_map = object->get_CollisionMap(); const size_t scale = Tile::tile_size / Tile::tile_collider_size; const size_t obj_cols = static_cast(object->dimension.x) * scale; const size_t obj_rows = static_cast(object->dimension.y) * scale; std::cout << "DIM: " << object->dimension.x << " " << object->dimension.y << std::endl; std::cout << "COL: " << obj_cols << " " << obj_rows << std::endl; const size_t base_x = static_cast(map_tile.x) * scale; const size_t base_y = static_cast(map_tile.y) * scale; std::cout << "BAS: " << base_x << " " << base_y << std::endl; const size_t map_cols = static_cast(Map::size.x) * scale; for (size_t oy = 0; oy < obj_rows; ++oy) { for (size_t ox = 0; ox < obj_cols; ++ox) { const size_t obj_idx = oy * obj_cols + ox; if (collision_map[obj_idx]) { const size_t mx = base_x + ox; const size_t my = base_y + oy; const size_t map_idx = my * map_cols + mx; std::cout << "COL: " << mx << " " << my << " " << map_idx << std::endl; Map::tile_collission_map[map_idx] = true; } } } } void set_TileCollissionForObjects(SDL_Point map_tile) { const size_t tile_index = static_cast(map_tile.y * Map::size.x + map_tile.x); const size_t scale = Tile::tile_size / Tile::tile_collider_size; const size_t start_y = static_cast(map_tile.y)* scale; const size_t start_x = static_cast(map_tile.x)* scale; const size_t map_cols = static_cast(Map::size.x) * scale; const TileMap &tile_map_item = tile_map[tile_index]; // reset collisions for this tile set_CollisionForTile(tile_map_item, static_cast(map_tile.x), static_cast(map_tile.y)); // merge collisions from all objects on the tile for (const TileObject& to : tile_map[tile_index].objects) { Object* object = Object::get_ObjectById(to.object_id); const std::vector collision_map = object->get_CollissionsOfTile(to.position); for (size_t oy = 0; oy < scale; ++oy) { for (size_t ox = 0; ox < scale; ++ox) { const size_t tile_cell = oy * scale + ox; if (collision_map[tile_cell]) { const size_t map_idx = (start_y + oy) * map_cols + (start_x + ox); Map::tile_collission_map[map_idx] = true; } } } } } void save_TileCollision(const std::string &path) { std::ofstream out(path, std::ios::binary); if (!out) { std::cerr << "Failed to open file for writing: " << path << '\n'; return; } out.write(reinterpret_cast(&Map::size.x), sizeof(Map::size.x)); out.write(reinterpret_cast(&Map::size.y), sizeof(Map::size.y)); // Write the size first size_t size = tile_collission_map.size(); out.write(reinterpret_cast(&size), sizeof(size)); // Write each bool as a byte for (bool value : tile_collission_map) { uint8_t byte = value ? 1 : 0; out.write(reinterpret_cast(&byte), sizeof(byte)); } std::cout << "Saved " << size << " collision cells to " << path << '\n'; } void load_TileCollision(const std::string &path) { std::ifstream in(path, std::ios::binary); if (!in) { std::cerr << "Failed to open file for reading: " << path << '\n'; return; } int map_tilesize_x; int map_tilesize_y; in.read(reinterpret_cast(&map_tilesize_x), sizeof(map_tilesize_x)); in.read(reinterpret_cast(&map_tilesize_y), sizeof(map_tilesize_y)); std::cout << "WUU " << map_tilesize_x << " " << map_tilesize_y<< std::endl; // Read the size size_t size = 0; in.read(reinterpret_cast(&size), sizeof(size)); if (!in) { std::cerr << "Failed to read size from file: " << path << '\n'; return; } // Resize and read data std::vector temp(size); const size_t w = static_cast(Map::size.x); const size_t h = static_cast(Map::size.y); const size_t m = Tile::tile_size/Tile::tile_collider_size; Map::tile_collission_map.assign(w * h * m * m, false); for (size_t i = 0; i < size; ++i) { uint8_t byte = 0; in.read(reinterpret_cast(&byte), sizeof(byte)); temp[i] = (byte != 0); size_t x = i% static_cast(map_tilesize_x); size_t y = i/ static_cast(map_tilesize_x); Map::tile_collission_map[y*static_cast(Map::size.x)+x] = temp[i]; } if (!in) { std::cerr << "File corrupted or incomplete: " << path << '\n'; return; } //Map::tile_collission_map = std::move(temp); std::cout << "Loaded " << size << " collision cells from " << path << '\n'; } void save_MapTiles(const std::vector& tile_map, const std::string& path) { std::ofstream file(path, std::ios::binary); if (!file.is_open()) return; size_t map_count = tile_map.size(); file.write(reinterpret_cast(&map_count), sizeof(map_count)); size_t id = 0; for (const auto& map : tile_map) { // --- background --- size_t map_tile_x = id % static_cast(Map::size.x); size_t map_tile_y = id / static_cast(Map::size.x); file.write(reinterpret_cast(&map_tile_x), sizeof(map_tile_x)); file.write(reinterpret_cast(&map_tile_y), sizeof(map_tile_y)); file.write(reinterpret_cast(&map.background.set_id), sizeof(map.background.set_id)); file.write(reinterpret_cast(&map.background.object_id), sizeof(map.background.object_id)); file.write(reinterpret_cast(&map.background.set_category), sizeof(map.background.set_category)); file.write(reinterpret_cast(&map.background.set_position), sizeof(map.background.set_position)); // --- overlays --- const std::size_t overlay_count = map.overlays.size(); file.write(reinterpret_cast(&overlay_count), sizeof(overlay_count)); for (const Tile_s& ov : map.overlays) { file.write(reinterpret_cast(&ov.set_id), sizeof(ov.set_id)); file.write(reinterpret_cast(&ov.object_id), sizeof(ov.object_id)); file.write(reinterpret_cast(&ov.set_category), sizeof(ov.set_category)); file.write(reinterpret_cast(&ov.set_position), sizeof(ov.set_position)); } // --- objects --- size_t obj_count = map.objects.size(); file.write(reinterpret_cast(&obj_count), sizeof(obj_count)); for (const auto& obj : map.objects) { Object* o = Object::get_ObjectById(obj.object_id); // TilesetObject file.write(reinterpret_cast(&obj.position.x), sizeof(obj.position.x)); file.write(reinterpret_cast(&obj.position.y), sizeof(obj.position.y)); file.write(reinterpret_cast(&o->dimension.x), sizeof(o->dimension.x)); file.write(reinterpret_cast(&o->dimension.y), sizeof(o->dimension.y)); file.write(reinterpret_cast(&obj.draw_from_this_tile), sizeof(obj.draw_from_this_tile)); auto object_type = static_cast(o->object_type); auto category = static_cast(o->category); file.write(reinterpret_cast(&object_type), sizeof(object_type)); file.write(reinterpret_cast(&category), sizeof(category)); // im getting tile_type on load int tileset_type = static_cast(o->tileset_type); file.write(reinterpret_cast(&tileset_type), sizeof(tileset_type)); file.write(reinterpret_cast(&o->tileset_id), sizeof(o->tileset_id)); file.write(reinterpret_cast(&o->tileset_object_id), sizeof(o->tileset_object_id)); file.write(reinterpret_cast(&o->z_index), sizeof(o->z_index)); if (o->category == ObjectCategory::BUILDING) { Building* b = static_cast(o); auto type = static_cast(b->building_type); auto status = static_cast(b->building_status); file.write(reinterpret_cast(&type), sizeof(type)); file.write(reinterpret_cast(&status), sizeof(status)); file.write(reinterpret_cast(&b->building_time), sizeof(b->building_time)); size_t cost_count = b->cost_fulfilled.size(); file.write(reinterpret_cast(&cost_count), sizeof(cost_count)); for (auto& p : b->cost_fulfilled) { auto r = static_cast(p.first); file.write(reinterpret_cast(&r), sizeof(r)); file.write(reinterpret_cast(&p.second), sizeof(p.second)); } size_t frac_count = b->fractional_buffer.size(); file.write(reinterpret_cast(&frac_count), sizeof(frac_count)); for (auto& p : b->fractional_buffer) { auto r = static_cast(p.first); file.write(reinterpret_cast(&r), sizeof(r)); file.write(reinterpret_cast(&p.second), sizeof(p.second)); } } else if (o->category == ObjectCategory::FARM_CROP) { Vegetable* v = static_cast(o); auto type = static_cast(v->type); file.write(reinterpret_cast(&type), sizeof(type)); file.write(reinterpret_cast(&v->is_seed), sizeof(v->is_seed)); file.write(reinterpret_cast(&v->quantity), sizeof(v->quantity)); file.write(reinterpret_cast(&v->growth_stage), sizeof(v->growth_stage)); file.write(reinterpret_cast(&v->next_update_sec), sizeof(v->next_update_sec)); file.write(reinterpret_cast(&v->collecting_duration_max), sizeof(v->collecting_duration_max)); file.write(reinterpret_cast(&v->tileset_object_x), sizeof(v->tileset_object_x)); file.write(reinterpret_cast(&v->tileset_object_y), sizeof(v->tileset_object_y)); auto slot = static_cast(v->equipement_slot); file.write(reinterpret_cast(&slot), sizeof(slot)); } } id++; } } std::vector load_MapTiles(const std::string& path) { std::vector tile_map; std::ifstream file(path, std::ios::binary); if (!file.is_open()) return tile_map; size_t map_count = 0; file.read(reinterpret_cast(&map_count), sizeof(map_count)); tile_map.resize(static_cast(Map::size.y*Map::size.x)); for (size_t id = 0; id < map_count; id++) { //int x = i % static_cast(Map::size.x); //int y = i / static_cast(Map::size.x); size_t x; size_t y; file.read(reinterpret_cast(&x), sizeof(x)); file.read(reinterpret_cast(&y), sizeof(y)); auto& map = tile_map[y*static_cast(Map::size.x)+x]; // --- background --- file.read(reinterpret_cast(&map.background.set_id), sizeof(map.background.set_id)); file.read(reinterpret_cast(&map.background.object_id), sizeof(map.background.object_id)); file.read(reinterpret_cast(&map.background.set_category), sizeof(map.background.set_category)); file.read(reinterpret_cast(&map.background.set_position), sizeof(map.background.set_position)); // --- overlays --- std::size_t overlay_count = 0; file.read(reinterpret_cast(&overlay_count), sizeof(overlay_count)); map.overlays.clear(); map.overlays.resize(overlay_count); for (std::size_t i = 0; i < overlay_count; ++i) { Tile_s& ov = map.overlays[i]; file.read(reinterpret_cast(&ov.set_id), sizeof(ov.set_id)); file.read(reinterpret_cast(&ov.object_id), sizeof(ov.object_id)); file.read(reinterpret_cast(&ov.set_category), sizeof(ov.set_category)); file.read(reinterpret_cast(&ov.set_position), sizeof(ov.set_position)); } TileSet& tileset = Tile::get_TilesetFromMapTile(map.background); map.background.object_id = static_cast(map.background.set_position.y*tileset.size.x + map.background.set_position.x); map.background.set_category = Tile::tilesets[TILE_BACKGROUND][map.background.set_id].category; // std::cout << "SCM: " << map.background.set_id << " " << map.background.object_id<< std::endl; // --- objects --- size_t obj_count = 0; file.read(reinterpret_cast(&obj_count), sizeof(obj_count)); map.objects.resize(obj_count); for (auto& map_object : map.objects) { TilesetObject obj; // TilesetObject file.read(reinterpret_cast(&obj.position.x), sizeof(obj.position.x)); file.read(reinterpret_cast(&obj.position.y), sizeof(obj.position.y)); file.read(reinterpret_cast(&obj.position.w), sizeof(obj.position.w)); file.read(reinterpret_cast(&obj.position.h), sizeof(obj.position.h)); file.read(reinterpret_cast(&obj.draw_from_this_tile), sizeof(obj.draw_from_this_tile)); int object_type; file.read(reinterpret_cast(&object_type), sizeof(object_type)); int cat_i; file.read(reinterpret_cast(&cat_i), sizeof(cat_i)); ObjectCategory category = static_cast(cat_i); int tt; file.read(reinterpret_cast(&tt), sizeof(tt)); TileType tileset_type = static_cast(tt); file.read(reinterpret_cast(&obj.tileset_info.set_id), sizeof(obj.tileset_info.set_id)); file.read(reinterpret_cast(&obj.tileset_info.object_id), sizeof(obj.tileset_info.object_id)); file.read(reinterpret_cast(&obj.z_index), sizeof(obj.z_index)); // SET DATA TO REAL OBJECT AND MAP OBJECT SDL_Point wp = {static_cast(x)-obj.position.x, static_cast(y)-obj.position.y}; Object* o = Object::get_ObjectByWorldPositionAndTilesetObjectID(wp, obj.tileset_info.object_id); Object* on = nullptr; SDL_Point dim = {obj.position.w, obj.position.h}; switch (category) { case ObjectCategory::STATIC: { on = new Static( static_cast(object_type), ObjectCategory::STATIC, tileset_type, obj.tileset_info.set_id, obj.tileset_info.object_id, wp, dim, obj.z_index); break; } case ObjectCategory::RESOURCE: { Resource_s r = Tile::get_ResourceFromTileSet( obj.tileset_info.set_id, obj.tileset_info.object_id); on = new Resource( static_cast(object_type), ObjectCategory::RESOURCE, tileset_type, obj.tileset_info.set_id, obj.tileset_info.object_id, wp, dim, obj.z_index, r.resource, r.quantity, r.collecting_methode, r.collecting_duration); break; } case ObjectCategory::BUILDING: { int bt_i; file.read(reinterpret_cast(&bt_i), sizeof(bt_i)); BuildingType bt = static_cast(bt_i); int status_i; file.read(reinterpret_cast(&status_i), sizeof(status_i)); BuildingStatus status = static_cast(status_i); float time; file.read(reinterpret_cast(&time), sizeof(time)); size_t cost_count; file.read(reinterpret_cast(&cost_count), sizeof(cost_count)); std::unordered_map cost_f; for (size_t i = 0; i < cost_count; ++i) { int r, v; file.read(reinterpret_cast(&r), sizeof(r)); file.read(reinterpret_cast(&v), sizeof(v)); cost_f[static_cast(r)] = v; } size_t frac_count; file.read(reinterpret_cast(&frac_count), sizeof(frac_count)); std::unordered_map frac_b; for (size_t i = 0; i < frac_count; ++i) { int r; float v; file.read(reinterpret_cast(&r), sizeof(r)); file.read(reinterpret_cast(&v), sizeof(v)); frac_b[static_cast(r)] = v; } on = new Building( static_cast(object_type), ObjectCategory::BUILDING, tileset_type, obj.tileset_info.set_id, obj.tileset_info.object_id, wp, dim, obj.z_index, bt); Building* b = static_cast(on); b->building_status = status; b->building_time = time; b->cost_fulfilled = std::move(cost_f); b->fractional_buffer = std::move(frac_b); break; } case ObjectCategory::FARM_CROP: { int type_i; bool is_seed; file.read(reinterpret_cast(&type_i), sizeof(type_i)); file.read(reinterpret_cast(&is_seed), sizeof(is_seed)); Vegetable* v = new Vegetable(static_cast(type_i), wp, is_seed); file.read(reinterpret_cast(&v->quantity), sizeof(v->quantity)); file.read(reinterpret_cast(&v->growth_stage), sizeof(v->growth_stage)); file.read(reinterpret_cast(&v->next_update_sec), sizeof(v->next_update_sec)); file.read(reinterpret_cast(&v->collecting_duration_max), sizeof(v->collecting_duration_max)); file.read(reinterpret_cast(&v->tileset_object_x), sizeof(v->tileset_object_x)); file.read(reinterpret_cast(&v->tileset_object_y), sizeof(v->tileset_object_y)); int slot; file.read(reinterpret_cast(&slot), sizeof(slot)); v->equipement_slot = static_cast(slot); on = v; break; } default: break; } if (!o && on) { Object::objects.push_back(on); o = on; } /* std::cout << "OP: " << obj.position.x << " " << obj.position.y << " ID " << o->id << std::endl; std::cout << "WP " << wp.x << " " << wp.y << std::endl; std::cout << "DM: " << obj.position.w << " " << obj.position.h << " ID " << obj.tileset_info.object_id << std::endl; */ map_object = {{obj.position.x, obj.position.y}, obj.draw_from_this_tile, o ? o->id : 0}; } } return tile_map; } inline bool isInView(float x, float y, float w, float h, const SDL_Rect &win) { return !(x + w < 0 || y + h < 0 || x > win.w || y > win.h); } inline int waveFrame( float t, int x_i, int y_i, int frame_count, float speed = 1.8f) { float wave = sinf(t * speed + x_i * 0.4f + y_i * 0.6f) + sinf(t * speed * 0.66f - x_i * 0.7f + y_i * 0.3f) * 0.5f; wave *= (1.0f / 1.5f); float scaled = (wave + 1.0f) * (frame_count * 0.5f); int frame = (int)scaled; if (frame < 0) frame = 0; if (frame >= frame_count) frame = frame_count - 1; return frame; } void draw_MapTiles(Game* game) { // std::cout << "FL " << Map::offset.x << " " << Map::offset.y << " " << Default::game_scale << std::endl; SDL_Renderer* renderer = game->renderer; Character& player = *game->state_playing->player; SDL_Rect win_size = game->win_size; float view_x0 = -Map::offset.x; float view_y0 = -Map::offset.y; float view_x1 = view_x0 + win_size.w / Scale(1.f); float view_y1 = view_y0 + win_size.h / Scale(1.f); int size = Tile::get_Size(); global_frame_time += Default::delta_time; /* if (global_frame_time >= global_frame_time_max) { frame_water = frame_water > 0 ? frame_water-1 : 3; global_frame_time = 0.0f; if (frame_water == 0) global_frame_time_max = 0.3f + ((float)rand() / (float)RAND_MAX) * 1.2f; //std::cout << "global_frame_time_max: " << global_frame_time_max << std::endl; } */ frame_meadow_time += Default::delta_time; if (frame_meadow_time >= frame_meadow_time_max) { frame_meadow++; frame_meadow %= 3; frame_meadow_time = 0.0f; if (frame_meadow == 0) frame_meadow_time_max = 1.4f + ((float)rand() / (float)RAND_MAX) * 2.3f; //std::cout << "frame_meadow_time_max: " << frame_meadow_time_max << std::endl; } for (size_t i = 0; i < Map::tile_map.size(); ++i) { // START draw background tiles Tile_s& tile = Map::tile_map[i].background; int x_i = i % static_cast(Map::size.x); int y_i = i / static_cast(Map::size.x); float world_x = x_i * size; float world_y = y_i * size; float world_x2 = world_x + size; float world_y2 = world_y + size; // CULL TILE IF OUTSIDE CAMERA if (world_x2 < view_x0 || world_x > view_x1 || world_y2 < view_y0 || world_y > view_y1) continue; float xf = world_x + Map::offset.x; float yf = world_y + Map::offset.y; SDL_FRect dst { Scale(xf), Scale(yf), Scale(size), Scale(size) }; SDL_Point set_position = tile.set_position; if (tile.set_category == TileCategory::TILE_WATER && set_position.y < 5) { float local_speed = 1.8f * (0.8f + 0.4f * sinf(x_i*0.3f + y_i*0.5f)); int frame = waveFrame(global_frame_time, x_i, y_i, 4, local_speed); set_position.x += frame * 6; } else if (tile.set_category == TileCategory::TILE_GROUND && set_position.y == 10) { float local_speed = 1.5f * (0.85f + 0.3f * sinf(x_i*0.25f + y_i*0.35f)); int frame = waveFrame(global_frame_time, x_i, y_i, 3, local_speed); set_position.x += frame; } SDL_FRect src { static_cast(set_position.x) * Tile::tile_size, static_cast(set_position.y) * Tile::tile_size, (float)Tile::tile_size, (float)Tile::tile_size }; SDL_RenderTexture(renderer, Tile::tilesets[TILE_BACKGROUND][tile.set_id].texture, &src, &dst); for (Tile_s& overlay : Map::tile_map[i].overlays) { if (overlay.set_category == TileCategory::TILE_OVERLAY_FARM) { Farm::soil_Render(renderer, {xf, yf}, overlay.set_position); } } // END draw background tiles } draw_ObjectTiles(renderer, player, win_size); // if (Default::game_state == GAME_PLAY) return; if (Default::modify_state == MODIFY_COLLISSION) { size_t selection_size = Tile::get_SelectionSize(Default::modify_state); const float cell_size = static_cast(selection_size); size_t map_width = static_cast(Map::size.x)*(Tile::tile_size/Tile::tile_collider_size); size_t map_height = static_cast(Map::size.y)*(Tile::tile_size/Tile::tile_collider_size); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(renderer, 255, 0, 0, 100); for (size_t y = 0; y < map_height; ++y) { for (size_t x = 0; x < map_width; ++x) { size_t index = y * map_width + x; if (!Map::tile_collission_map[index]) continue; SDL_FRect cell_rect = { Scale(x * cell_size + Map::offset.x), Scale(y * cell_size + Map::offset.y), Scale(cell_size), Scale(cell_size) }; // draw cell outline SDL_RenderRect(renderer, &cell_rect); // draw cross SDL_RenderLine(renderer, cell_rect.x, cell_rect.y, cell_rect.x + cell_rect.w, cell_rect.y + cell_rect.h); SDL_RenderLine(renderer, cell_rect.x + cell_rect.w, cell_rect.y, cell_rect.x, cell_rect.y + cell_rect.h); } } } } void draw_SelectionBorder(SDL_Renderer* renderer, Input& input) { // START render selecting border bool cursor_over_tile = Tile::hovering_set; if (cursor_over_tile) return; int selection_size = Tile::get_SelectionSize(Default::modify_state); SDL_FRect tile_rect { Scale(input.mouse_tile_position.x * selection_size + Map::offset.x), Scale(input.mouse_tile_position.y * selection_size + Map::offset.y), Scale(selection_size) * Tile::selection_tile_dimension.x, Scale(selection_size) * Tile::selection_tile_dimension.y }; SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); SDL_RenderRect(renderer, &tile_rect); // END render selecting border } void draw_ObjectTiles(SDL_Renderer* renderer, Character& player, SDL_Rect win_size) { int size = Tile::get_Size(); std::vector enemies_drawn(Enemy::enemies.size(), false); // draw objects and character bool character_drawn = false; bool player_behind = false; float character_collider_x = player.collider_world.x; // - player.collider.w*0.5; float character_collider_y = player.collider_world.y; // - player.collider.h*0.5; for (Bird* bird : Bird::birds) bird->drawn = false; for (size_t i = 0; i < Map::tile_map.size(); ++i) { TileMap& tilemap = Map::tile_map[i]; int x_i = i % static_cast(Map::size.x); int y_i = i / static_cast(Map::size.x); float xf = (x_i * size); float yf = (y_i * size); SDL_FPoint xy_point = {xf+size, yf+size}; // Render Character if no object is hiding it player_behind = false; for (TileObject& o : tilemap.objects) { Object* object = Object::get_ObjectById(o.object_id); // o = relative position, // so can be 0 0, 0 1, 1 0, 1 1 if object size is 2 2 #ifdef DEBUG_BUILD // START DEBUG RECT SDL_FRect dbg = { Scale(xf + Map::offset.x), Scale(yf + Map::offset.y), Scale(size), Scale(size)}; SDL_FRect dbg_rect = dbg; SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderRect(renderer, &dbg_rect); // START DEBUG RECT #endif //if (o.position.x != 0 || o.position.y != o.position.h-1) continue; // real object 0,0 start in map pixel float m_xf = xf - o.position.x*size; float m_yf = yf - o.position.y*size; float width = static_cast(object->dimension.x) * size; float height = static_cast(object->dimension.y) * size; SDL_FPoint m_point = {m_xf+width, m_yf+height}; SDL_FRect obj_bb { Scale(m_xf + Map::offset.x), Scale(m_yf + Map::offset.y), Scale(width), Scale(height) }; if (!isInView(obj_bb.x, obj_bb.y, obj_bb.w, obj_bb.h, win_size)) continue; //if (!o.draw_from_this_tile) continue; size_t j = 0; //std::cout << "PS "<< o.position.x<< " " <(enemy->collider_world.x), static_cast(enemy->collider_world.y), }; if (!isInView(enemy_bb.x, enemy_bb.y, enemy->collider.w, enemy->collider.h, win_size)) { j++; continue; } if ( !enemies_drawn[j] && (enemy->stats.health <= 0 || (enemy_bb.x >= m_xf && enemy_bb.y >= m_yf && enemy_bb.x + enemy->collider.w <= m_point.x && enemy_bb.y <= m_point.y && object->z_index > 0 ))) { if ( enemy->stats.health <= 0 || object->is_InFrontOf({m_xf, m_yf}, {enemy_bb.x, enemy_bb.y, enemy->collider.w, enemy->collider.h})) { enemy->Draw(renderer); enemies_drawn[j] = true; } } j++; } player_behind = false; int am_i_behind_an_object = object->is_InFrontOf({m_xf, m_yf}, {character_collider_x, character_collider_y, player.collider.w, player.collider.h}); if (am_i_behind_an_object) { if ( am_i_behind_an_object == 1 && character_collider_y-player.height/3 > m_yf && ( player.collider_world.x > m_xf || player.collider_world.x < m_xf+object->dimension.x ) ) player_behind = true; if (!character_drawn) { //std::cout << "DRAW BEHIND\n"; player.Draw(renderer); character_drawn = true; } } for (Bird* bird : Bird::birds) { if (bird->drawn) continue; if ( static_cast(bird->pos_x/Tile::tile_size) != x_i || static_cast((bird->pos_y-bird->altitude)/Tile::tile_size) != y_i) continue; bird->Render(renderer); // std::cout << "I AM GETTING CALLED BIRD AMP " << bird->pos_y << " " << bird->altitude << std::endl; bird->drawn = true; } //std::cout << player_behind << std::endl; //std::cout << "CHA: " << character_collider_x << " " << character_collider_y << " " << player.collider.w << " " << player.collider.h << std::endl; //std::cout << "OJJ: " << m_xf << " " << m_yf << " " << m_point.x << " " << m_point.y << std::endl; // START OBJECT DRAW if (o.draw_from_this_tile) object->Draw(renderer, {m_xf, m_yf}, player_behind); // END OBJECT DRAW } size_t j = 0; if ( !character_drawn && player.collider_world.x >= xf && player.collider_world.x <= xy_point.x && player.collider_world.y >= yf && player.collider_world.y <= xy_point.y) { player.Draw(renderer); character_drawn = true; } for (Enemy* enemy : Enemy::enemies) { if ( !enemies_drawn[j] && enemy->stats.health > 0 && enemy->collider_world.x >= xf && enemy->collider_world.x <= xy_point.x && enemy->collider_world.y >= yf && enemy->collider_world.y <= xy_point.y) { enemy->Draw(renderer); enemies_drawn[j] = true; } j++; } } for (Bird* bird : Bird::birds) if (!bird->drawn) { //std::cout << "BIRD AMP " << bird->pos_y << " " << bird->altitude << std::endl; bird->Render(renderer); } } void set_Offset(Input& input) { // Set map map offset set if (!input.click_left && Map::offset_to_set.x != 0 && Map::offset_to_set.y != 0) { Map::offset_to_set.x = 0; Map::offset_to_set.y = 0; Map::setting_offset = false; } // Set map offset else if (Map::offset_to_set.x != 0 && Map::offset_to_set.y != 0) { Map::offset.x = input.mouse_state.x - Map::offset_to_set.x; Map::offset.y = input.mouse_state.y - Map::offset_to_set.y; } // Update map offset set if (input.click_left && input.pressed_ctrl && (Map::offset_to_set.x == 0 && Map::offset_to_set.y == 0)) { Map::offset_to_set.x = input.mouse_state.x - Map::offset.x; Map::offset_to_set.y = input.mouse_state.y - Map::offset.y; Map::setting_offset = true; } } void set_Collission(Input& input) { size_t cells_per_tile = Tile::tile_size/Tile::tile_collider_size; const size_t map_width = static_cast(Map::size.x)*cells_per_tile; for (size_t y = 0; y < static_cast(Tile::selection_tile_dimension.y); ++y) { for (size_t x = 0; x < static_cast(Tile::selection_tile_dimension.x); ++x) { size_t cell_x = static_cast(input.mouse_tile_position.x) + x; size_t cell_y = static_cast(input.mouse_tile_position.y) + y; size_t id = cell_y * map_width + cell_x; if (id >= Map::tile_collission_map.size()) continue; Map::tile_collission_map[id] = !Map::tile_collission_map[id]; } } } std::vector& get_ObjectsFromMapTile(SDL_Point tile_point) { int index = static_cast(tile_point.y * Map::size.x + tile_point.x); return Map::tile_map[static_cast(index)].objects; } void place_ConstructionSide() { TilesetObject object = BuildingData::active_build.object; // object.building_status = TileBuildingStatus::CONSTRUCT; TileType type = Tile::get_Type(object.tileset_info.set_category); std::vector collision_map = Tile::get_ObjectCollisionsFromTileset(object.tileset_info.set_id, object.tileset_info.object_id, type); // std::cout << "I " << object.tileset_info.set_id << " " << object.tileset_info.object_id << " " << (int)type << " " << (int)BuildingData::active_build.type <(yc * width_c + xc); if (i >= collision_map.size()) break; if (collision_map[i] && y > draw_tile.y) { if (x <= draw_tile.x) draw_tile = {x, y}; } } } } } // place in map array Building* building = new Building(object.object_type, ObjectCategory::BUILDING, type, object.tileset_info.set_id, object.tileset_info.object_id, {static_cast(BuildingData::active_build.tile_position.x), static_cast(BuildingData::active_build.tile_position.y)}, {object.position.w, object.position.h}, object.z_index, BuildingData::active_build.type); Object::objects.push_back(building); for (int y = 0; y < object.position.h; y++) { for (int x = 0; x < object.position.w; x++) { SDL_Point world_position = {BuildingData::active_build.tile_position.x+x, BuildingData::active_build.tile_position.y+y}; object.position.x = x; object.position.y = y; object.draw_from_this_tile = false; size_t index = static_cast(world_position.y*Map::size.x + world_position.x); if (x == draw_tile.x && y == draw_tile.y) object.draw_from_this_tile = true; Map::tile_map[index].objects.push_back({{x, y}, object.draw_from_this_tile, building->id}); // Sort map objects std::sort(Map::tile_map[index].objects.begin(), Map::tile_map[index].objects.end(), [](const TileObject& a, const TileObject& b) { Object* oa = Object::get_ObjectById(a.object_id); Object* ob = Object::get_ObjectById(b.object_id); return oa->z_index < ob->z_index; }); set_TileCollissionForObjects({world_position.x, world_position.y}); } } std::cout << "PLACING!\n"; } bool is_FreePosition(SDL_FRect candidate_rect) { int left_tile = static_cast(candidate_rect.x / Tile::tile_collider_size); int top_tile = static_cast(candidate_rect.y / Tile::tile_collider_size); int right_tile = static_cast((candidate_rect.x + candidate_rect.w) / Tile::tile_collider_size); int bottom_tile = static_cast((candidate_rect.y + candidate_rect.h) / Tile::tile_collider_size); for (int ty = top_tile; ty <= bottom_tile; ++ty) { for (int tx = left_tile; tx <= right_tile; ++tx) { if (tx < 0 || ty < 0 || tx >= (Map::size.x*Tile::tile_collider_size) || ty >= (Map::size.y*Tile::tile_collider_size)) { return false; } size_t idx = static_cast(ty * Map::size.x*Tile::tile_collider_size + tx); if (Map::tile_collission_map[idx]) { return false; } } } // CHECK ENEMY COLLISION if (Enemy::is_CollidingWithEnemy(candidate_rect)) return false; return true; } SDL_FPoint get_ClosestPointWithoutCollision(const SDL_FRect &rect) { int cx_tile = static_cast(rect.x / Tile::tile_size); int cy_tile = static_cast(rect.y / Tile::tile_size); if (is_FreePosition({rect.x - rect.w*0.5f, rect.y - rect.h*0.5f, rect.w, rect.h})) return { rect.x, rect.y }; struct TilePos { int x, y; }; std::queue q; std::set> visited; q.push({ cx_tile, cy_tile }); visited.insert({ cx_tile, cy_tile }); const int dirs[4][2] = { {1,0}, {-1,0}, {0,1}, {0,-1} }; while (!q.empty()) { TilePos t = q.front(); q.pop(); float px = static_cast(t.x) * Tile::tile_size; float py = static_cast(t.y) * Tile::tile_size; SDL_FRect test_rect = { px - rect.w*0.5f, py - rect.h*0.5f, rect.w, rect.h }; if (is_FreePosition(test_rect)) return { px, py }; for (int i = 0; i < 4; ++i) { int nx = t.x + dirs[i][0]; int ny = t.y + dirs[i][1]; if (nx < 0 || ny < 0 || nx >= static_cast(Map::size.x) || ny >= static_cast(Map::size.y) ) continue; if (visited.insert({ nx, ny }).second) q.push({ nx, ny }); } } std::cout << "No point found!\n"; return { 0,0 }; } };