Nimbin[12]?SDL & Graphics / mapcreator / src/character/enemy.hpp

mapcreator git · master

SDL3 2.5D game and engine using assets, with map editor

sdl3 c++ game engine map-editor cmake · first commit 2025-10-31 · last commit 2026-09-07 (1 month ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-spieleentwicklung/map_creator

C++ 99.3%
git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gz
src/character/enemy.hpp 5.6 KB · 270 lines raw
#pragma once

#include <algorithm>
#include <mutex>
#include <condition_variable>

#include "animation.hpp"
#include "objects/object.hpp"
#include "inventory/weapon.hpp"

class Character;
class Enemy;

enum class EnemyStatus {
    IDLE,
    RUN,
    ATTACK,
    HIT,
    DEAD,
    DYING,
};

struct EnemyAnimation {
    std::unordered_map<WalkDirection, AnimationData> idle;
    std::unordered_map<WalkDirection, AnimationData> run;
    std::unordered_map<WalkDirection, AnimationData> attack;
    std::unordered_map<WalkDirection, AnimationData> hit;
    std::unordered_map<WalkDirection, AnimationData> death;
};

struct EnemyStats {
    float health;
    float health_max;

    float demage;
    bool  is_attacking;
    bool  has_attacked;
    float attack_duration;
    float attack_duration_max;
};

struct CollisionInterval {
    float min_x, max_x;
    float min_y, max_y;
    bool valid;
};

struct SpawnParams {
    double spawn_date;
    WeaponType type;
    WeaponMaterial material;
    SDL_FPoint pos;
    EnemyStats stats;
};


struct EnemyMoveThreadData {
    Enemy* enemy;
    SDL_FPoint player;
    bool is_moving;
};

enum class EnemyMovingType : uint32_t {
    NONE,
    IDLE,
    CHARACTER,
    OBJECT,
    WALK,
    LAST
};
struct EnemyMovingLogic {
    EnemyMovingType move_type = EnemyMovingType::NONE;
    void*      object = nullptr;
    SDL_FPoint position = {0,0};
    bool       position_changed = true;
    float      duration = 0.0f;
    int        max_distance = 120;
    int        min_distance = 80;
    double     path_blocked = 0; // time when blocked?
    bool       avoid_blockage = false;
    SDL_FPoint moving_distance = {0,0};
};

struct WorkerData {
    Enemy* enemy;
    std::shared_ptr<std::vector<bool>> grid; // use shared_ptr for safety
};

class Enemy {
    static int id_next;
           int id;
    float  speed;
    float  run; // multiplier
    bool   flip;
    static size_t tile_size;
    float  arm_reach_radius;

    float detection_radius;

    public:
    static SDL_FPoint colider_default;
    static std::vector<Enemy*> enemies;
    static std::vector<SpawnParams> enemies_to_spawn;


    EnemyMovingLogic moving_logic = {EnemyMovingType::NONE, nullptr};

    bool            moving;
    EnemyMovingType move_focus = EnemyMovingType::NONE;
    float x, y;
    SDL_FPoint next_position = {0,0};
    SDL_FRect  collider;

    CollisionInterval last_object_collision = {0,0,0,0,false};
    bool       avoiding_object  = false;
    SDL_FPoint avoidance_target = {0,0};
    std::vector<SDL_FPoint> avoidance_targets;

    Enemy* collidiing_with_enemy = nullptr;

    CollisionInterval last_map_collision = {0,0,0,0,false};
    bool avoiding_map = false;

    float dist_min = 24;
    float dist_max = 32;

    bool is_character_in_range = false;
    int  stuck_moves = 0;

    std::vector<SDL_FPoint> next_moves;
    SDL_Point last_player_pos{};
    SDL_Point last_target_pos{};


    AnimationData* active_anim;
    static EnemyAnimation animation_all;
    EnemyAnimation animation;
    WalkDirection  direction;
    std::unordered_map<WalkDirection, bool>  direction_blocked;
    bool direction_tested_up;
    bool direction_tested_left;

    EnemyStatus    status;

    Weapon weapon;

    EnemyStats stats;
    float max_death_time;

    float death_duration;
    float death_duration_max;

    bool point_in_reach;

    Enemy(WeaponType weapon_type,
            WeaponMaterial weapon_material, SDL_FPoint position, EnemyStats status);

    std::unordered_map<ResourceType,size_t> resources;

    SDL_FPoint    collider_world;
    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();
    static void
    init_All(SDL_Renderer*);

    void
    set_Status(const EnemyStatus&);
    void
    handle_Animation();

    void
    Draw(SDL_Renderer* renderer);

    static void
    init_SpawnEnemy(double delay_to_spawn_in_sec, WeaponType weapon_type, WeaponMaterial weapon_material, SDL_FPoint position, EnemyStats status);
    static bool
    spawn_Enemy(SpawnParams&);

    static Enemy*
    is_InEnemyReach(const SDL_FRect& rect);

    void
    Decide(Character& player);

    bool
    set_CollisinnWithEnemy(const SDL_FRect& rect);

    static bool
    is_CollidingWithEnemy(const SDL_FRect& rect);

    bool
    is_CollidingWithObjects(const SDL_FRect& rect);

    bool
    is_CollidingWithWorld(const SDL_FRect& rect);

    bool
    is_Colliding(const SDL_FRect& rect);

    inline bool character_InRange(SDL_FPoint char_pos) const;

    void
    compute_MapCollisionInterval(size_t cx, size_t cy, size_t max_x, size_t max_y);

    void death();

    static void remove_Dead();

    // void // OLD??
    // move_ToPosition(SDL_FPoint move_to_position);

    void
    set_AlignPosition(const SDL_FPoint& player);

    void
    set_NextMoves(const std::vector<bool>& map_tiles);

    void
    move_Path();

    void
    set_MoveLogic(EnemyMovingType&, Character& player);

    void
    Update(Character& player);

    void
    attack_Start();

    void
    Attack(bool in_reach);

    void
    attack_Stop();

    void
    getting_Hit(float demage);

    void
    set_TilesInReach();




    static bool
    save_All(const std::string &path);
    static bool
    load_All(const std::string &path);
};