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.gzFix enemy thread pool
src/character/character.cpp | 10 +++- src/character/character.hpp | 4 +- src/character/enemy.cpp | 141 +++++++++++++++++++++++++++++--------------- src/character/enemy.hpp | 27 ++++++++- src/inventory/inventory.hpp | 8 ++- src/inventory/item.cpp | 6 +- 6 files changed, 137 insertions(+), 59 deletions(-) diff --git a/src/character/character.cpp b/src/character/character.cpp index 524279e..d0aa87c 100644 --- a/src/character/character.cpp +++ b/src/character/character.cpp @@ -816,7 +816,7 @@ Character::attack_Enemy() { Enemy* enemy = Enemy::is_InEnemyReach(weaponrect); if (enemy && enemy->stats.health > 0) - enemy->getting_Hit(stats.demage); + enemy->getting_Hit(damage_Get()); attacking_logic.has_attacked = true; } @@ -1168,6 +1168,14 @@ Character::stamina_StopReg() { stamina_regen_logic.delay_is = 0; } +float +Character::damage_Get() { + if (!using_Weapon()) + return 0.0f; + std::cout << "DAMA " << static_cast<InventoryItem*>(selected_item)->damage << std::endl; + return static_cast<InventoryItem*>(selected_item)->damage; +} + void Character::thirst_Drain() { diff --git a/src/character/character.hpp b/src/character/character.hpp index 4d550d3..9f072c2 100644 --- a/src/character/character.hpp +++ b/src/character/character.hpp @@ -53,7 +53,7 @@ enum class CharacterStatus { struct CharacterMoveLogic { SDL_FPoint move_to_position; - bool automove; + bool automove = false; }; struct CharacterCollectingLogic { @@ -256,6 +256,8 @@ class Character { void stamina_StartReg(); void stamina_StopReg(); + float damage_Get(); + TileObject* find_ClosestObject(SDL_Point* tile_found, ObjectCategory category = ObjectCategory::NONE); void collect_Start(TileObject* map_object_p, SDL_Point tile_point); void collect_Object(); diff --git a/src/character/enemy.cpp b/src/character/enemy.cpp index a445ea4..050ab78 100644 --- a/src/character/enemy.cpp +++ b/src/character/enemy.cpp @@ -14,6 +14,17 @@ SDL_FPoint Enemy::colider_default = {7, 7}; EnemyAnimation Enemy::animation_all; size_t Enemy::tile_size = 64; +// Persistent thread pool +std::vector<SDL_Thread*> Enemy::workers; +std::vector<WorkerData> Enemy::job_queue; +std::mutex Enemy::queue_mutex; +std::condition_variable Enemy::queue_cv; + +bool Enemy::stop_threads = false; + +int Enemy::jobs_remaining = 0; +std::condition_variable Enemy::jobs_done_cv; + Enemy::Enemy(WeaponType weapon_type, WeaponMaterial weapon_material, SDL_FPoint position, EnemyStats status) : weapon(weapon_type, weapon_material) { x = position.x; @@ -73,6 +84,8 @@ Enemy::init_All(SDL_Renderer* renderer) { animation_all.death[WalkDirection::DOWN] = Animation::load(renderer, "Pixel_Crawler/Entities/Mobs/Skeleton Crew/Skeleton - Base/Death/Death-Sheet_processed.png", tile_size, tile_size, "None", false, false); animation_all.death[WalkDirection::SIDE] = Animation::load(renderer, "Pixel_Crawler/Entities/Mobs/Skeleton Crew/Skeleton - Base/Death/Death-Sheet_processed.png", tile_size, tile_size, "None", false, false); animation_all.death[WalkDirection::UP] = Animation::load(renderer, "Pixel_Crawler/Entities/Mobs/Skeleton Crew/Skeleton - Base/Death/Death-Sheet_processed.png", tile_size, tile_size, "None", false, false); + + init_Workers(10); } @@ -295,11 +308,6 @@ Enemy::is_InEnemyReach(const SDL_FRect& rect) { return nullptr; } -struct WorkerData { - Enemy* enemy; - const std::vector<bool>* grid; -}; - /* static inline double ms_since(Uint64 start) { static const double freq = static_cast<double>(SDL_GetPerformanceFrequency()); @@ -307,72 +315,106 @@ static inline double ms_since(Uint64 start) { } */ -void Enemy::run_GetMovesThreads() { - //Uint64 t0 = SDL_GetPerformanceCounter(); +int EnemyWorkerThread(void*) { + std::cout << "WORK!\n"; + while (true) { + std::unique_lock<std::mutex> lock(Enemy::queue_mutex); + Enemy::queue_cv.wait(lock, [] { + return Enemy::stop_threads || !Enemy::job_queue.empty(); + }); - std::vector<bool> grid = Map::tile_collission_map; - //std::cout << "grid copy: " << ms_since(t0) << " ms\n"; + if (Enemy::stop_threads && Enemy::job_queue.empty()) + return 0; - //Uint64 t1 = SDL_GetPerformanceCounter(); + WorkerData job = Enemy::job_queue.back(); + Enemy::job_queue.pop_back(); + lock.unlock(); - std::set<int> checks = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 32, 64, 128, 256}; - for (Enemy* enemy : Enemy::enemies) { - if (enemy->moving_logic.move_type != EnemyMovingType::WALK || - !checks.count(enemy->next_moves.size())) - continue; + job.enemy->set_NextMoves(*job.grid); - int tx = static_cast<int>(enemy->collider_world.x / Tile::tile_collider_size); - int ty = static_cast<int>(enemy->collider_world.y / Tile::tile_collider_size); + std::lock_guard<std::mutex> finish_lock(Enemy::queue_mutex); + if (--Enemy::jobs_remaining == 0) + Enemy::jobs_done_cv.notify_one(); + } +} - if (tx < 0 || ty < 0 || - tx >= static_cast<int>(Map::size.x * Tile::tile_collider_size) || - ty >= static_cast<int>(Map::size.y * Tile::tile_collider_size)) - continue; +void Enemy::init_Workers(int num_threads) { + stop_threads = false; + jobs_remaining = 0; + for (int i = 0; i < num_threads; ++i) { + SDL_Thread* th = SDL_CreateThread(EnemyWorkerThread, "EnemyWorker", nullptr); + workers.push_back(th); + } +} - size_t id = static_cast<size_t>(ty * (Map::size.x * Tile::tile_collider_size) + tx); - grid[id] = true; +void Enemy::shutdown_Workers() { + { + std::lock_guard<std::mutex> lock(queue_mutex); + stop_threads = true; } + queue_cv.notify_all(); - //std::cout << "grid marking: " << ms_since(t1) << " ms\n"; - //Uint64 t2 = SDL_GetPerformanceCounter(); + for (SDL_Thread* th : workers) { + SDL_WaitThread(th, nullptr); + } + workers.clear(); +} - std::vector<WorkerData> jobdata; - jobdata.reserve(Enemy::enemies.size()); +void Enemy::run_GetMovesThreads() +{ + std::vector<bool> grid = Map::tile_collission_map; - std::vector<SDL_Thread*> workers; - workers.reserve(Enemy::enemies.size()); + std::set<int> checks = {0,1,2,3,4,5,6,7,8,12,16,32,64,128,256}; + // ---- First pass: mark grid exactly like old version ---- for (Enemy* e : Enemy::enemies) { - if (e->point_in_reach) + if (e->moving_logic.move_type != EnemyMovingType::WALK || + !checks.count(e->next_moves.size())) continue; - jobdata.push_back({ e, &grid }); + int tx = static_cast<int>(e->collider_world.x / Tile::tile_collider_size); + int ty = static_cast<int>(e->collider_world.y / Tile::tile_collider_size); - SDL_Thread* th = SDL_CreateThread( - [](void* data) -> int { - auto* d = static_cast<WorkerData*>(data); - d->enemy->set_NextMoves(*d->grid); - return 0; - }, - "EnemyWorker", - &jobdata.back() - ); + if (tx < 0 || ty < 0 || + tx >= static_cast<int>(Map::size.x * Tile::tile_collider_size) || + ty >= static_cast<int>(Map::size.y * Tile::tile_collider_size)) + continue; - workers.push_back(th); + size_t id = static_cast<size_t>( + ty * (Map::size.x * Tile::tile_collider_size) + tx); + + grid[id] = true; } - //std::cout << "thread creation: " << ms_since(t2) << " ms\n"; - //Uint64 t3 = SDL_GetPerformanceCounter(); + auto grid_ptr = std::make_shared<std::vector<bool>>(std::move(grid)); - for (SDL_Thread* th : workers) - SDL_WaitThread(th, nullptr); + // ---- Wait for previous frame to finish ---- + { + std::unique_lock<std::mutex> lock(queue_mutex); + jobs_done_cv.wait(lock, [] { return jobs_remaining == 0; }); + } - //std::cout << "thread execution + join: " << ms_since(t3) << " ms\n"; - //std::cout << "total: " << ms_since(t0) << " ms\n"; -} + // ---- Push jobs ---- + { + std::lock_guard<std::mutex> lock(queue_mutex); + for (Enemy* e : Enemy::enemies) { + if (e->point_in_reach) + continue; + job_queue.push_back({ e, grid_ptr }); + ++jobs_remaining; + } + } + + queue_cv.notify_all(); + // ---- Wait like old SDL_WaitThread loop ---- + { + std::unique_lock<std::mutex> lock(queue_mutex); + jobs_done_cv.wait(lock, [] { return jobs_remaining == 0; }); + } +} @@ -385,6 +427,7 @@ void Enemy::Decide(Character& player) { //size_t dc_y = static_cast<size_t>(abs(d_y)); EnemyMovingType r = (move_focus != EnemyMovingType::NONE) ? move_focus: static_cast<EnemyMovingType>(1 + (rand() % static_cast<int>(EnemyMovingType::LAST)-1)); + r = EnemyMovingType::CHARACTER; set_MoveLogic(r, player); std::cout << "DEB " << (int) status << std::endl; } @@ -989,6 +1032,7 @@ Enemy::Update(Character& player) { if (move_focus == EnemyMovingType::CHARACTER) { moving_logic.duration -= Default::delta_time; // std::cout << moving_logic.duration << std::endl; + std::cout << "NEXT MOVES: " << next_moves.size() << std::endl; if ((point_moved && moving_logic.duration <= 0) || moving_logic.move_type != EnemyMovingType::CHARACTER) { set_MoveLogic(moving_logic.move_type, player); return; @@ -1087,6 +1131,7 @@ Enemy::attack_Stop() { void Enemy::getting_Hit(float demage) { // if (status != EnemyStatus::HIT) set_Status(EnemyStatus::HIT); + std::cout << "ENEM " << stats.health << " " << demage << std::endl; stats.health -= demage; #ifdef DEBUG_BUILD diff --git a/src/character/enemy.hpp b/src/character/enemy.hpp index a8b17ca..7cc893c 100644 --- a/src/character/enemy.hpp +++ b/src/character/enemy.hpp @@ -1,6 +1,8 @@ #pragma once #include <algorithm> +#include <mutex> +#include <condition_variable> #include "animation.hpp" #include "objects/object.hpp" @@ -77,6 +79,11 @@ struct EnemyMovingLogic { SDL_FPoint moving_distance = {0,0}; }; +struct WorkerData { + Enemy* enemy; + std::shared_ptr<std::vector<bool>> grid; // use shared_ptr for safety +}; + class Enemy { float speed; float run; // multiplier @@ -145,6 +152,23 @@ class Enemy { SDL_Point tile_world; std::vector<SDL_Point> tiles_in_reach; + // START THREAD + static std::vector<SDL_Thread*> workers; + static std::vector<WorkerData> job_queue; + static std::mutex queue_mutex; + static std::condition_variable queue_cv; + + static bool stop_threads; + + // Job completion tracking + static int jobs_remaining; + static std::condition_variable jobs_done_cv; + + static void init_Workers(int num_threads); + static void shutdown_Workers(); + static void run_GetMovesThreads(); + // END THREAD + void Init(); @@ -167,9 +191,6 @@ class Enemy { static Enemy* is_InEnemyReach(const SDL_FRect& rect); - static void - run_GetMovesThreads(); - void Decide(Character& player); diff --git a/src/inventory/inventory.hpp b/src/inventory/inventory.hpp index e87b719..76810e0 100644 --- a/src/inventory/inventory.hpp +++ b/src/inventory/inventory.hpp @@ -33,9 +33,10 @@ struct Inventory_s { struct InventoryItem : Inventory_s { ItemType type = ItemType::HAND; int health_current = 0; - int health_max = 0; - float speed = 0; - int level = 0; + int health_max = 0; + float speed = 0; + int level = 0; + float damage = 0; InventoryItem(size_t d, ItemType t) : Inventory_s(d, InventoryObjectType::ITEM), type(t) @@ -44,6 +45,7 @@ struct InventoryItem : Inventory_s { health_current = info.base_health; health_max = info.base_health; speed = info.base_speed; + damage = info.base_damage; level = 1; equipement_slot = info.equipement_slot; } diff --git a/src/inventory/item.cpp b/src/inventory/item.cpp index f53eded..6d2c46c 100644 --- a/src/inventory/item.cpp +++ b/src/inventory/item.cpp @@ -58,7 +58,7 @@ namespace Item { ItemType::SWORD_WOOD, "Sword wood", { {ResourceType::WOOD, 6} }, - 1, // base_damage + 2, // base_damage 0, // base_armor 20, // base_health 0.8, // base_speed @@ -76,7 +76,7 @@ namespace Item { ItemType::SWORD_STONE, "Sword stone", { {ResourceType::WOOD, 2}, {ResourceType::STONE, 4} }, - 3, // base_damage + 4, // base_damage 0, // base_armor 30, // base_health 1.6, // base_speed @@ -94,7 +94,7 @@ namespace Item { ItemType::WOODAXE_STONE, "Wood Axe made of stone", { {ResourceType::WOOD, 3}, {ResourceType::STONE, 5} }, - 1, // base_damage + 2, // base_damage 0, // base_armor 30, // base_health 1.5, // base_speed