Nimbin2git.christianimmanuel.de / Games / Entropie / commits / eea4011

Entropie git · main

git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gz

Broken state NewAllObj

Christian Immanuel · 2025-02-03 11:20 · eea4011bbba8a1e3e7abc8afde0f1ada870bfde5

 CMakeLists.txt |  10 +++--
 camera.c       |  14 +++----
 camera.h       |   5 ++-
 character.c    |  22 +++++-----
 character.h    |  17 ++------
 collectable.c  |  11 +++++
 collectable.h  |  18 +++++++++
 main.c         |  60 ++++++++++++++++++---------
 map.c          |  89 +++++++++++++++++++++++++---------------
 map.h          |  18 +++++----
 object.c       | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 object.h       |  32 +++++++++++++++
 render.c       |  95 ++++++++++++++++++++++++++++++++++++-------
 render.h       |   4 +-
 14 files changed, 407 insertions(+), 114 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c2fd98..df4b55b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,11 +6,13 @@ project(FestivalGame C)
 
 # Define source files
 set(SOURCES
-    main.c
-    map.c
-    character.c
-    render.c
     camera.c
+	character.c
+	collectable.c
+	main.c
+	map.c
+	object.c
+	render.c
 )
 
 # Include directories
diff --git a/camera.c b/camera.c
index 65299c1..5702528 100644
--- a/camera.c
+++ b/camera.c
@@ -2,24 +2,20 @@
 
 extern int MAP_WIDTH;
 extern int MAP_HEIGHT;
