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/map/tile.cpp raw
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <iostream>
#include <algorithm>
#include "map/tile.hpp"
#include "defaults/input.hpp"
#include "map/map.hpp"
#include "defaults/ui.hpp"
namespace Tile {
size_t active_tileset_id = 0;
TileType active_tileset_type = TILE_BACKGROUND;
TileSet* active_tileset = nullptr;
bool draw_tile_set = true;
bool tile_selected = false;
bool object_selected = false;
size_t selected_object_id = SIZE_MAX;
SDL_Point selected_position = {0,0};
TileObjectPropSettingStates object_props_setting_state = TileObjectPropSettingStates::OBJECT_SETTING_STATE_TYPE;
std::unordered_map<TileType, std::vector<TileSet>> tilesets;
std::vector<SDL_Point> selected_tiles;
SDL_FPoint tileset_offset = {0, Ui::top_bar_height};
SDL_FPoint tileset_offset_to_set = {0, 0};
bool setting_tileset_offset = false;
float tileset_scale = 0;
float tileset_scale_to_set = 0;
bool setting_tileset_scale = false;
bool hovering_set = false;
SDL_Point selection_tile_dimension = {1, 1};
SDL_Point selected_tile_dimension = {1, 1};
std::string save_tileset_collission_path = "saves/save.tileset_collissions";
std::string save_tileset_objects_path = "saves/save.tileset_objects";
std::string save_tileset_floortype_path = "saves/save.tileset_floortype";
std::vector<TileSettingHistory> tile_setting_history;
std::vector<FloorProps> floor_props;
std::unordered_map<TileCategory, std::unordered_map<size_t,TilesetFloorProps>> tileset_floor_props;
const char* to_String(TileTypeFloors type) {
switch (type) {
case NONE: return "NONE";
case MEADOW: return "MEADOW";
case CLAY: return "CLAY";
case SOIL: return "SOIL";
case BRICKS: return "BRICKS";
case ICE: return "ICE";
case DESERT: return "DESERT";
case WATER: return "WATER";
default: return "UNKNOWN";
}
}
bool
Init(SDL_Renderer* renderer) {
Tile::tilesets[TILE_BACKGROUND].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Tilesets/Floors_Tiles.png"),
{25, 26},
TILE_GROUND, {}, {}, {}
});
Tile::tilesets[TILE_BACKGROUND].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Tilesets/Water_tiles.png"),
{25, 25},
TILE_WATER, {}, {}, {}
});
Tile::tilesets[TILE_BACKGROUND].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Tilesets/Dungeon_Tiles.png"),
{25, 25},
TILE_DUNGEON, {}, {}, {}
});
Tile::tilesets[TILE_BACKGROUND].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Tilesets/Wall_Tiles.png"),
{25, 25},
TILE_WALL, {}, {}, {}
});
Tile::tilesets[TILE_BACKGROUND].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Tilesets/Wall_Variations.png"),
{16, 30},
TILE_WALL_VARIATION, {}, {}, {}
});
Tile::tilesets[TILE_OVERLAY].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Tilesets/Overlay_tiles.png"),
{25,25},
TILE_OVERLAY_FARM, {}, {}, {}
});
Tile::tilesets[TILE_BUILDING].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Structures/Buildings/Floors.png"),
{25, 25},
TILE_FLOORS, {}, {}, {}
});
Tile::tilesets[TILE_BUILDING].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Structures/Buildings/Props.png"),
{25, 25},
TILE_PROPS, {}, {}, {}
});
Tile::tilesets[TILE_BUILDING].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Structures/Buildings/Roofs.png"),
{25, 25},
TILE_ROOFS, {}, {}, {}
});
Tile::tilesets[TILE_BUILDING].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Structures/Buildings/Walls.png"),
{42, 50},
TILE_WALLS, {}, {}, {}
});
Tile::tilesets[TILE_BUILDING].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Furniture.png"),
{50, 54},
TILE_FURNITURE, {}, {}, {}
});
Tile::tilesets[TILE_BUILDING].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Structures/Stations/Workbench/Workbench.png"),
{12, 22},
TILE_WORKBENCH, {}, {}, {}
});
Tile::tilesets[TILE_OBJECT].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Vegetation.png"),
{25, 27},
TILE_VEGETATION, {}, {}, {}
});
Tile::tilesets[TILE_OBJECT].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Rocks.png"),
{13, 19},
TILE_ROCK, {}, {}, {}
});
Tile::tilesets[TILE_OBJECT].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Trees/Model_01/Size_02.png"),
{16, 8},
TILE_TREE, {}, {}, {}
});
Tile::tilesets[TILE_OBJECT].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Trees/Model_01/Size_03.png"),
{13, 12},
TILE_TREE, {}, {}, {}
});
Tile::tilesets[TILE_OBJECT].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Trees/Model_01/Size_04.png"),
{23, 16},
TILE_TREE, {}, {}, {}
});
Tile::tilesets[TILE_OBJECT].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Trees/Model_01/Size_05.png"),
{28, 23},
TILE_TREE, {}, {}, {}
});
Tile::tilesets[TILE_FARM].push_back(
{IMG_LoadTexture(renderer, "Pixel_Crawler/Environment/Props/Static/Farm.png"),
{25, 25},
TILE_FARMING, {}, {}, {}
});
for (auto& [tile_type, tileset_vector] : Tile::tilesets) {
for (auto& tileset : tileset_vector) {
SDL_Texture* tex = tileset.texture;
if (tex) {
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_NEAREST);
}
}
}
if (!Tile::tilesets[TILE_BACKGROUND][0].texture) {
SDL_Log("Couldn't load texture: %s\n", SDL_GetError());
return false;
}
const int cells_per_tile = Tile::get_Size() / Tile::tile_collider_size;
for (auto& tileset : Tile::tilesets[TILE_BACKGROUND]) {
if (tileset.texture) {
SDL_SetTextureScaleMode(tileset.texture, SDL_SCALEMODE_NEAREST);
}
}
for (auto &pair : Tile::tilesets) {
for (auto &tile : pair.second) {
size_t total_cells = static_cast<size_t>(tile.size.x * cells_per_tile * tile.size.y * cells_per_tile);
tile.collission_map.assign(total_cells, false);
}
}
Tile::load_Collissions();
Tile::load_Objects();
ResourceData::load_Resources();
Tile::load_TilesetFloorProps();
Tile::active_tileset = &Tile::tilesets[TILE_BACKGROUND][0];
floor_props.push_back({NONE, true, false});
floor_props.push_back({MEADOW, true, false});
floor_props.push_back({CLAY, true, false});
floor_props.push_back({SOIL, true, true});
floor_props.push_back({BRICKS, true, false});
floor_props.push_back({ICE, false, false});
floor_props.push_back({DESERT, false, false});
floor_props.push_back({WATER, false, false});
return true;
}
TileType
get_Type(TileCategory category) {
switch (category) {
case TILE_GROUND:
case TILE_WATER:
case TILE_WALL:
case TILE_WALL_VARIATION:
case TILE_DUNGEON:
return TILE_BACKGROUND;
case TILE_OVERLAY_FARM:
return TILE_OVERLAY;
case TILE_FLOORS:
case TILE_PROPS:
case TILE_ROOFS:
case TILE_WALLS:
case TILE_WORKBENCH:
case TILE_FURNITURE:
return TILE_BUILDING;
case TILE_TREE:
case TILE_ROCK:
case TILE_VEGETATION:
case TILE_FARMING:
return TILE_OBJECT;
}
return TILE_TYPE_LAST;
}
size_t
get_Size() {
return (tile_size);
}
size_t
get_SelectionSize(ModifyState_s modify_state) {
if (modify_state == MODIFY_COLLISSION)
return (tile_collider_size);
return (tile_size);
}
size_t
get_ObjectIdFromTileset(SDL_Point selected_tile, TileSet tileset) {
for (const auto& pair : tileset.objects) {
SDL_Rect position = pair.second.position;
if (position.x <= static_cast<int>(selected_tile.x) &&
position.y <= static_cast<int>(selected_tile.y) &&
position.x+pair.second.position.w > static_cast<int>(selected_tile.x) &&
position.y+pair.second.position.h > static_cast<int>(selected_tile.y)) {
return pair.first;
}
}
return SIZE_MAX;
}
void
set_HoveringTileset(SDL_FPoint mouse_state) {
size_t selection_size = get_Size();
float logical_x = mouse_state.x - tileset_offset.x;
float logical_y = mouse_state.y - tileset_offset.y;
int tile_x = static_cast<int>(logical_x / selection_size);
int tile_y = static_cast<int>(logical_y / selection_size);
hovering_set = (tile_x >= 0 && tile_x < static_cast<int>(active_tileset->size.x) &&
tile_y >= 0 && tile_y < static_cast<int>(active_tileset->size.y));
}
TileSet&
get_TilesetFromMapTile(Tile_s tile) {
return tilesets[get_Type(tile.set_category)][tile.set_id];
}
void
save_Objects() {
std::ofstream file(save_tileset_objects_path, std::ios::binary);
if (!file) return;
uint32_t types_count = tilesets.size();
file.write(reinterpret_cast<const char*>(&types_count), sizeof(types_count));
for (const auto& [type, vec] : tilesets) {
uint32_t t = static_cast<uint32_t>(type);
file.write(reinterpret_cast<const char*>(&t), sizeof(t));
uint32_t set_count = vec.size();
file.write(reinterpret_cast<const char*>(&set_count), sizeof(set_count));
for (const auto& tile : vec) {
uint64_t obj_count = tile.objects.size();
file.write(reinterpret_cast<const char*>(&obj_count), sizeof(obj_count));
for (const auto& [key, obj] : tile.objects) {
file.write(reinterpret_cast<const char*>(&key), sizeof(key));
// --- TilesetObject serialization ---
file.write(reinterpret_cast<const char*>(&obj.position.x), sizeof(obj.position.x));
file.write(reinterpret_cast<const char*>(&obj.position.y), sizeof(obj.position.y));
file.write(reinterpret_cast<const char*>(&obj.position.w), sizeof(obj.position.w));
file.write(reinterpret_cast<const char*>(&obj.position.h), sizeof(obj.position.h));
file.write(reinterpret_cast<const char*>(&obj.draw_from_this_tile), sizeof(obj.draw_from_this_tile));
int type_value = static_cast<int>(obj.object_type);
file.write(reinterpret_cast<const char*>(&type_value), sizeof(type_value));
file.write(reinterpret_cast<const char*>(&obj.collectable), sizeof(obj.collectable));
//int building_status = static_cast<int>(obj.building_status);
// file.write(reinterpret_cast<const char*>(&building_status), sizeof(building_status));
file.write(reinterpret_cast<const char*>(&obj.z_index), sizeof(obj.z_index));
// --- Tile_s serialization ---
file.write(reinterpret_cast<const char*>(&obj.tileset_info.set_id), sizeof(obj.tileset_info.set_id));
file.write(reinterpret_cast<const char*>(&obj.tileset_info.object_id), sizeof(obj.tileset_info.object_id));
int category = static_cast<int>(obj.tileset_info.set_category);
file.write(reinterpret_cast<const char*>(&category), sizeof(category));
file.write(reinterpret_cast<const char*>(&obj.tileset_info.set_position.x), sizeof(obj.tileset_info.set_position.x));
file.write(reinterpret_cast<const char*>(&obj.tileset_info.set_position.y), sizeof(obj.tileset_info.set_position.y));
}
}
}
}
void
load_Objects() {
std::ifstream file(save_tileset_objects_path, std::ios::binary);
if (!file) return;
uint32_t types_count = 0;
file.read(reinterpret_cast<char*>(&types_count), sizeof(types_count));
for (uint32_t i = 0; i < types_count; ++i) {
uint32_t t = 0;
file.read(reinterpret_cast<char*>(&t), sizeof(t));
TileType type = static_cast<TileType>(t);
uint32_t set_count = 0;
file.read(reinterpret_cast<char*>(&set_count), sizeof(set_count));
auto& vec = tilesets[type];
for (uint32_t j = 0; j < set_count && j < vec.size(); ++j) {
uint64_t obj_count = 0;
file.read(reinterpret_cast<char*>(&obj_count), sizeof(obj_count));
vec[j].objects.clear();
for (uint64_t k = 0; k < obj_count; ++k) {
size_t key = 0;
file.read(reinterpret_cast<char*>(&key), sizeof(key));
TilesetObject obj{};
file.read(reinterpret_cast<char*>(&obj.position.x), sizeof(obj.position.x));
file.read(reinterpret_cast<char*>(&obj.position.y), sizeof(obj.position.y));
file.read(reinterpret_cast<char*>(&obj.position.w), sizeof(obj.position.w));
file.read(reinterpret_cast<char*>(&obj.position.h), sizeof(obj.position.h));
file.read(reinterpret_cast<char*>(&obj.draw_from_this_tile), sizeof(obj.draw_from_this_tile));
int type_value = 0;
file.read(reinterpret_cast<char*>(&type_value), sizeof(type_value));
obj.object_type = static_cast<ObjectType>(type_value);
file.read(reinterpret_cast<char*>(&obj.collectable), sizeof(obj.collectable));
file.read(reinterpret_cast<char*>(&obj.z_index), sizeof(obj.z_index));
// --- Tile_s deserialization ---
file.read(reinterpret_cast<char*>(&obj.tileset_info.set_id), sizeof(obj.tileset_info.set_id));
file.read(reinterpret_cast<char*>(&obj.tileset_info.object_id), sizeof(obj.tileset_info.object_id));
int category = 0;
file.read(reinterpret_cast<char*>(&category), sizeof(category));
obj.tileset_info.set_category = static_cast<TileCategory>(category);
file.read(reinterpret_cast<char*>(&obj.tileset_info.set_position.x), sizeof(obj.tileset_info.set_position.x));
file.read(reinterpret_cast<char*>(&obj.tileset_info.set_position.y), sizeof(obj.tileset_info.set_position.y));
vec[j].objects.emplace(key, obj);
}
}
}
}
void
save_Collissions() {
std::ofstream file(save_tileset_collission_path, std::ios::binary);
if (!file) return;
uint32_t types_count = tilesets.size();
file.write(reinterpret_cast<char*>(&types_count), sizeof(types_count));
for (const auto &[type, vec] : tilesets) {
uint32_t t = static_cast<uint32_t>(type);
file.write(reinterpret_cast<char*>(&t), sizeof(t));
uint32_t set_count = vec.size();
file.write(reinterpret_cast<char*>(&set_count), sizeof(set_count));
for (const auto &tile : vec) {
uint64_t map_size = tile.collission_map.size();
file.write(reinterpret_cast<char*>(&map_size), sizeof(map_size));
for (bool v : tile.collission_map) {
uint8_t b = v ? 1 : 0;
file.write(reinterpret_cast<char*>(&b), 1);
}
}
}
}
void
load_Collissions() {
std::ifstream file(save_tileset_collission_path, std::ios::binary);
if (!file) return;
uint32_t types_count = 0;
file.read(reinterpret_cast<char*>(&types_count), sizeof(types_count));
for (uint32_t i = 0; i < types_count; ++i) {
uint32_t t = 0;
file.read(reinterpret_cast<char*>(&t), sizeof(t));
TileType type = static_cast<TileType>(t);
uint32_t set_count = 0;
file.read(reinterpret_cast<char*>(&set_count), sizeof(set_count));
auto &vec = tilesets[type];
for (uint32_t j = 0; j < set_count && j < vec.size(); ++j) {
uint64_t map_size = 0;
file.read(reinterpret_cast<char*>(&map_size), sizeof(map_size));
vec[j].collission_map.resize(map_size);
for (uint64_t k = 0; k < map_size; ++k) {
uint8_t b = 0;
file.read(reinterpret_cast<char*>(&b), 1);
vec[j].collission_map[k] = (b != 0);
}
}
}
}
inline int TileCategoryToInt(TileCategory t) { return static_cast<int>(t); }
inline int TileTypeFloorsToInt(TileTypeFloors f) { return static_cast<int>(f); }
inline TileCategory IntToTileCategory(int i) { return static_cast<TileCategory>(i); }
inline TileTypeFloors IntToTileTypeFloors(int i) { return static_cast<TileTypeFloors>(i); }
void
save_TilesetFloorProps() {
std::ofstream out(save_tileset_floortype_path, std::ios::binary);
if (!out) {
std::cerr << "Failed to open file for saving: " << save_tileset_floortype_path << "\n";
return;
}
size_t map_size = tileset_floor_props.size();
out.write(reinterpret_cast<const char*>(&map_size), sizeof(map_size));
for (auto& [tile_type, inner_map] : tileset_floor_props) {
int tt = TileCategoryToInt(tile_type);
out.write(reinterpret_cast<const char*>(&tt), sizeof(tt));
size_t inner_size = inner_map.size();
out.write(reinterpret_cast<const char*>(&inner_size), sizeof(inner_size));
for (auto& [index, props] : inner_map) {
out.write(reinterpret_cast<const char*>(&index), sizeof(index));
int floor = TileTypeFloorsToInt(props.tiletype);
out.write(reinterpret_cast<const char*>(&floor), sizeof(floor));
out.write(reinterpret_cast<const char*>(&props.z_index), sizeof(props.z_index));
}
}
}
void
load_TilesetFloorProps() {
std::ifstream in(save_tileset_floortype_path, std::ios::binary);
if (!in) {
std::cerr << "Failed to open file for loading: " << save_tileset_floortype_path << "\n";
return;
}
tileset_floor_props.clear();
size_t map_size = 0;
in.read(reinterpret_cast<char*>(&map_size), sizeof(map_size));
for (size_t i = 0; i < map_size; ++i) {
int tt_int;
in.read(reinterpret_cast<char*>(&tt_int), sizeof(tt_int));
TileCategory tt = IntToTileCategory(tt_int);
size_t inner_size = 0;
in.read(reinterpret_cast<char*>(&inner_size), sizeof(inner_size));
std::unordered_map<size_t, TilesetFloorProps> inner_map;
for (size_t j = 0; j < inner_size; ++j) {
size_t index;
int floor_int;
int z_index;
in.read(reinterpret_cast<char*>(&index), sizeof(index));
in.read(reinterpret_cast<char*>(&floor_int), sizeof(floor_int));
in.read(reinterpret_cast<char*>(&z_index), sizeof(z_index));
inner_map[index] = TilesetFloorProps{IntToTileTypeFloors(floor_int), z_index};
}
tileset_floor_props[tt] = std::move(inner_map);
}
}
void
draw_SelectedObject(SDL_Renderer* renderer, Input input) {
// render selected object
if (Tile::object_selected && Default::modify_state == MODIFY_TILES) {
TilesetObject object = active_tileset->objects[selected_object_id];
SDL_FRect obj_src = {
object.position.x * static_cast<float>(Tile::tile_size),
object.position.y * static_cast<float>(Tile::tile_size),
object.position.w * static_cast<float>(Tile::tile_size),
object.position.h * static_cast<float>(Tile::tile_size)
};
SDL_FPoint tile_offset = {
(static_cast<float>(selected_position.x) - object.position.x) * static_cast<float>(Tile::tile_size),
(static_cast<float>(selected_position.y) - object.position.y) * static_cast<float>(Tile::tile_size)
};
SDL_FPoint offset = {(float)tileset_offset.x, (float)tileset_offset.y};
if (!hovering_set) {
offset.x = Map::offset.x;
offset.y = Map::offset.y;
}
SDL_FRect dst {Scale(input.mouse_tile_position.x* static_cast<int>(Tile::tile_size) + offset.x - tile_offset.x),
Scale(input.mouse_tile_position.y* static_cast<int>(Tile::tile_size) + offset.y - tile_offset.y),
Scale(object.position.w * static_cast<float>(Tile::tile_size)),
Scale(object.position.h * static_cast<float>(Tile::tile_size))};
SDL_Texture* tex = Tile::tilesets[active_tileset_type][active_tileset_id].texture;
SDL_SetTextureAlphaMod(tex, 100);
SDL_RenderTexture(renderer, tex, &obj_src, &dst);
SDL_SetTextureAlphaMod(tex, 255);
}
}
void
draw_Tileset(SDL_Renderer* renderer, Input input) {
// render Set
float cell_size = Tile::get_SelectionSize(Default::modify_state);
SDL_FRect dst = {
0.0f + tileset_offset.x * Default::game_scale,
0.0f + tileset_offset.y * Default::game_scale,
Scale(Tile::active_tileset->size.x * tile_size),
Scale(Tile::active_tileset->size.y * tile_size)
};
SDL_FRect bg_rect = dst;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderFillRect(renderer, &bg_rect);
SDL_RenderTexture(renderer, Tile::active_tileset->texture, NULL, &dst);
// Render Set-Border
float border_thickness = 4.0f;
SDL_FRect top = { dst.x-border_thickness, dst.y-border_thickness, dst.w+border_thickness*2, border_thickness };
SDL_FRect bottom = { dst.x-border_thickness, dst.y + dst.h, dst.w+border_thickness*2, border_thickness };
SDL_FRect left = { dst.x-border_thickness, dst.y-border_thickness, border_thickness, dst.h+border_thickness*2 };
SDL_FRect right = { dst.x + dst.w, dst.y-border_thickness, border_thickness, dst.h+border_thickness*2 };
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderFillRect(renderer, &top);
SDL_RenderFillRect(renderer, &bottom);
SDL_RenderFillRect(renderer, &left);
SDL_RenderFillRect(renderer, &right);
// render object cells
if (Default::modify_state == MODIFY_FLOOR_TYPE) {
SDL_SetRenderDrawColor(renderer, 0, 160, 255, 255);
SDL_Point tileset_size = active_tileset->size;
for (const auto& pair : tileset_floor_props[active_tileset->category]) {
if (pair.second.tiletype == NONE) continue;
int x = static_cast<int>(pair.first) % tileset_size.x;
int y = static_cast<int>(pair.first) / tileset_size.x;
SDL_FRect cell_rect = {
Scale(x * tile_size + tileset_offset.x),
Scale(y * tile_size + tileset_offset.y),
Scale(tile_size),
Scale(tile_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);
}
} else if (Default::modify_state == MODIFY_OBJECTS || Default::modify_state == MODIFY_OBJECTS_PROPS || Default::modify_state == MODIFY_OBJECTS_PROPS_RESOURCE) {
SDL_SetRenderDrawColor(renderer, 0, 255, Default::modify_state == MODIFY_OBJECTS_PROPS ? 160 : 255, 255);
for (const auto& pair : active_tileset->objects) {
if (Default::modify_state == MODIFY_OBJECTS_PROPS_RESOURCE && !pair.second.collectable) continue;
if (pair.second.object_type == ObjectType::NONE)
SDL_SetRenderDrawColor(renderer, 200, 0, 0, 255);
else
SDL_SetRenderDrawColor(renderer, 0, 255, Default::modify_state == MODIFY_OBJECTS_PROPS ? 160 : 255, 255);
SDL_FRect cell_rect = {
Scale(pair.second.position.x * cell_size + tileset_offset.x),
Scale(pair.second.position.y * cell_size + tileset_offset.y),
Scale(pair.second.position.w * cell_size),
Scale(pair.second.position.h * 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);
}
// render collision cells
} else if (Default::modify_state == MODIFY_COLLISSION) {
size_t map_width = static_cast<size_t>(Tile::active_tileset->size.x);
size_t map_height = static_cast<size_t>(Tile::active_tileset->size.y);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 100);
size_t cells_per_tile = tile_size/tile_collider_size;
for (size_t y = 0; y < map_height*cells_per_tile; ++y) {
for (size_t x = 0; x < map_width*cells_per_tile; ++x) {
size_t index = y * map_width*cells_per_tile + x;
if (!Tile::active_tileset->collission_map[index])
continue;
SDL_FRect cell_rect = {
Scale(x * cell_size + tileset_offset.x),
Scale(y * cell_size + tileset_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);
}
}
}
// render selection_border
if (hovering_set) {
SDL_FRect tile_rect {Scale(input.mouse_tile_position.x*cell_size + tileset_offset.x),
Scale(input.mouse_tile_position.y*cell_size + tileset_offset.y),
Scale(cell_size*Tile::selection_tile_dimension.x),
Scale(cell_size*Tile::selection_tile_dimension.y)};
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderRect(renderer, &tile_rect);
}
// render selected border
if (Tile::tile_selected) {
SDL_FRect tile_rect_selected
{Scale(Tile::selected_tiles[0].x*tile_size + tileset_offset.x),
Scale(Tile::selected_tiles[0].y*tile_size + tileset_offset.y),
Scale(tile_size*Tile::selected_tile_dimension.x),
Scale(tile_size*Tile::selected_tile_dimension.y)};
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderRect(renderer, &tile_rect_selected);
} else if (Tile::object_selected) {
TilesetObject object = active_tileset->objects[selected_object_id];
SDL_FRect tile_rect_selected
{Scale(object.position.x*static_cast<int>(tile_size) + tileset_offset.x),
Scale(object.position.y*static_cast<int>(tile_size) + tileset_offset.y),
Scale(object.position.w*static_cast<int>(tile_size)),
Scale(object.position.h*static_cast<int>(tile_size))};
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderRect(renderer, &tile_rect_selected);
SDL_FRect tile_rect_selected_position
{Scale(selected_position.x * static_cast<int>(tile_size) + tileset_offset.x),
Scale(selected_position.y * static_cast<int>(tile_size) + tileset_offset.y),
Scale(tile_size),
Scale(tile_size)};
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 60);
SDL_RenderFillRect(renderer, &tile_rect_selected_position);
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 60);
SDL_RenderRect(renderer, &tile_rect_selected_position);
}
}
void
clear_Objects(Input& input) {
for (int y = 0; y < Tile::selection_tile_dimension.y; y++) {
for (int x = 0; x < Tile::selection_tile_dimension.x; x++) {
int map_x = input.mouse_tile_position.x + x;
int map_y = input.mouse_tile_position.y + y;
if (map_x >= Map::size.x || map_y >= Map::size.y)
continue;
size_t index = static_cast<size_t>(map_y * Map::size.x + map_x);
auto& tile_objects = Map::tile_map[index].objects;
if (!input.pressed_c || tile_objects.empty())
continue;
TileObject &obj = tile_objects[0];
Object* object = Object::get_ObjectById(obj.object_id);
if (!object) continue;
int world_tile_x = map_x - obj.position.x;
int world_tile_y = map_y - obj.position.y;
for (int wx = world_tile_x; wx < world_tile_x + object->dimension.x; ++wx) {
for (int wy = world_tile_y; wy < world_tile_y + object->dimension.y; ++wy) {
if (wx < 0 || wy < 0 || wx >= Map::size.x || wy >= Map::size.y)
continue;
size_t i = static_cast<size_t>(wy * Map::size.x + wx);
auto &objects = Map::tile_map[i].objects;
for (auto it = objects.begin(); it != objects.end();) {
Object* oo = Object::get_ObjectById(it->object_id);
if (!oo || oo->id == object->id) {
it = objects.erase(it);
} else ++it;
}
Map::set_TileCollissionForObjects({wx, wy});
}
}
delete object;
}
}
}
void
set_Collission(Input& input) {
const int map_width = Tile::active_tileset->size.x * (tile_size/tile_collider_size);
for (int y = 0; y < Tile::selection_tile_dimension.y; ++y) {
for (int x = 0; x < Tile::selection_tile_dimension.x; ++x) {
int cell_x = input.mouse_tile_position.x + x;
int cell_y = input.mouse_tile_position.y + y;
size_t id = static_cast<size_t>(cell_y * map_width + cell_x);
if (id >= Tile::active_tileset->collission_map.size())
continue;
Tile::active_tileset->collission_map[id] = !Tile::active_tileset->collission_map[id];
}
}
}
bool
objec_HasCollission(TilesetObject& object) {
TileType type = get_Type( object.tileset_info.set_category);
std::vector<bool> collision_map =
Tile::get_ObjectCollisionsFromTileset(object.tileset_info.set_id,
object.tileset_info.object_id, type);
for (bool collission : collision_map) {
if (collission) return true;
}
return false;
}
std::vector<bool>
get_CollissionsOfTileFromObject(TilesetObject& obj, SDL_Point tile) {
const size_t scale = Tile::tile_size / Tile::tile_collider_size;
// convert rectangle to collider coordinates
// 0 2
TileType type = get_Type( obj.tileset_info.set_category);
std::vector<bool> collision_map =
Tile::get_ObjectCollisionsFromTileset(obj.tileset_info.set_id,
obj.tileset_info.object_id, type);
int y_start = tile.y * (tile_size/tile_collider_size);
int y_end = y_start + static_cast<int>(tile_size/tile_collider_size);
int x_start = tile.x * (tile_size/tile_collider_size);
int x_end = x_start + static_cast<int>(tile_size/tile_collider_size);
int obj_w = static_cast<size_t>(obj.position.w) * scale;
//int obj_h = static_cast<size_t>(obj.position.h) * scale;
std::vector<bool> collissions;
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);
bool cell_value = index < collision_map.size() ? collision_map[index] : false;
collissions.push_back(cell_value);
}
}
/*
int obj_abs_x = static_cast<int>(tile.x) - obj.position.x;
int obj_abs_y = static_cast<int>(tile.y) - obj.position.y;
int obj_cx = obj_abs_x * static_cast<int>(scale);
int obj_cy = obj_abs_y * static_cast<int>(scale);
size_t obj_cw = static_cast<size_t>(obj.position.w) * scale;
size_t obj_ch = static_cast<size_t>(obj.position.h) * scale;
int start_cx = obj_cx;
int end_cx = obj_cx + static_cast<int>(Tile::tile_size) / static_cast<int>(Tile::tile_collider_size);
int start_cy = obj_cy;
int end_cy = obj_cy + static_cast<int>(Tile::tile_size) / static_cast<int>(Tile::tile_collider_size);
for (int cy = start_cy; cy < end_cy; ++cy) {
for (int cx = start_cx; cx < end_cx; ++cx) {
int rel_x = cx - obj_cx;
int rel_y = cy - obj_cy;
if (rel_x < 0 || rel_y < 0 || static_cast<size_t>(rel_x) >= obj_cw || static_cast<size_t>(rel_y) >= obj_ch) {
continue;
}
size_t obj_index = static_cast<size_t>(rel_y) * obj_cw + static_cast<size_t>(rel_x);
bool cell_value = obj_index < obj.collission_map.size() ? obj.collission_map[obj_index] : false;
std::cout << (int)cell_value;
collissions.push_back(cell_value);
}
std::cout << std::endl;
}
*/
return collissions;
}
void
set_Object(Input& input) {
std::unordered_map<size_t, TilesetObject>& objects = active_tileset->objects;
size_t object_id = objects.size();
size_t mouse_tile_x = static_cast<size_t>(input.mouse_tile_position.x);
size_t mouse_tile_y = static_cast<size_t>(input.mouse_tile_position.y);
// check if any tile already in objects map
bool removed_object = false;
for (size_t y = 0; y < static_cast<size_t>(Tile::selection_tile_dimension.y); ++y) {
for (size_t x = 0; x < static_cast<size_t>(Tile::selection_tile_dimension.x); ++x) {
size_t cell_x = mouse_tile_x + x;
size_t cell_y = mouse_tile_y + y;
for (size_t i = 0; i < object_id; i++) {
if (objects[i].position.x == static_cast<int>(cell_x) && objects[i].position.y == static_cast<int>(cell_y)) {
objects.erase(i);
removed_object = true;
break;
}
}
}
}
std::cout<< "NEW OBJ ID " << object_id << " " << selected_object_id << std::endl;
if (removed_object) return;
// add objecz to map
objects[object_id].position.x = static_cast<int>(mouse_tile_x);
objects[object_id].position.y = static_cast<int>(mouse_tile_y);
objects[object_id].position.w = Tile::selection_tile_dimension.x,
objects[object_id].position.h = Tile::selection_tile_dimension.y,
objects[object_id].object_type = ObjectType::NONE,
objects[object_id].collectable = false;
//objects[object_id].building_status = TileBuildingStatus::NONE;
Tile_s tileset_info = {Tile::active_tileset_id,
object_id,
Tile::tilesets[Tile::active_tileset_type][Tile::active_tileset_id].category ,
{static_cast<int>(objects[object_id].position.x),
static_cast<int>(objects[object_id].position.y)}};
objects[object_id].tileset_info = tileset_info;
// std::cout << mouse_tile_x << " " << mouse_tile_y << " " << Tile::selection_tile_dimension.x << " " << Tile::selection_tile_dimension.x << std::endl;
}
void
set_ObjectProps(Input& input) {
static ObjectType set_type = ObjectType::NONE;
static bool set_collectable = 0;
static int set_zindex = 1;
if (input.click_left_released) {
object_props_setting_state = TileObjectPropSettingStates::OBJECT_SETTING_STATE_TYPE;
size_t id = get_ObjectIdFromTileset({input.mouse_tile_position.x,
input.mouse_tile_position.y});
if (id == SIZE_MAX) return;
Tile::object_selected = true;
Tile::selected_object_id = id;
Tile::selected_position = {input.mouse_tile_position.x, input.mouse_tile_position.y};
Tile::tile_selected = false;
TilesetObject object = active_tileset->objects[selected_object_id];
if (object.object_type != ObjectType::NONE) {
set_type = object.object_type;
set_collectable = object.collectable;
set_zindex = object.z_index;
}
std::cout << "Type: " << Object::to_String(set_type)
<< ", Collectable: " << set_collectable << ", Z-Index: " << set_zindex
<< std::endl;
std::cout << "Setting: ";
} else if (object_selected) {
if (input.pressed_return_released) {
// get to next
object_props_setting_state = static_cast<TileObjectPropSettingStates>(static_cast<int>(object_props_setting_state) + 1);
std::cout << "Setting: ";
switch ( object_props_setting_state ) {
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_TYPE:
std::cout << "-> Type\n active: " << Object::to_String(set_type) << std::endl;
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_COLLECTING_METHODE:
std::cout << "-> Collecting Methode\n active: " << set_collectable << std::endl;
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_ZINDEX_METHODE:
std::cout << "-> Z-Index\n active: " << set_zindex << std::endl;
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_SAVE:
std::cout << "Save ?\n";
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_LAST: {
// Save current
TilesetObject& object = active_tileset->objects[selected_object_id];
object.object_type = set_type;
object.collectable = set_collectable;
object.z_index = set_zindex;
save_Objects();
std::cout << "Saving!"
<< "\n Type :" << Object::to_String(object.object_type)
<< "\n Collectable :" << object.collectable
<< "\n Z-Index :" << object.z_index
<< std::endl;
object_selected = false;
break; }
default:
break;
}
} else if (input.pressed_arrowdown_released) {
switch ( object_props_setting_state ) {
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_TYPE:
set_type = static_cast<ObjectType>(
(static_cast<int>(set_type) + 1) % static_cast<int>(ObjectType::LAST)
);
std::cout << "Type: " << Object::to_String(set_type) << std::endl;
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_COLLECTING_METHODE:
set_collectable = !set_collectable;
std::cout << "Collectable: " << set_collectable << "\n";
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_ZINDEX_METHODE:
set_zindex -= 1;
std::cout << "Z-Index " << set_zindex << "\n";
break;
default:
break;
}
std::cout << "Type: " << Object::to_String(set_type)
<< ", Collectable: " << set_collectable
<< ", Z-Index: "<< set_zindex
<< std::endl;
} else if (input.pressed_arrowup_released) {
switch ( object_props_setting_state ) {
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_TYPE:
{
int type = static_cast<int>(set_type);
int last = static_cast<int>(ObjectType::LAST);
type = (type - 1 + last) % last;
set_type = static_cast<ObjectType>(type);
}
std::cout << "Type: " << Object::to_String(set_type) << std::endl;
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_COLLECTING_METHODE:
set_collectable = !set_collectable;
std::cout << "Collectable: " << set_collectable << "\n";
break;
case TileObjectPropSettingStates::OBJECT_SETTING_STATE_ZINDEX_METHODE:
set_zindex += 1;
std::cout << "Z-Index " << set_zindex << "\n";
break;
default:
break;
}
std::cout << "Type: " << Object::to_String(set_type)
<< ", Collectable: " << set_collectable
<< ", Z-Index: "<< set_zindex
<< std::endl;
}
}
};
void
set_FloorType(Input& input) {
static TileTypeFloors set_type = TileTypeFloors::NONE;
static size_t set_state = 0;
static int set_zindex = 0;
static TilesetFloorProps* props = nullptr;
if (input.click_left_released) {
size_t id = static_cast<size_t>(input.mouse_tile_position.x +
input.mouse_tile_position.y * active_tileset->size.x);
if (id == SIZE_MAX) return;
Tile::tile_selected = false;
Tile::object_selected = true;
Tile::selected_object_id = id;
Tile::selected_position = {input.mouse_tile_position.x, input.mouse_tile_position.y};
set_state = 0;
props = nullptr;
props = &tileset_floor_props[active_tileset->category][id];
if (props->tiletype != NONE) {
set_type = props->tiletype;
set_zindex = props->z_index;
}
std::cout << "Type: " << to_String(set_type) << std::endl;
std::cout << "Z-Index: " << set_zindex << std::endl;
if (set_state == 2) std::cout << "Save?\n";
} else if (object_selected) {
if ( input.pressed_return_released ) {
set_state++;
if (set_state > 2) {
std::cout << "Saving...\n";
props->tiletype = set_type;
props->z_index = set_zindex;
save_TilesetFloorProps();
set_state = 0;
} else
std::cout << "Setting: \n";
std::cout << "Type: " << to_String(set_type) << std::endl;
std::cout << "Z-Index: " << set_zindex << std::endl;
} else if (set_state == 0) {
if (input.pressed_arrowup_released) {
int type = static_cast<int>(set_type);
int last = static_cast<int>(TileTypeFloors::LAST);
type = (type - 1 + last) % last;
set_type = static_cast<TileTypeFloors>(type);
} else if (input.pressed_arrowdown_released) {
set_type = static_cast<TileTypeFloors>(
(static_cast<int>(set_type) + 1) % static_cast<int>(TileTypeFloors::LAST)
);
}
if ( input.pressed_arrowdown_released || input.pressed_arrowup_released || input.pressed_return_released) {
std::cout << "Type: " << to_String(set_type) << std::endl;
}
} else if (set_state == 1) {
if (input.pressed_arrowup_released) {
set_zindex++;
} else if (input.pressed_arrowdown_released) {
set_zindex--;
}
if ( input.pressed_arrowdown_released || input.pressed_arrowup_released) {
std::cout << "Z-Index: " << set_zindex << std::endl;
}
}
}
}
TileTypeFloors
get_FloorType(Tile_s& tile_s) {
SDL_Point& position = tile_s.set_position;
TileSet& tileset = get_TilesetFromMapTile(tile_s);
size_t id = static_cast<size_t>(position.y * tileset.size.x + position.x);
return tileset_floor_props[tile_s.set_category][id].tiletype;
}
TileTypeFloors
get_FloorType(SDL_Point& world_tile) {
if (Map::tile_map[Map::get_IdFromTilePoint(world_tile)].overlays.size() > 0) {
for (Tile_s t : Map::tile_map[Map::get_IdFromTilePoint(world_tile)].overlays) {
if (t.set_position.x == 0 && t.set_position.y == 0)
return TileTypeFloors::SOIL;
}
}
Tile_s& tile_s = Map::tile_map[Map::get_IdFromTilePoint(world_tile)].background;
SDL_Point& position = tile_s.set_position;
TileSet& tileset = get_TilesetFromMapTile(tile_s);
size_t id = static_cast<size_t>(position.y * tileset.size.x + position.x);
return tileset_floor_props[tile_s.set_category][id].tiletype;
}
void
transfer_ToMap(Input& input) {
// If pressing on tileset
if (hovering_set) {
if (!input.click_left) {
if (active_tileset_type == TILE_BACKGROUND || input.pressed_shift) {
Tile::selected_tiles.clear();
for (int y = 0; y < Tile::selection_tile_dimension.y; y++) {
for (int x = 0; x < Tile::selection_tile_dimension.x; x++) {
Tile::selected_tiles.push_back({input.mouse_tile_position.x+x,
input.mouse_tile_position.y+y
});
}
}
Tile::selected_tile_dimension.x = Tile::selection_tile_dimension.x;
Tile::selected_tile_dimension.y = Tile::selection_tile_dimension.y;
Tile::tile_selected = true;
return;
}
size_t id = get_ObjectIdFromTileset({input.mouse_tile_position.x,
input.mouse_tile_position.y});
if (id == SIZE_MAX) return;
Tile::object_selected = true;
Tile::selected_object_id = id;
Tile::selected_position = {input.mouse_tile_position.x, input.mouse_tile_position.y};
Tile::tile_selected = false;
print_TileObject(active_tileset->objects[selected_object_id]);
}
}
// If pressing on map
else if ( input.click_left_released && !input.pressed_c && (Tile::tile_selected || Tile::object_selected) && !Map::setting_offset &&
( input.mouse_tile_position.x >= 0 && input.mouse_tile_position.y >= 0 ) &&
( input.mouse_tile_position.x < Map::size.x ) &&
( input.mouse_tile_position.y < Map::size.y )
) {
std::cout << "MOUS: " << input.mouse_tile_position.x << " " << input.mouse_tile_position.y << std::endl;
// Set selected tile in map
if (Tile::active_tileset_type == TILE_OBJECT) {
TilesetObject object = active_tileset->objects[selected_object_id];
std::vector<bool> collision_map = get_ObjectCollisionsFromTileset(object.tileset_info.set_id, object.tileset_info.object_id, get_Type(object.tileset_info.set_category));
bool has_collission = objec_HasCollission(object);
SDL_Point tile_offset = {
selected_position.x - object.position.x,
selected_position.y - object.position.y
};
int map_origin_x = input.mouse_tile_position.x - tile_offset.x;
int map_origin_y = input.mouse_tile_position.y - tile_offset.y;
std::cout << "WP " << map_origin_x << " " << map_origin_y << std::endl;
TileType type = get_Type(object.tileset_info.set_category);
Resource_s res;
if (object.collectable) {
res = get_ResourceFromTileSet(object.tileset_info.set_id, object.tileset_info.object_id);
}
Object* new_object = !object.collectable ?
new Object(object.object_type,
object.collectable ?
ObjectCategory::RESOURCE :
ObjectCategory::STATIC,
type,
object.tileset_info.set_id,
object.tileset_info.object_id,
{map_origin_x, map_origin_y},
{object.position.w, object.position.h},
object.z_index)
:
new Resource(object.object_type,
ObjectCategory::RESOURCE,
type,
object.tileset_info.set_id,
object.tileset_info.object_id,
{map_origin_x, map_origin_y},
{object.position.w, object.position.h},
object.z_index,
res.resource,
res.quantity,
res.collecting_methode,
res.collecting_duration
);
Object::objects.push_back(new_object);
TileObject o ={ {0,0}, false, new_object->id };
bool tile_exists = false;
bool check_existence = true;
bool draw_is_set = false;
std::cout << "##################################\n";
for (int y = 0; y < object.position.h && !tile_exists; y++) {
for (int x = 0; x < object.position.w && !tile_exists; x++) {
//bool shall_set_on_tile = true;
o.draw_from_this_tile = false;
o.position.x = x; o.position.y = y;
int map_x = map_origin_x + x ;
int map_y = map_origin_y + y ;
if (map_x < 0 || map_y < 0 ||
map_x >= static_cast<int>(Map::size.x) ||
map_y >= static_cast<int>(Map::size.y))
continue;
int index = map_y * static_cast<int>(Map::size.x) + map_x;
if (has_collission) {
size_t s = Tile::tile_size / Tile::tile_collider_size;
size_t width_c = static_cast<size_t>(object.position.w) * s;
bool check = false;
for (size_t yc = static_cast<size_t>(y) * s; yc < static_cast<size_t>(y + 1) * s && !check; yc++) {
for (size_t xc = static_cast<size_t>(x) * s; xc < static_cast<size_t>(x + 1) * s && !check; xc++) {
size_t i = yc * width_c + xc;
if (collision_map[i]) {
check = true;
if (!draw_is_set) {
o.draw_from_this_tile = true;
draw_is_set = true;
}
}
std::cout << (collision_map[i] ? '#' : '.') << ' ';
}
std::cout << '\n';
}
//shall_set_on_tile = check;
std::cout << "---- tile (" << x << "," << y << ") ----\n";
} else {
if (!draw_is_set)
o.draw_from_this_tile = true;
draw_is_set = true;
}
//if (!shall_set_on_tile) continue;
// make sure we dont get dublicates
if (check_existence) {
for (const TileObject& t : Map::tile_map[static_cast<size_t>(index)].objects) {
Object* map_o = Object::get_ObjectById(t.object_id);
if (t.position.x == x && t.position.y == y && map_o->tileset_object_id == selected_object_id) {
std::cout << "Object already set!\n";
tile_exists = true;
break;
}
}
check_existence = false;
if (tile_exists) break;
}
Map::tile_map[static_cast<size_t>(index)].objects.push_back(o);
std::sort(Map::tile_map[static_cast<size_t>(index)].objects.begin(),
Map::tile_map[static_cast<size_t>(index)].objects.end(),
[](const TileObject& a, const TileObject& b) {
return Object::get_ObjectById(a.object_id)->z_index < Object::get_ObjectById(b.object_id)->z_index;
});
//print_TileObject(o);
}
}
// SET OBJECT COLLISION ON TILE_MAP
if (tile_exists) {
delete Object::objects.back();
return;
}
if (!has_collission) return;
Map::set_ObjectCollisionOnTilemap(new_object->id, {map_origin_x, map_origin_y});
return;
}
else if (Tile::active_tileset_type == TILE_BACKGROUND) {
for (int y = 0; y < Tile::selection_tile_dimension.y; y++) {
for (int x = 0; x < Tile::selection_tile_dimension.x; x++) {
int map_x = input.mouse_tile_position.x + x;
int map_y = input.mouse_tile_position.y + y;
if (map_x < Map::size.x && map_y < Map::size.y) {
size_t index = static_cast<size_t>(map_y * Map::size.x + map_x);
// Repeat selection if placing is bigger than original
int wrapped_x = x % Tile::selected_tile_dimension.x;
int wrapped_y = y % Tile::selected_tile_dimension.y;
size_t t_id = static_cast<size_t>(wrapped_y * Tile::selected_tile_dimension.x + wrapped_x);
Tile_s& background = Map::tile_map[index].background;
TileSet tileset = get_TilesetFromMapTile(background);
/*
tile_setting_history.push_back({
TILE_BACKGROUND,
index,
{background.set_id,
background.set_category,
{background.set_position.x,
background.set_position.y
}
}
});
*/
background.set_id = Tile::active_tileset_id;
background.set_position.x = Tile::selected_tiles[t_id].x;
background.set_position.y = Tile::selected_tiles[t_id].y;
background.object_id = static_cast<size_t>(map_y*tileset.size.x + map_x);
background.set_category = Tile::tilesets[TILE_BACKGROUND][background.set_id].category;
}
}
}
}
}
}
void
set_TilesetOffset(Input& input) {
// START UNUSED FUNCTION
// reset scale
if (!input.click_left && tileset_scale_to_set != 0) {
tileset_scale_to_set = 0;
setting_tileset_scale = false;
}
// Set scale
else if (tileset_scale_to_set != 0) {
tileset_scale = input.mouse_state.y - tileset_scale_to_set;
}
// Update scale
if (input.click_left && input.pressed_shift &&
(tileset_scale_to_set == 0)) {
tileset_scale_to_set = input.mouse_state.y - tileset_scale;
setting_tileset_scale = true;
}
// END UNUSED FUNCTION
// Reset tileset offset
if (!input.click_left && tileset_offset_to_set.x != 0 && tileset_offset_to_set.y != 0) {
tileset_offset_to_set.x = 0;
tileset_offset_to_set.y = 0;
setting_tileset_offset = false;
}
// Set tileset offset
else if (tileset_offset_to_set.x != 0 && tileset_offset_to_set.y != 0) {
tileset_offset.x = input.mouse_state.x - tileset_offset_to_set.x;
tileset_offset.y = input.mouse_state.y - tileset_offset_to_set.y;
}
// Update tileset_offset set
if (input.click_left && input.pressed_ctrl &&
(tileset_offset_to_set.x == 0 && tileset_offset_to_set.y == 0)) {
tileset_offset_to_set.x = input.mouse_state.x - tileset_offset.x;
tileset_offset_to_set.y = input.mouse_state.y - tileset_offset.y;
setting_tileset_offset = true;
}
}
Resource_s
get_ResourceFromTileSet(size_t tileset_id, size_t object_id) {
return tilesets[TILE_OBJECT][tileset_id].resources[object_id];
}
TilesetObject
get_ObjectFromTileSet(size_t tileset_id, size_t object_id, TileType type) {
return tilesets[type][tileset_id].objects[object_id];
}
std::vector<bool>
get_ObjectCollisionsFromTileset(size_t tileset_id, size_t object_id, TileType type) {
TileSet& ts = tilesets[type][tileset_id];
auto it = ts.objects.find(object_id);
if (it == ts.objects.end()) {
return {};
}
TilesetObject& obj = it->second;
std::vector<bool> vec;
int scale = Tile::tile_size / Tile::tile_collider_size;
int collider_w = obj.position.w * scale;
int collider_h = obj.position.h * scale;
int collider_x = obj.position.x * scale;
int collider_y = obj.position.y * scale;
int row_width = ts.size.x * scale;
if (collider_x + collider_w > row_width ||
collider_y + collider_h > ts.size.y * scale) {
std::cerr << "Object rectangle out of collider bounds!\n";
return vec;
}
vec.reserve(static_cast<size_t>(collider_w * collider_h));
for (int y = 0; y < collider_h; ++y) {
for (int x = 0; x < collider_w; ++x) {
size_t index = static_cast<size_t>((collider_y + y) * row_width + (collider_x + x));
vec.push_back(ts.collission_map[index]);
}
}
return vec;
}
void
print_CollisionMap(const TilesetObject& obj) {
size_t collider_w = static_cast<size_t>(obj.position.w) * Tile::tile_size / Tile::tile_collider_size;
size_t collider_h = static_cast<size_t>(obj.position.h) * Tile::tile_size / Tile::tile_collider_size;
std::cout << "Collision Map for object "
<< obj.tileset_info.object_id
<< " (collider size: " << collider_w << "x" << collider_h << "):\n";
std::vector<bool> collision_map = get_ObjectCollisionsFromTileset(obj.tileset_info.set_id, obj.tileset_info.object_id, get_Type(obj.tileset_info.set_category));
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 << "? "; // safety: missing data
} else {
std::cout << (collision_map[index] ? "1 " : "0 ");
}
}
std::cout << "\n";
}
}
void
print_TileObject(const TilesetObject& obj) {
std::cout << "TilesetObject {\n";
std::cout << " position: { x: " << obj.position.x
<< ", y: " << obj.position.y
<< ", w: " << obj.position.w
<< ", h: " << obj.position.h << " }\n";
std::cout << " object_type: " << static_cast<int>(obj.object_type) << "\n";
std::cout << " collectable: " << std::boolalpha << obj.collectable << "\n";
std::cout << " z_index: " << obj.z_index << "\n";
std::cout << " tileset_info: {\n";
std::cout << " set_id: " << obj.tileset_info.set_id << "\n";
std::cout << " object_id: " << obj.tileset_info.object_id << "\n";
std::cout << " set_category: " << static_cast<int>(obj.tileset_info.set_category) << "\n";
std::cout << " set_position: { x: " << obj.tileset_info.set_position.x
<< ", y: " << obj.tileset_info.set_position.y << " }\n";
std::cout << " }\n";
std::cout << "}\n";
print_CollisionMap(obj);
}
/*
bool
is_BehindTileObject(TilesetObject object, SDL_FPoint position, SDL_FRect rect) {
const int scale = Tile::tile_size / Tile::tile_collider_size;
const int obj_w = object.position.w * scale;
const int obj_h = object.position.h * scale;
const int obj_x = position.x / scale;
const int obj_y = 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;
//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;
// horizontal overlap?
if (rect_x + rect_w <= obj_x || rect_x >= obj_x + obj_w)
return true;
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;
// rect completely above object
if (rect_y < obj_y)
return true;
int rect_row = rect_y - obj_y;
// rect completely below object
if (rect_row >= obj_h)
return true;
// --------------------------------------------------------
// SCAN COLLIDER ROWS BELOW THE RECT
// --------------------------------------------------------
//bool collission_above = false;
bool collission_below = false;
bool anywhere_above = false;
bool anywhere_below = false;
for (int y = 0; y < obj_h; ++y) {
int base = y * row_width;
for (int x = 0; x < obj_w; ++x) {
if (object.collission_map[static_cast<size_t>(base + x)]) {
if (y < rect_row) {
//std::cout << "ABOVE ";
anywhere_above = true;
if (x > start_x && x < end_x) {
//collission_above = true;
return false;
}
} else {
//std::cout << "BELOW\n";
anywhere_below = true;
if (x > start_x && x < end_x) {
//std::cout << "BELOW";
collission_below = true;
}
}
}
}
}
if (anywhere_below && !collission_below)
return true;
if (collission_below)
return true;
if (!anywhere_above && !collission_below)
return false;
return false;
}
*/
}