Nimbin[12]?SDL & Graphics / mapcreator / commits / a42fef9

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

Bird fix zindex

Christian Immanuel · 2025-12-16 21:00 · a42fef970ad8341af12aca5e21f971edeef058de

 src/bird/bird.cpp           | 109 +++++++++++++++++++++++++++++++++++---------
 src/bird/bird.hpp           |  27 +++++++----
 src/character/character.cpp |   3 --
 src/map/map.cpp             |  22 +++++++++
 4 files changed, 127 insertions(+), 34 deletions(-)

diff --git a/src/bird/bird.cpp b/src/bird/bird.cpp
index 88ca72d..6e4860d 100644
--- a/src/bird/bird.cpp
+++ b/src/bird/bird.cpp
@@ -18,11 +18,17 @@ static constexpr float FLIGHT_HEIGHT = 80.0f;  // Consistent flying altitude
 
 SDL_Texture* Bird::texture;
 
+std::vector<Bird*> Bird::birds{};
+std::atomic<std::uint64_t> Bird::next_id{0};
+
 Bird::Bird(float x, float y)
-    : pos_x(x),
+    : drawn(false),
+      pos_x(x),
       pos_y(y),
+      id(next_id.fetch_add(1, std::memory_order_relaxed)),
       target_pos{x, y},
       decision_timer(0.0) {
+    birds.push_back(this);
     set_State(BirdState::WALKING, 2.4);
 }
 
@@ -33,7 +39,8 @@ bool Bird::Init(SDL_Renderer* renderer) {
 }
 
 void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
-    std::cout << (int)state << " ISTART " << is_starting_to_fly << " ILAND " << is_landing << " XY: "  << pos_x << " " << pos_y << " DC " << decision_timer << " STT: " << state_timer << std::endl;
+    // std::cout << "ALT: " << altitude << std::endl;
+    // std::cout << (int)state << " ISTART " << is_starting_to_fly << " ILAND " << is_landing << " XY: "  << pos_x << " " << pos_y << " DC " << decision_timer << " STT: " << state_timer << std::endl;
     state_timer += delta_s;
     decision_timer -= delta_s;
 
@@ -52,7 +59,7 @@ void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
         eating_timer += delta_s;
         if (eating_timer >= 3.0) {
             set_State(BirdState::START_TO_FLY, 0.0);
-            PickFlyTarget(player_pos);
+            pick_FlyTarget(player_pos);
             return;
         }
     }
@@ -99,13 +106,35 @@ void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
         if (dist > 0.4) {
             float move = speed * delta_s;
             if (move > dist) move = dist;
-            pos_x += (dx / dist) * move;
-            pos_y += (dy / dist) * move;
+
+            float next_px = pos_x + (dx / dist) * move;
+            float next_py = pos_y + (dy / dist) * move;
+            bool can_walk = false;
+            if (Map::is_FreePosition({
+                        next_px - tile_size / 2,
+                        pos_y - tile_size / 2,
+                        tile_size,
+                        tile_size
+                        })) {
+                pos_x = next_px;
+                can_walk = true;
+            }
+            if (Map::is_FreePosition({
+                        pos_x - tile_size / 2,
+                        next_py - tile_size / 2,
+                        tile_size,
+                        tile_size
+                        })) {
+                pos_y += (dy / dist) * move;
+                can_walk = true;
+            }
+            if (!can_walk)
+                set_State(BirdState::IDLE, 0.4);
 
             if (fabsf(dx) > 0.01f) facing_left = (dx < 0.0f);
         } else {
-            set_State(BirdState::IDLE, 0.0);
-            return;
+            std::cout << "BIRD WALK REACHED GOAL" << std::endl;
+            set_State(BirdState::IDLE, 0.4);
         }
     }
     else
@@ -141,12 +170,11 @@ void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
         float y_offset_delta = -((takeoff_progress + y_offset) - takeoff_prev_y_offset);
         takeoff_prev_y_offset = takeoff_progress + y_offset;
 
-        std::cout << "FACIN A: " << facing_left << std::endl;
         facing_left = ( pos_x+x_offset_delta - pos_x < 0.0f);
-        std::cout << "FACIN B: " << facing_left << std::endl;
 
         pos_x += x_offset_delta;
         pos_y += y_offset_delta;
+        altitude += y_offset_delta*-1;
 
         // If finished takeoff, align for straight flight
         if (takeoff_progress >= FLIGHT_HEIGHT) {
@@ -159,7 +187,7 @@ void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
             facing_left = (target_pos.x - pos_x < 0.0f);
         }
 
