camera: started work on camera scrolling.
authorLukas Krickl <lukas@krickl.dev>
Tue, 3 Mar 2026 04:13:32 +0000 (05:13 +0100)
committerLukas Krickl <lukas@krickl.dev>
Tue, 3 Mar 2026 04:13:32 +0000 (05:13 +0100)
The input scroll system currently is hard coded in i_input.
This is likely not where it should remain but for now it works just
fine. Changed docs for commands to explicitly mention commands should
*only* affect gameplay and not contain anything related to menus or
camera movement.

src/i_input.c
src/i_input.h
src/p_r_sdl/p_draw.c
src/r_assets.c
src/t_camera.c
src/t_camera.h
src/t_command.c
src/t_command.h
src/t_map.c
src/tests/t_command.c
src/u_math.c

index 441b3e62c83ecc920437c1443f1df5185df4e0f2..a7cd748406d32b8a1959309e45ca268f46553dd0 100644 (file)
@@ -42,13 +42,13 @@ void i_input_cursor_set(i32 x, i32 y) {
 }
 
 lrts_bool i_input_just_pressed(enum i_input_actions action) {
-       LRTS_UNUSED(action);
-       return LRTS_FALSE;
+       struct i_input_map_ent *e = &i_input_map.inputs[action];
+       return e->pressed == 1 && !i_input_is_delayed(action);
 }
 
 lrts_bool i_input_held(enum i_input_actions action) {
-       LRTS_UNUSED(action);
-       return LRTS_FALSE;
+       struct i_input_map_ent *e = &i_input_map.inputs[action];
+       return (e->pressed & 1) > 0 && !i_input_is_delayed(action);
 }
 
 lrts_bool i_input_double_press(enum i_input_actions action) {
@@ -56,23 +56,62 @@ lrts_bool i_input_double_press(enum i_input_actions action) {
        return LRTS_FALSE;
 }
 
+void i_input_delay_ticks(enum i_input_actions action, u32 tick_count) {
+       struct i_input_map_ent *e = &i_input_map.inputs[action];
+       struct lrts_state *s = lrts_state();
+
+       e->delay_until_tick = s->tick_count + tick_count;
+}
+
+lrts_bool i_input_is_delayed(enum i_input_actions action) {
+       struct lrts_state *s = lrts_state();
+       struct i_input_map_ent *e = &i_input_map.inputs[action];
+       
+       if (s->tick_count >= e->delay_until_tick) {
+               return LRTS_FALSE;
+       }
+       return LRTS_TRUE;
+}
+
 void i_input_poll(void) {
        u32 i;
        struct i_input_map_ent *e;
        p_poll_events();
        i_input_update();
        
-       /* translate inputs
-        * to command queue 
+       /* 
+        * handle inputs
+        * either directly or 
+        * by translating to a commnad
         */
        for (i = 0; i < I_INPUT_ACTION_LEN; i++) {
                e =  &i_input_map.inputs[i];
                LRTS_UNUSED(e);
                switch (i) {
                        case I_INPUT_ACTION_CAMERA_UP:
+                               if (i_input_held(i)) {
+                                       t_camera_scroll(&t_main_camera, 0, -10);
+                                       i_input_delay_ticks(i, 1);
+                               }
+                               break;
                        case I_INPUT_ACTION_CAMERA_DOWN:
+                               if (i_input_held(i)) {
+                                       t_camera_scroll(&t_main_camera, 0, 10);
+                                       i_input_delay_ticks(i, 1);
+                               }
+                               break;
                        case I_INPUT_ACTION_CAMERA_LEFT:
+                               if (i_input_held(i)) {
+                                       t_camera_scroll(&t_main_camera, -10, 0);
+                                       i_input_delay_ticks(i, 1);
+                               }
+                               break;
                        case I_INPUT_ACTION_CAMERA_RIGHT:
+                               if (i_input_held(i)) {
+                                       t_camera_scroll(&t_main_camera, 10, 0);
+                                       i_input_delay_ticks(i, 1);
+                               }
+                               break;
                        case I_INPUT_ACTION_CURSOR_CLICK:
                        case I_INPUT_ACTION_CURSOR_ACTION:
                        case I_INPUT_ACTION_CURSOR_DRAG:
index afa574aa4241d41240e9fd14028d97d1f62e6194..bb8d97501a0c43a9f70a6947fd52c279b5e656f7 100644 (file)
@@ -50,6 +50,10 @@ struct i_input_map_ent {
         * the most recent state is in the rightmost bit
         */
        u16 pressed;
+       
+       /* do not run again until the tick counter
+        * has reached this number */
+       u32 delay_until_tick;
 };
 
 /* map of all input actions to scanscodes */
@@ -90,6 +94,11 @@ lrts_bool i_input_double_press(enum i_input_actions action);
  */
 void i_input_poll(void);
 
+/* delays this action from beign treated as pressed for n ticks */
+void i_input_delay_ticks(enum i_input_actions action, u32 tick_count);
+
+/* tests if the input is delayed */
+lrts_bool i_input_is_delayed(enum i_input_actions action);
 
 /* inits the default for a keybind */
 void i_input_map_init_default(enum i_input_actions action, 
index 468b1bd6fb95598e6fedcb16f5059eb75024478e..2cb6750822296162f58a50423dbd421b25c27072 100644 (file)
@@ -18,7 +18,7 @@ u64 p_ticks_per_second(void) {
 }
 
 void p_draw_begin(void) {
-       SDL_FillSurfaceRect(r_target, NULL, 0x000000);
+       SDL_FillSurfaceRect(r_target, NULL, 0x0000FF);
 }
 
 void p_draw_end(void) {
index f805170740b5ca455d624d5a0cf886b0cf63bf6e..b68499e54b6d105b452dad93ce7e5cea8f671b09 100644 (file)
@@ -47,10 +47,12 @@ void r_asset_init_fallback_tile(void) {
 }
 
 void r_draw_solid_isometric_tile(i32 x, i32 y, r_color color) {
+       struct lrts_state *s = lrts_state();
        u32 i = 0;
        u32 j = 0;
        r_color final_color;
        struct u_vec2 t = u_tile_to_screen(x, y);
+       t = u_screen_to_camera(&t_main_camera, t);
 
        /* converted origin point in isometric space */
        
@@ -61,9 +63,14 @@ void r_draw_solid_isometric_tile(i32 x, i32 y, r_color color) {
                        r_draw_pixel(&r_framebuffer, t.x + i, t.y + j, final_color);
                }
        }
+
+       if (s->debug) {
+               u_debug_draw_text(t.x, t.y, "%d/%d", x, y);
+       }
 }
 
 void r_draw_tile(struct t_tile *t, i32 x, i32 y) {
+
        switch (t->type) {
                case T_TILE_TYPE_NONE:
                        break;
index e8e0b1c2a68ee646cb91228d5e568f563e479a05..bb60a64b8c05af03c5e5bb395eef0593e08408bc 100644 (file)
@@ -15,7 +15,16 @@ struct t_camera t_camera_init(i32 viewport_x, i32 viewport_y) {
 void t_camera_scroll(struct t_camera *c, i32 by_x, i32 by_y) {
        c->x += by_x;
        c->y += by_y;
-       U_CLAMP(c->x, 0, c->viewport_x);
-       U_CLAMP(c->y, 0, c->viewport_y);
+
+       /* TODO: calculate max viewport based on map */
+       U_CLAMP(c->x, -4096, 4096);
+       U_CLAMP(c->y, -4096, 4096);
 }
 
+
+struct u_vec2 u_screen_to_camera(struct t_camera *c, struct u_vec2 v) {
+       v.x -= c->x;
+       v.y -= c->y;
+
+       return v;
+}
index 73af3c79f46ef991fdcd28a68f1e28b658e3f97a..347d34994340ac50f01286ef9ced183fed32b6b8 100644 (file)
@@ -17,4 +17,7 @@ struct t_camera t_camera_init(i32 viewport_x, i32 viewport_y);
 
 void t_camera_scroll(struct t_camera *c, i32 by_x, i32 by_y);
 
+/* adjusts a screen coodrinate by the camera offset */
+struct u_vec2 u_screen_to_camera(struct t_camera *c, struct u_vec2 v);
+
 #endif
index 29dd1b929c44709755119b9c690f9919b233cdc2..5a84377011ff8cf676372113defe0c29baa6e7c9 100644 (file)
@@ -5,6 +5,7 @@ struct t_command_queue t_command_queue;
 
 u32 t_command_queue_process(void) {
        u32 i = 0;
+       u32 n_exec = 0;
        struct t_command *c;
        struct lrts_state *state = lrts_state();
 
@@ -17,16 +18,18 @@ u32 t_command_queue_process(void) {
                if (c->type == T_COMMAND_NONE || c->run_at_tick > state->tick_count) {
                        break;
                }
-               t_command_exec(c);
+               if (t_command_exec(c)) {
+                       n_exec++;
+               }
        }
 
-       return 0;
+       return n_exec;
 }
 
 lrts_bool t_command_exec(struct t_command *c) {
        if (c->type == T_COMMAND_NONE) {
                u_log(U_LOG_WARN, "Command of type none was passed to exec\n");
-               return LRTS_TRUE;
+               return LRTS_FALSE;
        }
        
        c->type = T_COMMAND_NONE;
index 0e92bf435f84e6cc3f085ba5c2e1ee72b4a4b50c..3667457f2153645e1db98137b2585016eee25118 100644 (file)
@@ -4,8 +4,15 @@
 #include "u_defs.h"
 
 /**
- * A command is an order for a unit.
- * each unit has a command queue.
+ * A command is a serializable action.
+ * Commands must have the following properties:
+ * - they must be unique
+ * - they must be sorted by type, player and tick number
+ * - commands are executed as soon as tick number >= current tick
+ * - commands must represent all changes to the game state
+ * - commands are sent over the network for multiplayer
+ * - all coordinates inside the command buffer must be in world-space
+ * - commands must not include client-side only interactions such as menus or camera
  */
 
 #define T_COMMANDS_MAX 0x4FF
 enum t_command_type {
        T_COMMAND_NONE = 0,
        /* no-op command */
-       T_COMMAND_NOOP,
-       /* moves camera in the direction of a 
-        * provided vector
-        */
-       T_COMMAND_MOVE_CAMERA
+       T_COMMAND_NOOP
 };
 
 enum t_command_flags {
index 8e09900b1f82e5decde2b3c655583c87bf04c796..4f3995c909372f5dfe4b10f3d0895325c4176c0a 100644 (file)
@@ -36,6 +36,9 @@ void t_map_draw(struct t_map *m) {
        end.x = ((t_main_camera.x + t_main_camera.viewport_x) / R_TILE_W) * 2;
        end.y = ((t_main_camera.y + t_main_camera.viewport_y) / R_TILE_H) * 2;
 
+       start.x = 0;
+       start.y = 0;
+
        for (i = start.x; i < end.x; i++) {
                for (j = start.y; j < end.y; j++) {
                        r_draw_tile(&m->tiles[j * m->width + i], i, j);
index 99ccef69ad687ca74edb7ffe50fcfc304b676b36..87b5a6586156dffdb05c7a651a9604b9bbef5bee 100644 (file)
@@ -5,10 +5,10 @@ int test_t_command_push(void) {
        struct t_command t;
        u32 i = 0;
 
-       t.type = T_COMMAND_MOVE_CAMERA;
+       t.type = T_COMMAND_NONE;
        t_command_push(t);
        T_ASSERT(t_command_queue.idx == 1, ("write index moved\n"));
-       T_ASSERT(t_command_queue.buffer[0].type == T_COMMAND_MOVE_CAMERA, ("command written\n"));
+       T_ASSERT(t_command_queue.buffer[0].type == T_COMMAND_NONE, ("command written\n"));
 
        for (i = 0; i < T_COMMANDS_MAX+1; i++) {
                t_command_push(t);
index 7e2b12225cabc2a6115eb269ca1e23b98999f861..52908e5fc3b0172e362b0a5933ae95ab0448ddaa 100644 (file)
@@ -13,7 +13,7 @@ struct u_vec2 u_vec2_mul(i32 n, struct u_vec2 v) {
 struct u_vec2 u_tile_to_screen(i32 x, i32 y) {
        struct u_vec2 r;
 
-       r.x = (x * R_TILE_W / 2) + (y * R_TILE_W / 2);;
+       r.x = (x * R_TILE_W / 2) + (y * R_TILE_W / 2);
        r.y = (y * R_TILE_H / 2) - (x * R_TILE_H / 2);
 
        return r;