mapcreator git · master
SDL3 2.5D game and engine using assets, with map editor
C++ 99.3%git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gzsrc/objects/object.cpp raw
#include "object.hpp"
#include <iostream>
#include <algorithm>
#include "map/tile.hpp"
#include "map/map.hpp"
std::vector<Object*> Object::objects;
Object::~Object() {
for (int y = 0; y < dimension.y; y++) {
for (int x = 0; x < dimension.x; x++) {
size_t m_id = static_cast<size_t>((y+world_tile_position.y)*Map::size.x+(x+world_tile_position.x));
if (m_id >= static_cast<size_t>(Map::size.x*Map::size.y))
continue;
std::vector<TileObject>& t_objects = Map::tile_map[m_id].objects;
for (auto it = t_objects.begin(); it != t_objects.end(); ) {
if (it->object_id == id)
it = t_objects.erase(it);
else ++it;
}
}
}
};
const char* Object::to_String(ObjectType type) {
switch (type) {
case ObjectType::NONE: return "NONE";
case ObjectType::ROCK: return "ROCK";
case ObjectType::TREE: return "TREE";
case ObjectType::STICK: return "STICK";
case ObjectType::BUSH: return "BUSH";
case ObjectType::FLOWER: return "FLOWER";
case ObjectType::FOOD: return "FOOD";
case ObjectType::FURNITURE: return "FURNITURE";
case ObjectType::ROOF: return "ROOF";
case ObjectType::FLOOR: return "FLOOR";
case ObjectType::FURNISHING: return "FURNISHING";
case ObjectType::WORKBENCH: return "WORKBENCH";
default: return "UNKNOWN";
}
}
std::vector<Object*>
Object::get_ObjectsByWorldPosition(SDL_Point position) {
std::vector<Object*> objects;
for (Object* object : Object::objects) {
if (object->world_tile_position.x == position.x && object->world_tile_position.y == position.y) {
objects.push_back(object);
}
}
return objects;
}
Object*
Object::get_ObjectByWorldPositionAndTilesetObjectID(SDL_Point position, size_t ts_object_id) {
std::vector<Object*> os = Object::get_ObjectsByWorldPosition(position);
for (Object* o : os) {
if (o->tileset_object_id == ts_object_id)
return o;
}
return nullptr;
}
Object*
Object::get_ObjectById(size_t id) {
//std::cout << "GETTT " << id << std::endl;
for (Object* object : Object::objects)
if (object->id == id) return object;
return nullptr;
}
SDL_Point
Object::get_SetPosition() {
return Tile::tilesets[tileset_type][tileset_id].objects[tileset_object_id].tileset_info.set_position;
}
int
Object::is_InFrontOf(SDL_FPoint world_position, SDL_FRect rect) {
const int scale = Tile::tile_size / Tile::tile_collider_size;
const int obj_w = dimension.x * scale;
const int obj_h = dimension.y * scale;
const int obj_x = world_position.x / scale;
const int obj_y = world_position.y / scale;
const int rect_x = rect.x / Tile::tile_collider_size;
const int rect_y = rect.y / Tile::tile_collider_size;
const int rect_w = (rect.w + Tile::tile_collider_size - 1) / Tile::tile_collider_size;
const int rect_h = (rect.h + Tile::tile_collider_size - 1) / Tile::tile_collider_size;
/*
std::cout << "WP: " << world_position.x << " " << world_position.y << std::endl;
std::cout << "OB " << obj_x << " " << obj_y << " " << obj_w << " " << obj_h << std::endl;
std::cout << "RE " << rect_x << " " << rect_y << " " << rect_w << std::endl;
*/
const int row_width = obj_w;
// object is left or right of rect
if (rect_x + rect_w <= obj_x || rect_x >= obj_x + obj_w)
return false;
int start_x = std::max(rect_x, obj_x) - obj_x;
int end_x = std::min(rect_x + rect_w, obj_x + obj_w) - obj_x;
// is above object
if (rect_y+rect_h < obj_y)
return 2;
// is below object
if (obj_y + obj_h <= rect_y)
return false;
//
int rect_row = rect_y - obj_y;
if (rect_row >= obj_h)
return 2;
bool collission_below = false;
bool anywhere_above = false;
bool anywhere_below = false;
std::vector<bool> collission_map = get_CollisionMap();
bool has_collision = false;
for (int y = 0; y < obj_h; ++y) {
int base = y * row_width;
for (int x = 0; x < obj_w; ++x) {
if (collission_map[static_cast<size_t>(base + x)]) {
has_collision = true;
if (y < rect_row) {
//std::cout << "ABOVE \n";
anywhere_above = true;
if (x > start_x && x < end_x) {
//std::cout << "SUPABOVE \n";
//collission_above = true;
return false;
}
} else {
//std::cout << "BELOW\n";
anywhere_below = true;
if (x > start_x && x < end_x) {
//std::cout << "SUPBELOW\n";
collission_below = true;
}
}
}
}
}
if ( !has_collision ) {
//std::cout << "NO COLL\n";
SDL_FRect temp_rect = { world_position.x, world_position.y, static_cast<float>(dimension.x*Tile::tile_size), static_cast<float>(dimension.y*Tile::tile_size) };
//std::cout << "COLL " << SDL_HasRectIntersectionFloat(&temp_rect, &rect) << " " << world_position.x << " " << world_position.y << " " << rect.x << " " << rect.y <<std::endl;
//std::cout << "WIDH " << dimension.x *Tile::tile_size<< " " << dimension.y *Tile::tile_size<< " RE " << rect.w << " " << rect.h << std::endl;
if (z_index <= 0 ) return false;
return !SDL_HasRectIntersectionFloat(&temp_rect, &rect);
}
//std::cout << "COL " << collission_below << " " << anywhere_below << " " << anywhere_above << std::endl;
if ((collission_below || anywhere_below) && !anywhere_above)
return true;
if (!anywhere_above && !collission_below)
return false;
return false;
}
std::vector<bool> Object::get_CollisionMap() {
std::vector<bool> map =
Tile::get_ObjectCollisionsFromTileset(
tileset_id,
tileset_object_id,
tileset_type);
if (!map.empty())
return map;
const size_t n = Tile::tile_collider_size * Tile::tile_collider_size;
return std::vector<bool>(n, false);
}
bool
Object::has_Collision() {
for (bool collission : get_CollisionMap()) {
if (collission) return true;
}
return false;
}
std::vector<bool>
Object::get_CollissionsOfTile(SDL_Point tile) {
std::vector<bool> collision_map = get_CollisionMap();
const size_t scale = Tile::tile_size / Tile::tile_collider_size;
int y_start = tile.y * static_cast<int>(Tile::tile_size/Tile::tile_collider_size);
int y_end = y_start + static_cast<int>(Tile::tile_size/Tile::tile_collider_size);
int x_start = tile.x * static_cast<int>(Tile::tile_size/Tile::tile_collider_size);
int x_end = x_start + static_cast<int>(Tile::tile_size/Tile::tile_collider_size);
int obj_w = static_cast<size_t>(dimension.x) * scale;
std::vector<bool> collisions;
for (int y = y_start; y < y_end; y++) {
for (int x = x_start; x < x_end; x++) {
size_t index = static_cast<size_t>(y * obj_w + x);
collisions.push_back(collision_map[index]);
}
}
return collisions;
}
void
Object::print_CollisionMap() {
size_t collider_w = static_cast<size_t>(dimension.x) * Tile::tile_size / Tile::tile_collider_size;
size_t collider_h = static_cast<size_t>(dimension.y) * Tile::tile_size / Tile::tile_collider_size;
std::cout << "Collision Map for object "
<< tileset_object_id
<< " (collider size: " << collider_w << "x" << collider_h << "):\n";
std::vector<bool> collision_map = get_CollisionMap();
for (size_t y = 0; y < collider_h; ++y) {
for (size_t x = 0; x < collider_w; ++x) {
size_t index = y * collider_w + x;
if (index >= collision_map.size()) {
std::cout << "? ";
} else {
std::cout << (collision_map[index] ? "1 " : "0 ");
}
}
std::cout << "\n";
}
}
void
Object::Draw(SDL_Renderer* renderer, SDL_FPoint position, bool is_transparent, int transparency) {
SDL_Point obj_set_pos = get_SetPosition();
SDL_FRect obj_src {
static_cast<float>(obj_set_pos.x) * static_cast<float>(Tile::tile_size),
static_cast<float>(obj_set_pos.y) * static_cast<float>(Tile::tile_size),
static_cast<float>(dimension.x * static_cast<int>(Tile::tile_size)),
static_cast<float>(dimension.y * static_cast<int>(Tile::tile_size))
};
int size = Tile::get_Size();
SDL_FRect dst;
if (object_type == ObjectType::VEGETABLE) {
dst = { Scale(position.x + Map::offset.x),
Scale(position.y + Map::offset.y-7),
Scale(dimension.x * size),
Scale(dimension.y * size) };
} else {
dst = { Scale(position.x + Map::offset.x),
Scale(position.y + Map::offset.y),
Scale(dimension.x * size),
Scale(dimension.y * size) };
}
SDL_Texture* tex = Tile::tilesets[tileset_type][tileset_id].texture;
if (is_transparent)
SDL_SetTextureAlphaMod(tex, transparency);
SDL_RenderTexture(renderer, tex, &obj_src, &dst);
if (is_transparent)
SDL_SetTextureAlphaMod(tex, 255);
#ifdef DEBUG_BUILD
std::vector<bool> collision_map = get_CollisionMap();
size_t scale = Tile::tile_size / Tile::tile_collider_size;
size_t collider_w = static_cast<size_t>(dimension.x) * scale;
size_t collider_h = static_cast<size_t>(dimension.y) * scale;
for (size_t y = 0; y < collider_h; ++y) {
for (size_t x = 0; x < collider_w; ++x) {
size_t index = y * collider_w + x;
if (index >= collision_map.size()) continue;
if (collision_map[index]) {
SDL_FRect col_rect = {
Scale(static_cast<float>(position.x + (x * Tile::tile_collider_size)) + Map::offset.x),
Scale(static_cast<float>(position.y + (y * Tile::tile_collider_size)) + Map::offset.y),
Scale(static_cast<float>(Tile::tile_collider_size)),
Scale(static_cast<float>(Tile::tile_collider_size))
};
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 120);
SDL_RenderFillRect(renderer, &col_rect);
}
}
}
#endif
}
void
Object::Remove(Object* obj) {
if (!obj) return;
int start_x = obj->world_tile_position.x;
int start_y = obj->world_tile_position.y;
int end_x = start_x + obj->dimension.x;
int end_y = start_y + obj->dimension.y;
for (int y = start_y; y < end_y; ++y) {
for (int x = start_x; x < end_x; ++x) {
size_t index = static_cast<size_t>(y * Map::size.x + x);
if (index >= Map::tile_map.size()) continue;
auto& tile_objects = Map::tile_map[index].objects;
tile_objects.erase(
std::remove_if(tile_objects.begin(), tile_objects.end(),
[obj](const TileObject& to) { return to.object_id == obj->id; }),
tile_objects.end());
Map::set_TileCollissionForObjects({x, y});
}
}
Object::objects.erase(
std::remove(Object::objects.begin(),
Object::objects.end(),
obj),
Object::objects.end()
);
delete obj;
}