-        std::cout << "DEL: " << x_offset_delta << " " << y_offset_delta << std::endl;
+        // std::cout << "DEL: " << x_offset_delta << " " << y_offset_delta << std::endl;
     }
     // Handle landing animation with circular arc (position-based)
     else if (is_landing) {
@@ -169,6 +197,7 @@ void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
         if (landing_progress >= FLIGHT_HEIGHT) {
         // if (fabs(target_pos.y - landing_start_y) >= FLIGHT_HEIGHT+1) {
             std::cout << "STOP FLYING! START LANDING" << std::endl;
+            altitude = 0.0f;
             set_State(BirdState::STOP_FLYING, 0.0);
             return;
         }
@@ -197,6 +226,7 @@ void Bird::Update(double delta_s, const SDL_FPoint& player_pos) {
         if (fabsf(dx) > 0.01f) {
             facing_left = (dx < 0.0f);
         }
+        altitude -= y_offset_delta;
         pos_x += x_offset_delta;
         pos_y += y_offset_delta;
     }
@@ -238,10 +268,13 @@ void Bird::set_Position(SDL_FPoint point) {
 
 void Bird::set_State(BirdState new_state, double dec_timer) {
 
+    std::cout << "BIRD SET STATE " << (int)new_state << std::endl;
     decision_timer = dec_timer;
 
+    /*
     if (state == new_state)
         return;
+    */
 
     state = new_state;
     state_timer = 0.0f;
@@ -268,13 +301,13 @@ void Bird::set_State(BirdState new_state, double dec_timer) {
 
         case BirdState::EATING:
             current_frame = 0;
-            //eating_timer = 0.0;
             set_Animation(3, 3, 0.15);
             break;
 
         case BirdState::START_TO_FLY: {
             current_frame = 0;
             is_starting_to_fly = true;
+            altitude = 0.0f;
             set_Animation(4, 8, 0.06);
             decision_timer = 8*0.06;
             takeoff_progress = 0.0f;
@@ -322,6 +355,7 @@ void Bird::Decide(const SDL_FPoint& player_pos) {
     float dy = pos_y - player_pos.y;
     float dist_sq = dx * dx + dy * dy;
 
+    std::cout << "START DECIED\n";
     // If too far, fly closer
     if ( dist_sq > MAX_RADIUS * MAX_RADIUS &&
          state != BirdState::FLYING &&
@@ -329,19 +363,21 @@ void Bird::Decide(const SDL_FPoint& player_pos) {
          state != BirdState::START_TO_FLY) {
         std::cout << "BIRD TARGET TOO FAR\n";
         set_State(BirdState::START_TO_FLY, 0.0);
-        PickFlyTarget(player_pos);
+        pick_FlyTarget(player_pos);
         return;
     }
     if (state == BirdState::START_TO_FLY) {
+        std::cout << "FUU 1 " << std::endl;
         set_State(BirdState::FLYING, 0.0);
         return;
     }
 
     // Random behavior when close to player
     int   choice   = rand() % 100;
-    float duration = rand() %  80 * 0.1f + 1.1f;
+    float duration = rand() %  70 * 0.1f + 1.1f;
 
     if (state == BirdState::STOP_FLYING) {
+        std::cout << "FUU 2 " << std::endl;
         set_State(BirdState::IDLE, duration);
         return;
     }
@@ -351,22 +387,27 @@ void Bird::Decide(const SDL_FPoint& player_pos) {
     }
     else if (choice < 50) {
         set_State(BirdState::WALKING, duration);
-        PickGroundTarget(player_pos);
+        pick_GroundTarget(player_pos);
     }
     else if (choice < 75) {
         set_State(BirdState::IDLE, duration);
     }
     else {
         set_State(BirdState::START_TO_FLY, 0.0);
-        PickFlyTarget(player_pos);
+        std::cout << "PDECIDE PICK START\n";
+        pick_FlyTarget(player_pos);
+        std::cout << "PDECIDE PICK END\n";
     }
+    std::cout << "END\n";
 }
 
-void Bird::PickFlyTarget(const SDL_FPoint& player_pos) {
+void Bird::pick_FlyTarget(const SDL_FPoint& player_pos) {
     const float MIN_DIST = MAX_RADIUS; // minimum distance from current position
 
     float angle, radius, dx, dy, dist_sq;
-    do {
+    constexpr int max_attempts = 100;
+
+    for (int i = 0; i < max_attempts; ++i) {
         angle = (rand() % 628) / 100.0f;  // 0 to ~2*PI
         radius = MIN_RADIUS + (rand() % static_cast<int>(MAX_RADIUS - MIN_RADIUS));
 
@@ -381,11 +422,35 @@ void Bird::PickFlyTarget(const SDL_FPoint& player_pos) {
         dy = target_pos.y - pos_y;
         dist_sq = dx * dx + dy * dy;
 
-    } while (dist_sq < MIN_DIST * MIN_DIST);  // ensure minimum distance
+        if (!Map::is_FreePosition({
+                    target_pos.x - tile_size / 2,
+                    target_pos.y - tile_size / 2,
+                    tile_size,
+                    tile_size
+                    }))
+            dist_sq = MIN_DIST*MIN_DIST+1;
+
+        if (dist_sq >= MIN_DIST * MIN_DIST)
+            return;
+    };
+    set_State(BirdState::IDLE, 0.8);
 }
 
-void Bird::PickGroundTarget(const SDL_FPoint& player_pos) {
-    float offset = static_cast<float>((rand() % 64) - 32);  // -32 to +32
-    target_pos.x = player_pos.x + offset;
-    target_pos.y = player_pos.y;
+void Bird::pick_GroundTarget(const SDL_FPoint& player_pos) {
+    constexpr int max_attempts = 100;
+
+    for (int i = 0; i < max_attempts; ++i) {
+        float offset_x= static_cast<float>((rand() % 64) - 32);  // -32 to +32
+        float offset_y= static_cast<float>((rand() % 64) - 32);  // -32 to +32
+        target_pos.x = player_pos.x + offset_x;
+        target_pos.y = player_pos.y + offset_y;
+        if (Map::is_FreePosition({
+                    target_pos.x - tile_size / 2,
+                    target_pos.y - tile_size / 2,
+                    tile_size,
+                    tile_size
+                    }))
+            return;
+    };
+    set_State(BirdState::IDLE, 0.8);
 }
diff --git a/src/bird/bird.hpp b/src/bird/bird.hpp
index c683fe3..e5456c6 100644
--- a/src/bird/bird.hpp
+++ b/src/bird/bird.hpp
@@ -1,5 +1,10 @@
 #pragma once
 
+#include <SDL3/SDL.h>
+#include <cstdint>
+#include <vector>
+#include <atomic>
+
 static constexpr float MIN_RADIUS = 124.f;
 static constexpr float MAX_RADIUS = 164.f;
 static constexpr float FLY_SPEED  =  42.f;
@@ -16,19 +21,23 @@ enum class BirdState {
     ATTACK      // 6
 };
 
-#include <SDL3/SDL.h>
-#include <cstdint>
-
 class Bird {
 public:
+    static std::vector<Bird*> birds;
+    bool drawn;
+    float altitude = 0.0f;
+
+    float pos_x = 0;
+    float pos_y = 0;
+
     Bird(float x, float y);
 
     static bool Init(SDL_Renderer*);
 
     void Update(double delta_s, const SDL_FPoint& player_pos);
     void Decide(const SDL_FPoint& player_pos);
-    void PickFlyTarget(const SDL_FPoint& player_pos);
-    void PickGroundTarget(const SDL_FPoint& player_pos);
+    void pick_FlyTarget(const SDL_FPoint& player_pos);
+    void pick_GroundTarget(const SDL_FPoint& player_pos);
 
 
     void Render(SDL_Renderer* renderer);
@@ -39,19 +48,19 @@ public:
     BirdState get_State() const;
 
 private:
+    static std::atomic<std::uint64_t> next_id;
+    std::uint64_t id;
+
+
     void set_Animation(int row, int frames, double frame_time);
 
     static SDL_Texture* texture;
 
-    float pos_x = 0;
-    float pos_y = 0;
-
     SDL_FPoint velocity{0.f, 0.f};
     SDL_FPoint target_pos{0.f, 0.f};
 
     double state_timer      = 0.0;
     double decision_timer   = 0.0;
-    double eating_timer     = 0.0;
 
     bool is_landing  = false;
     bool is_starting_to_fly = false;
diff --git a/src/character/character.cpp b/src/character/character.cpp
index 0127f60..ed38916 100644
--- a/src/character/character.cpp
+++ b/src/character/character.cpp
@@ -305,9 +305,6 @@ Character::Draw(SDL_Renderer* renderer) {
     float center_x = x + (src.w * 0.5f);
     float start_y  = y - row_h - 2.0f;
     messages->Render(renderer, center_x, start_y);
-
-    // DRAW BIRD
-    bird->Render(renderer);
 }
 
 /*
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 737af21..31980fa 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -10,6 +10,7 @@
 #include "building/building.hpp"
 #include "game/game.hpp"
 #include "farm/farm.hpp"
+#include "bird/bird.hpp"
 
 namespace Map {
 
@@ -693,6 +694,9 @@ namespace Map {
         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];
 
@@ -707,6 +711,7 @@ namespace Map {
             // Render Character if no object is hiding it
             player_behind = false;
 
+            // DRAW BIRD
             for (TileObject& o : tilemap.objects) {
                 Object* object = Object::get_ObjectById(o.object_id);
                 // o = relative position,
@@ -821,6 +826,23 @@ namespace Map {
                 }
                 j++;
             }
+            for (Bird* bird : Bird::birds) {
+                if (bird->drawn)
+                    continue;
+                if ( static_cast<int>(bird->pos_x/Tile::tile_size) != x_i ||
+                        static_cast<int>((bird->pos_y+bird->altitude)/Tile::tile_size) != y_i)
+                    continue;
+
+                bird->Render(renderer);
+                bird->drawn = true;
+            }
+        }
+        for (Bird* bird : Bird::birds) {
+            if (bird->drawn)
+                continue;
+
+            bird->Render(renderer);
+            bird->drawn = true;
         }
     }