-extern float MAP_CENTER_X;
-extern float MAP_CENTER_Y;
-extern float WINDOW_WIDTH;
-extern float WINDOW_HEIGHT;
 extern const int TILE_SIZE;
 
 
 
 void setCamera(Camera* camera) {
         // Calculate camera offset
-        camera->offset_x = MAP_CENTER_X - (WINDOW_WIDTH / 2);
-        camera->offset_y = MAP_CENTER_Y - (WINDOW_HEIGHT / 2);
+        camera->offset_x = camera->center_x - (camera->view_w / 2);
+        camera->offset_y = camera->center_y - (camera->view_h / 2);
 
-        // Calculate window bounds in terms of tiles
+        // Calculate  bounds in terms of tiles
         camera->min_x = (int)(camera->offset_x / TILE_SIZE);
-        camera->max_x = (int)((camera->offset_x + WINDOW_WIDTH) / TILE_SIZE);
+        camera->max_x = (int)((camera->offset_x + camera->view_w) / TILE_SIZE);
         camera->min_y = (int)(camera->offset_y / TILE_SIZE);
-        camera->max_y = (int)((camera->offset_y + WINDOW_HEIGHT) / TILE_SIZE);
+        camera->max_y = (int)((camera->offset_y + camera->view_h) / TILE_SIZE);
 
         // Ensure bounds are within map limits
         camera->min_x = (camera->min_x < 0) ? 0 : camera->min_x;
diff --git a/camera.h b/camera.h
index 2624d8d..2989a6a 100644
--- a/camera.h
+++ b/camera.h
@@ -5,14 +5,17 @@ typedef struct {
     // Calculate the camera offset once
     float offset_x;
     float offset_y;
+    float center_x;
+    float center_y;
 
     // Calculate the window bounds in terms of tiles
     int min_x;
     int max_x;
     int min_y;
     int max_y;
+    float view_w, view_h;
 
-
+    void* render_object;
 } Camera;
 
 void setCamera(Camera* camera);
diff --git a/character.c b/character.c
index 40d3235..8624410 100644
--- a/character.c
+++ b/character.c
@@ -10,62 +10,60 @@ char* strdup(const char* s);
 
 
 // Function to create a new character
-Character Character_create(const char *name, int energy, int friendliness, int creativity, Position pos) {
+Character Character_create(const char *name, int energy, int friendliness, int creativity) {
     Character c;
     c.name = strdup(name);
     c.energy = energy;
     c.friendliness = friendliness;
     c.creativity = creativity;
-    c.position = pos;
+    c.object = (Object*)malloc(sizeof(Object));
     return c;
 }
 
 
 // Function to create characters with constant values and return the array
-Character* Character_creates(int* size) {
+Character* Character_creates(Object* object_first, int* size) {
     *size = 4;  // Set the number of characters
     Character* characters = malloc(sizeof(Character) * (*size));  // Allocate memory for the characters
+    for (int i = 0; i < *size; i++) {
+        characters[i].object = Object_create_pos(0,0,20,30);
+        Object_add(object_first, characters[i].object);
+        characters[i].object->parent_type = Object_Character;
+        characters[i].object->parent = (void*)&characters[i];
+    }
 
     // Initialize each character with constant values
     characters[0].name = "Bob";
-    characters[0].dimension = (Dimension){20,30};
     characters[0].color = (Color){0, 0, 255, 255};
     characters[0].energy = 50;
     characters[0].friendliness = 80;
     characters[0].creativity = 70;
     characters[0].role = "Organizer";
     characters[0].preferences = "Music, Dance";
-    characters[0].position = (Position){0, 0};
 
     characters[1].name = "Alice";
-    characters[1].dimension = (Dimension){20,30};
     characters[1].color = (Color){255, 0, 255, 255};
     characters[1].energy = 40;
     characters[1].friendliness = 60;
     characters[1].creativity = 90;
     characters[1].role = "Performer";
     characters[1].preferences = "Singing, Acting";
-    characters[1].position = (Position){0, 0};
 
     characters[2].name = "Charlie";
-    characters[2].dimension = (Dimension){20,30};
     characters[2].color = (Color){255, 0, 255, 255};
     characters[2].energy = 70;
     characters[2].friendliness = 85;
     characters[2].creativity = 60;
     characters[2].role = "Technician";
     characters[2].preferences = "Sound, Lighting";
-    characters[2].position = (Position){0, 0};
 
     characters[3].name = "Diana";
-    characters[3].dimension = (Dimension){20,30};
     characters[3].color = (Color){255, 0, 255, 255};
     characters[3].energy = 55;
     characters[3].friendliness = 75;
     characters[3].creativity = 80;
     characters[3].role = "Volunteer";
     characters[3].preferences = "Logistics, Helping";
-    characters[3].position = (Position){0, 0};
 
     return characters;
 }
@@ -74,7 +72,7 @@ Character* Character_creates(int* size) {
 // Function to print character details
 void Character_log(const Character* character) {
     printf("╔════════════════════════════════════════════╗\n");
-    printf("║                 Character Info             ║\n");
+    printf("║ %3.0f/%3.0f         Character Info             ║\n", character->object->x, character->object->y);
     printf("╠════════════════════════════════════════════╣\n");
     printf("║ Name       : %-29s ║\n", character->name);
     printf("║ Role       : %-29s ║\n", character->role);
diff --git a/character.h b/character.h
index 06cfda2..8901d8a 100644
--- a/character.h
+++ b/character.h
@@ -2,15 +2,7 @@
 #define CHARACTER_H
 
 #include "color.h"
-
-typedef struct {
-    double x, y;
-} Position;
-
-typedef struct {
-    double w, h;
-} Dimension;
-
+#include "object.h"
 
 typedef struct {
     char* name;
@@ -19,13 +11,12 @@ typedef struct {
     int   creativity;
     char* role;
     char* preferences;
-    Position position;
     Color color;
-    Dimension dimension;
+    Object* object;
 } Character;
 
-Character  Character_create(const char *name, int energy, int friendliness, int creativity, Position pos);
-Character* Character_creates(int* size);
+Character  Character_create(const char *name, int energy, int friendliness, int creativity);
+Character* Character_creates(Object* object_first, int* size);
 
 void Character_log(const Character* character);
 
diff --git a/collectable.c b/collectable.c
new file mode 100644
index 0000000..1f4ba3a
--- /dev/null
+++ b/collectable.c
@@ -0,0 +1,11 @@
+#include "stdlib.h"
+#include "stdio.h"
+
+#include "collectable.h"
+
+Collectable* Collectable_create() {
+    Collectable* t = (Collectable*)malloc(sizeof(Collectable));
+    if (!t)
+        fprintf(stderr, "Failled to allocate memory: Collectable_create();");
+    return t;
+}
diff --git a/collectable.h b/collectable.h
new file mode 100644
index 0000000..8d115a6
--- /dev/null
+++ b/collectable.h
@@ -0,0 +1,18 @@
+#ifndef COLLECTABLE_H
+#define COLLECTABLE_H
+
+#include "object.h"
+
+
+typedef enum {
+    Collectable_Default
+} CollectableType;
+
+typedef struct {
+    CollectableType type;
+    Object* object;
+} Collectable;
+
+Collectable* Collectable_create();
+
+#endif
diff --git a/main.c b/main.c
index 301ddbd..d1326de 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
+#include <float.h>
 #include <SDL3/SDL.h>
 #include <SDL3/SDL_init.h>
 #include <SDL3_ttf/SDL_ttf.h>
@@ -12,24 +13,23 @@
 #define MOVEMENT_SPEED 100.0f
 
 TileType** map;
-ObjectType*** map_objects;
+MapObjectType*** map_objects;
 unsigned char** map_objects_count;
 int MAP_WIDTH  = 0;
 int MAP_HEIGHT = 0;
-float MAP_CENTER_X = 0;
-float MAP_CENTER_Y = 0;
-float WINDOW_WIDTH = 960;
-float WINDOW_HEIGHT = 620;
 const int TILE_SIZE = 32;
 
 int characters_size;
 Character* characters;
 Character* character;
+Object*    object_first;
 
 
 
 int main() {
     Camera camera;
+    camera.view_w = 960;
+    camera.view_h = 620;
 
     if (!SDL_Init(SDL_INIT_VIDEO)) {
         fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError());
@@ -43,12 +43,12 @@ int main() {
     }
 
     SDL_Window* window = SDL_CreateWindow("Entropie",
-                                          WINDOW_WIDTH, WINDOW_HEIGHT,
+                                          camera.view_w, camera.view_h,
                                           0);
 
     // Initialize the camera to be centered on the window initially
-    MAP_CENTER_X = WINDOW_WIDTH / 2;
-    MAP_CENTER_Y = WINDOW_HEIGHT / 2;
+    camera.center_x = camera.view_w / 2;
+    camera.center_y = camera.view_h / 2;
 
     if (!window) {
         fprintf(stderr, "SDL_CreateWindow Error: %s\n", SDL_GetError());
@@ -75,17 +75,30 @@ int main() {
 
     srand(42);
 
-    characters = Character_creates(&characters_size);
+
+    object_first = Object_create_pos(FLT_MIN,FLT_MIN,0,0);
+
+    characters = Character_creates(object_first, &characters_size);
     int character_active_id = 0;
     character = &characters[character_active_id];
     printf("\n\n### %d %d %d\n", character->color.r, character->color.g, character->color.b);
+    printf("\n\n### %f %f %f %f\n", character->object->x, character->object->y, character->object->w, character->object->h);
 
     // Load the map and assign character positions
-    if (Map_load("map.txt", characters, characters_size) != 0) {
+    if (Map_load("hof.map", characters, characters_size, object_first) != 0) {
         fprintf(stderr, "Failed to load map\n");
         return 1;
     }
     printf("MAP: %d %d\n", MAP_WIDTH, MAP_HEIGHT);
+    printf("\n\n### %f %f %f %f\n", character->object->x, character->object->y, character->object->w, character->object->h);
+
+
+
+    Object* obj = object_first;
+    while (obj->next) {
+        object_log(obj->next);
+        obj = obj->next;
+    }
 
 
     int running = 1;
@@ -138,20 +151,26 @@ int main() {
         }
 
         // Calculate the new position
-        float new_x = character->position.x + move_x * MOVEMENT_SPEED * delta_time;
-        float new_y = character->position.y + move_y * MOVEMENT_SPEED * delta_time;
+        float new_x = character->object->x + move_x * MOVEMENT_SPEED * delta_time;
+        float new_y = character->object->y + move_y * MOVEMENT_SPEED * delta_time;
 
         // Check collisions
-        if (Map_isPassable(new_x, character->position.y, character->dimension.w, character->dimension.h)) {
-            character->position.x = new_x;
+        if (Map_isPassable(new_x, character->object->y, character->object->w, character->object->h)) {
+            character->object->x = new_x;
         }
-        if (Map_isPassable(character->position.x, new_y, character->dimension.w, character->dimension.h)) {
-            character->position.y = new_y;
+        if (Map_isPassable(character->object->x, new_y, character->object->w, character->object->h)) {
+            character->object->y = new_y;
         }
 
         // Center camera
-        MAP_CENTER_X = character->position.x;
-        MAP_CENTER_Y = character->position.y;
+        camera.center_x = character->object->x;
+        camera.center_y = character->object->y;
+        Object* ro = character->object;
+        while (ro->prev && Object_is_visible(ro, &camera))
+            ro = ro->prev;
+        if (ro->prev)
+            ro = ro->next;
+        camera.render_object = (void*)ro;
         setCamera(&camera);
 
 
@@ -163,15 +182,16 @@ int main() {
 
 
         // Render stuff
-        Render_map(renderer, camera);
+        Render_map(renderer, camera, character->object);
         Render_characterInfo(renderer, font, character);
-        //Render_rect(renderer, MAP_CENTER_X - 2, MAP_CENTER_Y - 2, 4, 4, 255, 255, 0, 255);
+        //Render_rect(renderer, camera.center_x - 2, camera.center_y - 2, 4, 4, 255, 255, 0, 255);
 
         SDL_RenderPresent(renderer);
     }
 
     Character_free(characters, characters_size);
     Map_free();
+    Objects_free(object_first);
     SDL_DestroyRenderer(renderer);
     SDL_DestroyWindow(window);
     SDL_Quit();
diff --git a/map.c b/map.c
index 6f6a2d8..ec14b42 100644
--- a/map.c
+++ b/map.c
@@ -4,6 +4,14 @@
 #include <ctype.h>
 
 #include "map.h"
+#include "collectable.h"
+
+Tile* Tile_create() {
+    Tile* t = (Tile*)malloc(sizeof(Tile));
+    if (!t)
+        fprintf(stderr, "Failled to allocate memory: Tile_create();");
+    return t;
+}
 
 
 void Map_log(void) {
@@ -19,7 +27,7 @@ void Map_log(void) {
                     printf("OBJECT [%d|%d] %d: %d\n", y, x, map_objects_count[y][x], map_objects[y][x][i]);
 }
 
-int Map_load(const char* filename, Character* characters, int characters_size) {
+int Map_load(const char* filename, Character* characters, int characters_size, Object* object_first) {
     FILE* file = fopen(filename, "r");
     if (!file) {
         fprintf(stderr, "Error opening map file\n");
@@ -53,7 +61,7 @@ int Map_load(const char* filename, Character* characters, int characters_size) {
 
     // Dynamically allocate memory for the map
     map = (TileType**)malloc(map_height * sizeof(TileType*));
-    map_objects = (ObjectType***)malloc(map_height * sizeof(ObjectType**));
+    map_objects = (MapObjectType***)malloc(map_height * sizeof(MapObjectType**));
     map_objects_count = (unsigned char**)malloc(map_height * sizeof(unsigned char*));
     if (!map || !map_objects) {
         fclose(file);
@@ -63,7 +71,7 @@ int Map_load(const char* filename, Character* characters, int characters_size) {
 
     for (int i = 0; i < map_height; i++) {
         map[i] = (TileType*)malloc(map_width * sizeof(TileType));
-        map_objects[i] = (ObjectType**)malloc(map_width * sizeof(ObjectType*));
+        map_objects[i] = (MapObjectType**)malloc(map_width * sizeof(MapObjectType*));
         map_objects_count[i] = (unsigned char*)malloc(map_width * sizeof(unsigned char));
         if (!map[i] || !map_objects[i]) {
             fclose(file);
@@ -73,6 +81,7 @@ int Map_load(const char* filename, Character* characters, int characters_size) {
     }
 
     // Now load the map data
+    Object* prev = object_first;
     int y = 0;
     while (fgets(line, sizeof(line), file)) {
         int x = 0;
@@ -80,59 +89,75 @@ int Map_load(const char* filename, Character* characters, int characters_size) {
         // Split the line into words and map them to tile types
         char* token = strtok(line, " \n");
         while (token != NULL) {
-            map_objects[y][x] = (ObjectType*)malloc(sizeof(ObjectType));
-            map_objects_count[y][x] = 0;
+            Object* active = Object_create();
+            active->x = x*TILE_SIZE;
+            active->y = y*TILE_SIZE;
+            active->w = TILE_SIZE;
+            active->h = TILE_SIZE;
             // Map the string (word) to the appropriate tile type
+#define TILE_CREATE(t)      \
+    Tile* tile = Tile_create();     \
+    active->parent_type = Object_Tile;     \
+    active->parent = (void*)tile;     \
+    map[y][x] = t;     \
+    tile->type = t;
             if (strcmp(token, "..") == 0) {
-                map[y][x] = TILE_EMPTY;
+                TILE_CREATE(TILE_EMPTY)
             } else if (strcmp(token, "##") == 0) {
-                map[y][x] = TILE_WALL;
+                TILE_CREATE(TILE_WALL)
             } else if (strcmp(token, "==") == 0) {
-                map[y][x] = TILE_HOUSE;
+                TILE_CREATE(TILE_HOUSE)
             } else if (strcmp(token, "~~") == 0) {
-                map[y][x] = TILE_WATER;
+                TILE_CREATE(TILE_WATER)
             } else if (strcmp(token, "__") == 0) {
-                map[y][x] = TILE_WAY;
+                TILE_CREATE(TILE_WAY)
             } else if (strcmp(token, "++") == 0) {
-                map[y][x] = TILE_ROAD;
+                TILE_CREATE(TILE_ROAD)
             } else if (strcmp(token, "––") == 0) {
-                map[y][x] = TILE_TRACK;
+                TILE_CREATE(TILE_TRACK)
             } else if (strcmp(token, ";;") == 0) {
-                map[y][x] = TILE_GRAVEL;
+                TILE_CREATE(TILE_GRAVEL)
             } else if (strcmp(token, "DD") == 0) {
-                map[y][x] = TILE_DIRT;
+                TILE_CREATE(TILE_DIRT)
             } else if (strcmp(token, "WW") == 0) {
-                map[y][x] = TILE_GRASS;
+                TILE_CREATE(TILE_GRASS)
             } else if (strcmp(token, "TT") == 0) {
-                map[y][x] = TILE_TREE;
+                TILE_CREATE(TILE_TREE)
             } else if (strcmp(token, "PP") == 0) {
-                map[y][x] = TILE_PLAYER_SPAWN;
+                TILE_CREATE(TILE_PLAYER_SPAWN)
             } else if (strcmp(token, "CC") == 0) {
-                map[y][x] = TILE_CHARACTER_SPAWN;
+                TILE_CREATE(TILE_CHARACTER_SPAWN)
             } else if (strcmp(token, "oo") == 0) {
-                map[y][x] = TILE_COLLECTABLE;
+                TILE_CREATE(TILE_COLLECTABLE)
+#undef TILE_CREATE
+
             } else if (token[0] == 'o' && isdigit(token[1])) {
+                map[y][x] = TILE_COLLECTABLE;
                 int collectable_index = atoi(&token[1]);
-                if (collectable_index >= 0 && collectable_index < COLLECTABLE_MAX-COLLECTABLE_0) {
-                    map_objects[y][x][0] = (ObjectType)(COLLECTABLE_0 + collectable_index);
-                    map_objects_count[y][x] = 1;
-                    printf("Set position of object %d %d %d\n", x, y, collectable_index);
-                }
+                printf("Set position of object %d %d %d\n", x, y, collectable_index);
+                Collectable* collectable = Collectable_create();
+                collectable->object = active;
+                active->parent_type = Object_Collectable;
+                active->parent = (void*)collectable;
+
             } else if (token[0] == 'C' && isdigit(token[1])) {
-                int char_index = atoi(&token[1]);
-                if (char_index >= 0 && char_index < characters_size) {
-                    characters[char_index].position.x = x * TILE_SIZE;
-                    characters[char_index].position.y = y * TILE_SIZE;
-                    printf("Set position of character %d to (%d, %d)\n", char_index, x * TILE_SIZE, y * TILE_SIZE);
-                }
-                map_objects[y][x][0] = (ObjectType)(CHARACTER_0 + char_index);
-                map_objects_count[y][x] = 1;
+                free(active);
                 map[y][x] = TILE_CHARACTER_SPAWN;
+                int char_index = atoi(&token[1]);
+                Character* character = &characters[char_index];
+                printf("Set position of character %d to (%d, %d)\n%p || %d\n", char_index, x * TILE_SIZE, y * TILE_SIZE, character, character->object->parent_type);
+                active = character->object;
+                active->x = x*TILE_SIZE;
+                active->y = y*TILE_SIZE;
             } else {
                 map[y][x] = TILE_EMPTY;
+                active->parent_type = Object_Undefined;;
+                active->parent = NULL;
             }
 
+            Object_add(prev, active);
             x++;
+            prev = active;
             token = strtok(NULL, " \n");
         }
 
diff --git a/map.h b/map.h
index 8940e6c..2c1f16d 100644
--- a/map.h
+++ b/map.h
@@ -7,10 +7,6 @@
 
 extern int MAP_WIDTH;
 extern int MAP_HEIGHT;
-extern float MAP_CENTER_X;
-extern float MAP_CENTER_Y;
-extern float WINDOW_WIDTH;
-extern float WINDOW_HEIGHT;
 extern const int TILE_SIZE;
 
 typedef enum {
@@ -42,15 +38,23 @@ typedef enum {
     COLLECTABLE_2,
     COLLECTABLE_3,
     COLLECTABLE_MAX,
-} ObjectType;
+} MapObjectType;
+
+typedef struct {
+    TileType type;
+    Object* object;
+} Tile;
 
 extern TileType** map;
-extern ObjectType*** map_objects;
+extern MapObjectType*** map_objects;
 extern unsigned char** map_objects_count;
 
+
+Tile* Tile_create();
+
 void Map_log(void);
 
-int Map_load(const char* filename, Character* characters, int characters_size);
+int Map_load(const char* filename, Character* characters, int characters_size, Object*);
 int Map_isPassable(float x, float y, float w, float h);
 
 void Map_free();
diff --git a/object.c b/object.c
new file mode 100644
index 0000000..a0a8998
--- /dev/null
+++ b/object.c
@@ -0,0 +1,126 @@
+#include "object.h"
+#include "camera.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+void object_log(const Object* obj) {
+    if (!obj) {
+        printf("Object: NULL\n");
+        return;
+    }
+
+    printf("Object Debug Info:\n");
+    printf("  Type: %d\n", obj->parent_type);
+    printf("  Position: (%.2f, %.2f)\n", obj->x, obj->y);
+    printf("  Size: %.2fx%.2f\n", obj->w, obj->h);
+    printf("  Parent Pointer: %p\n", obj->parent);
+    printf("  Prev: %p | Next: %p\n", (void*)obj->prev, (void*)obj->next);
+}
+
+Object* Object_create() {
+    Object* obj = (Object*)malloc(sizeof(Object));
+    if (!obj) fprintf(stderr, "Failed allocate Object_create()");
+    obj->prev = NULL;
+    obj->next = NULL;
+    return obj;
+}
+Object* Object_create_pos(float x, float y, float w, float h) {
+    Object* o = Object_create();
+    o->x = x;
+    o->y = y;
+    o->w = w;
+    o->h = h;
+    o->prev = NULL;
+    o->next = NULL;
+    return o;
+}
+
+char Object_is_visible(Object* obj, Camera* camera) {
+    if (!obj || !camera) return 0;
+
+    float obj_left   = obj->x;
+    float obj_right  = obj->x + obj->w;
+    float obj_top    = obj->y;
+    float obj_bottom = obj->y + obj->h;
+
+    float cam_left   = camera->offset_x;
+    float cam_right  = camera->offset_x + camera->view_w;
+    float cam_top    = camera->offset_y;
+    float cam_bottom = camera->offset_y + camera->view_h;
+
+    return !(obj_right < cam_left ||  // Object is left of the view
+             obj_left > cam_right ||  // Object is right of the view
+             obj_bottom < cam_top ||  // Object is above the view
+             obj_top > cam_bottom);   // Object is below the view
+}
+
+
+// Helper function: compute the z-index of an object (e.g., bottom edge)
+static inline float get_z_index(const Object *obj) {
+    return obj->y + (obj->parent_type == Object_Tile ? 0 : obj->h );
+}
+
+// Insertion function: insert obj_new into the doubly linked list starting at reference.
+// This function will traverse backward or forward from the reference to find the proper spot.
+// After insertion, obj_new is correctly linked into the list.
+Object* Object_add(Object *reference, Object *obj_new) {
+    if (!obj_new) {
+        fprintf(stderr, "NULL passed in Object_add()\n");
+        return NULL;
+    }
+
+    // Unlink from doubly linked list
+    if (obj_new->prev) {
+        obj_new->prev->next = obj_new->next;
+    }
+    if (obj_new->next) {
+        obj_new->next->prev = obj_new->prev;
+    }
+    // Initialize the new object's pointers
+    obj_new->prev = NULL;
+    obj_new->next = NULL;
+
+    // Calculate the new object's z-index
+    float new_z = get_z_index(obj_new);
+
+    // Start from the reference node
+    Object *current = reference;
+    float current_z = get_z_index(current);
+
+    if (new_z < current_z) {
+        // We need to move backwards: find the first node whose z-index is less than or equal to new_z
+        while (current->prev != NULL && get_z_index(current->prev) > new_z) {
+            current = current->prev;
+        }
+        // Insert obj_new before current
+        obj_new->next = current;
+        obj_new->prev = current->prev;
+        if (current->prev != NULL) {
+            current->prev->next = obj_new;
+        }
+        current->prev = obj_new;
+    } else {
+        // new_z is greater than or equal to current_z; move forward until we find a node with a greater z-index
+        while (current->next != NULL && get_z_index(current->next) <= new_z) {
+            current = current->next;
+        }
+        // Insert obj_new after current
+        obj_new->prev = current;
+        obj_new->next = current->next;
+        if (current->next != NULL) {
+            current->next->prev = obj_new;
+        }
+        current->next = obj_new;
+    }
+    return obj_new;
+}
+
+void Objects_free(Object* first) {
+    while (first) {
+        Object* next = first->next;
+        free(first);
+        first = next;
+    }
+}
diff --git a/object.h b/object.h
new file mode 100644
index 0000000..9ea7cb9
--- /dev/null
+++ b/object.h
@@ -0,0 +1,32 @@
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#include "camera.h"
+
+typedef enum {
+    Object_Undefined,
+    Object_Tile,
+    Object_Character,
+    Object_Collectable,
+} ObjectType;
+
+
+typedef struct Object_s {
+    struct Object_s* prev,* next;
+    ObjectType parent_type;
+    void*      parent;
+    float  x, y;
+    float  w, h;
+} Object;
+
+
+void object_log(const Object* obj);
+
+Object* Object_create ();
+Object* Object_create_pos(float x, float y, float w, float h);
+
+char Object_is_visible(Object* obj, Camera* camera);
+Object* Object_add    (Object* reference, Object* obj_new);
+void    Objects_free  (Object* first);
+
+#endif
diff --git a/render.c b/render.c
index f9fc093..62a4679 100644
--- a/render.c
+++ b/render.c
@@ -2,16 +2,13 @@
 #include <SDL3_ttf/SDL_ttf.h>
 
 #include "color.h"
+#include "object.h"
 #include "render.h"
 #include "character.h"
 #include "map.h"
 
 extern int MAP_WIDTH;
 extern int MAP_HEIGHT;
-extern float MAP_CENTER_X;
-extern float MAP_CENTER_Y;
-extern float WINDOW_WIDTH;
-extern float WINDOW_HEIGHT;
 extern const int TILE_SIZE;
 
 extern int characters_size;
@@ -72,7 +69,7 @@ void Render_characterInfo(SDL_Renderer *renderer, TTF_Font* font, const Characte
     Render_text(renderer, font, stats, margin_left, (text_height * 3) + margin_top, textColor);
 }
 
-void Render_character(SDL_Renderer* renderer, Character* character) {
+void Render_character(SDL_Renderer* renderer, Camera camera, Character* character) {
     // Set the drawing color for the character (e.g., blue)
 
     Color c = character->color;
@@ -80,18 +77,88 @@ void Render_character(SDL_Renderer* renderer, Character* character) {
 
     // Define the rectangle
     SDL_FRect rect = {
-        character->position.x - MAP_CENTER_X + (WINDOW_WIDTH / 2), // Adjust for camera position
-        character->position.y - MAP_CENTER_Y + (WINDOW_HEIGHT / 2), // Adjust for camera position
-        character->dimension.w,
-        character->dimension.h
+        character->object->x - camera.center_x + (camera.view_w / 2), // Adjust for camera position
+        character->object->y - camera.center_y + (camera.view_h / 2), // Adjust for camera position
+        character->object->w,
+        character->object->h
     };
 
     // Render the filled rectangle
     SDL_RenderFillRect(renderer, &rect);
 }
 
+void Render_object(SDL_Renderer* renderer, Camera camera, Object* object) {
+    printf("## %f %f %p\n", object->x, object->y, object);
+    if (object->parent_type == Object_Character) {
+        Character* character = (Character*)object->parent;
+        Color co = character->color;
+        SDL_SetRenderDrawColor(renderer, co.r, co.g, co.b, co.a);
+    } else if (object->parent_type == Object_Tile) {
+        Tile* tile = (Tile*)object->parent;
+        switch (tile->type) {
+            case TILE_TREE:
+                SDL_SetRenderDrawColor(renderer, 34, 139, 34, 255); // Forest Green for trees
+                break;
+            case TILE_GRASS:
+                SDL_SetRenderDrawColor(renderer, 50, 205, 50, 255); // Lime Green for grass
+                break;
+            case TILE_DIRT:
+                SDL_SetRenderDrawColor(renderer, 139, 69, 19, 255); // Saddle Brown for dirt
+                break;
+            case TILE_WATER:
+                SDL_SetRenderDrawColor(renderer, 70, 130, 180, 255); // Steel Blue for water
+                break;
+            case TILE_WAY:
+                SDL_SetRenderDrawColor(renderer, 255, 223, 186, 255); // Peach for pathways
+                break;
+            case TILE_ROAD:
+                SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255); // Gray for roads
+                break;
+            case TILE_TRACK:
+                SDL_SetRenderDrawColor(renderer, 139, 69, 19, 255); // Saddle Brown for tracks
+                break;
+            case TILE_GRAVEL:
+                SDL_SetRenderDrawColor(renderer, 169, 169, 169, 255); // Light Gray for gravel
+                break;
+            case TILE_WALL:
+                SDL_SetRenderDrawColor(renderer, 105, 105, 105, 255); // Dim Gray for walls
+                break;
+            case TILE_EMPTY:
+                SDL_SetRenderDrawColor(renderer, 240, 248, 255, 255); // Alice Blue for empty tiles
+                break;
+            case TILE_PLAYER_SPAWN:
+                SDL_SetRenderDrawColor(renderer, 255, 223, 0, 255); // Golden Yellow for player spawn
+                break;
+            case TILE_CHARACTER_SPAWN:
+                SDL_SetRenderDrawColor(renderer, 255, 105, 180, 255); // Hot Pink for character spawn
+                break;
+            case TILE_HOUSE:
+                SDL_SetRenderDrawColor(renderer, 178, 34, 34, 255); // Firebrick for houses
+                break;
+            case TILE_COLLECTABLE:
+                SDL_SetRenderDrawColor(renderer, 255, 215, 0, 255); // Gold for collectibles
+                break;
+            default:
+                SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // Black for unknown types
+                break;
+        }
+    } else {
+        return;
+    }
+
+    SDL_FRect tileRect = { object->x - camera.offset_x, object->y - camera.offset_y, object->w, object->h };
+    SDL_RenderFillRect(renderer, &tileRect);
+}
 
-void Render_map(SDL_Renderer* renderer, Camera camera) {
+void Render_map(SDL_Renderer* renderer, Camera camera, Object* object) {
+    Object* next = camera.render_object;
+        printf("*_* %p %f %f\n", next, next->x, next->y);
+    while (next->next && Object_is_visible(next, &camera)) {
+        Render_object(renderer, camera, next);
+        next = next->next;
+    }
+}
+void Render_map_OLD(SDL_Renderer* renderer, Camera camera, Object* object) {
     // printf("MIN %d\n", camera.min_y);
     // Render only the tiles within the visible window area
     for (int y = camera.min_y; y <= camera.max_y; y++) {
@@ -157,10 +224,10 @@ void Render_map(SDL_Renderer* renderer, Camera camera) {
                 float pos_x = tile_x, pos_y = tile_y;
                 int char_id = map_objects[y][x][i] - CHARACTER_0;
                 if (char_id >= 0 && char_id < CHARACTER_MAX-CHARACTER_0) {
-                    w = characters[char_id].dimension.w;
-                    h = characters[char_id].dimension.h;
-                    pos_x = characters[char_id].position.x - MAP_CENTER_X + (WINDOW_WIDTH / 2);
-                    pos_y = characters[char_id].position.y - MAP_CENTER_Y + (WINDOW_HEIGHT / 2);
+                    w = characters[char_id].object->w;
+                    h = characters[char_id].object->h;
+                    pos_x = characters[char_id].object->x - camera.center_x + (camera.view_w / 2);
+                    pos_y = characters[char_id].object->y - camera.center_y + (camera.view_h / 2);
                     if (char_id == 0) {
                         printf("REND_CAR %d %f %f\n", char_id, pos_x, tile_x);
                         printf("MIN %d %d %d %d\n", camera.min_y, camera.min_x, camera.max_y, camera.max_x);
diff --git a/render.h b/render.h
index 555db43..be4eed9 100644
--- a/render.h
+++ b/render.h
@@ -15,8 +15,8 @@ void Render_text(SDL_Renderer* renderer, TTF_Font* font, const char* text, int x
 // Function to print character details to the SDL window
 void Render_characterInfo(SDL_Renderer *renderer, TTF_Font* font, const Character* character);
 
-void Render_character(SDL_Renderer* renderer, Character* character);
+void Render_character(SDL_Renderer* renderer, Camera camera, Character* character);
 
-void Render_map(SDL_Renderer* renderer, Camera camera);
+void Render_map(SDL_Renderer* renderer, Camera camera, Object* object);
 
 #endif