complete basic movement default tip

Mon, 14 Jul 2025 21:56:53 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 14 Jul 2025 21:56:53 +0200
changeset 206
26726b7a89a7
parent 205
d1e44c861426

complete basic movement

src/2d.c file | annotate | diff | comparison | revisions
src/ascension/scene_node.h file | annotate | diff | comparison | revisions
src/scene_node.c file | annotate | diff | comparison | revisions
src/sprite.c file | annotate | diff | comparison | revisions
src/text.c file | annotate | diff | comparison | revisions
test/snake/snake.c file | annotate | diff | comparison | revisions
--- a/src/2d.c	Sun Jul 13 17:17:15 2025 +0200
+++ b/src/2d.c	Mon Jul 14 21:56:53 2025 +0200
@@ -199,7 +199,7 @@
     node->update_func = asc_rectangle_update;
     node->destroy_func = asc_rectangle_destroy;
     node->draw_func = asc_rectangle_draw;
-    asc_node_update(node);
+    asc_scene_node_update(node);
     return node;
 }
 
@@ -355,6 +355,6 @@
     node->update_func = asc_ellipsis_update;
     node->destroy_func = asc_ellipsis_destroy;
     node->draw_func = asc_ellipsis_draw;
-    asc_node_update(node);
+    asc_scene_node_update(node);
     return node;
 }
--- a/src/ascension/scene_node.h	Sun Jul 13 17:17:15 2025 +0200
+++ b/src/ascension/scene_node.h	Mon Jul 14 21:56:53 2025 +0200
@@ -28,6 +28,7 @@
 #ifndef ASCENSION_SCENE_NODE_H
 #define ASCENSION_SCENE_NODE_H
 
+#include <cx/allocator.h>
 #include <cx/list.h>
 #include <cx/string.h>
 
@@ -76,6 +77,12 @@
      * The #ASC_SCENE_NODE_FLAGS_MASK bits are reserved for general flags.
      */
     uint32_t flags;
+    void *user_data;
+    const CxAllocator *user_data_allocator;
+    /**
+     * A free function that takes the allocator as the first argument and the data as the second.
+     */
+    cx_destructor_func2 user_data_free_func;
 };
 
 
@@ -104,8 +111,6 @@
  */
 #define ASC_SCENE_NODE_HIDDEN                 0x80000000
 
-// TODO: some functions are prefixed asc_scene_node_ and others just asc_node_
-
 /**
  * Creates an empty node that may serve as a container for other nodes.
  *
@@ -131,10 +136,10 @@
  * Calculates the transformation matrix from components.
  *
  * Used internally, usually you never need to call this.
- * Use asc_node_update_transform() to trigger a recalculation.
+ * Use asc_scene_node_update_transform() to trigger a recalculation.
  *
  * @param node the node
- * @see asc_node_update_transform()
+ * @see asc_scene_node_update_transform()
  */
 void asc_scene_node_calculate_transform(AscSceneNode *node);
 
@@ -177,10 +182,11 @@
  */
 void asc_scene_node_unlink(AscSceneNode *node);
 
-void asc_node_update(AscSceneNode *node);
+void asc_scene_node_update(AscSceneNode *node);
 
-void asc_node_update_transform(AscSceneNode *node);
+void asc_scene_node_update_transform(AscSceneNode *node);
 
+void asc_scene_node_allocate_data(AscSceneNode *node, size_t n);
 
 /**
  * This is the z-position a simple 2D element should have to allow
@@ -188,50 +194,63 @@
  */
 #define ASC_SCENE_2D_DEPTH_OFFSET 0.0078125f
 
-static inline void asc_node_set_position(AscSceneNode *node, asc_vec3f position) {
+static inline void asc_scene_node_set_position(AscSceneNode *node, asc_vec3f position) {
     node->position = position;
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
+}
+
+static inline void asc_scene_node_move(AscSceneNode *node, asc_vec3f offset) {
+    node->position.x += offset.x;
+    node->position.y += offset.y;
+    node->position.z += offset.z;
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_set_scale(AscSceneNode *node, asc_vec3f scale) {
+static inline void asc_scene_node_set_scale(AscSceneNode *node, asc_vec3f scale) {
     node->scale = scale;
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_set_origin(AscSceneNode *node, asc_vec3f origin) {
+static inline void asc_scene_node_set_origin(AscSceneNode *node, asc_vec3f origin) {
     node->origin = origin;
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_set_position2f(AscSceneNode *node, asc_vec2f position) {
+static inline void asc_scene_node_set_position2f(AscSceneNode *node, asc_vec2f position) {
     node->position.x = position.x;
     node->position.y = position.y;
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_set_scale2f(AscSceneNode *node, asc_vec2f scale) {
-    node->scale.width = scale.width;
-    node->scale.height = scale.height;
-    asc_node_update_transform(node);
+static inline void asc_scene_node_move2f(AscSceneNode *node, asc_vec2f offset) {
+    node->position.x += offset.x;
+    node->position.y += offset.y;
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_set_origin2f(AscSceneNode *node, asc_vec2f origin) {
-    node->origin.x = origin.x;
-    node->origin.y = origin.y;
-    asc_node_update_transform(node);
+static inline void asc_scene_node_set_scale2f(AscSceneNode *node, asc_vec2f scale) {
+    node->scale.width = scale.width;
+    node->scale.height = scale.height;
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_set_rotation(AscSceneNode *node, asc_transform rotation) {
-    memcpy(node->rotation, rotation, ASC_TRANSFORM_SIZE);
-    asc_node_update_transform(node);
+static inline void asc_scene_node_set_origin2f(AscSceneNode *node, asc_vec2f origin) {
+    node->origin.x = origin.x;
+    node->origin.y = origin.y;
+    asc_scene_node_update_transform(node);
 }
 
-static inline void asc_node_roll_deg(AscSceneNode *node, float angle) {
+static inline void asc_scene_node_set_rotation(AscSceneNode *node, asc_transform rotation) {
+    memcpy(node->rotation, rotation, ASC_TRANSFORM_SIZE);
+    asc_scene_node_update_transform(node);
+}
+
+static inline void asc_scene_node_roll_deg(AscSceneNode *node, float angle) {
     asc_transform r, d;
     asc_transform_roll(r, asc_rad(angle));
     asc_transform_apply(d, r, node->rotation);
     asc_transform_copy(node->rotation, d);
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
 #endif
--- a/src/scene_node.c	Sun Jul 13 17:17:15 2025 +0200
+++ b/src/scene_node.c	Mon Jul 14 21:56:53 2025 +0200
@@ -55,6 +55,9 @@
 
 static void asc_scene_node_destroy(AscSceneNode *node) {
     cxListFree(node->behaviors);
+    if (node->user_data_free_func != NULL) {
+        node->user_data_free_func((void*)node->user_data_allocator, node->user_data);
+    }
     if (node->destroy_func != NULL) {
         node->destroy_func(node);
     }
@@ -135,7 +138,7 @@
             offsetof(AscSceneNode, prev),
             offsetof(AscSceneNode, next)
     );
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
 void asc_scene_node_unlink(AscSceneNode *node) {
@@ -147,14 +150,14 @@
             offsetof(AscSceneNode, prev),
             offsetof(AscSceneNode, next)
     );
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
-void asc_node_update(AscSceneNode *node) {
+void asc_scene_node_update(AscSceneNode *node) {
     asc_set_flag(node->flags, ASC_SCENE_NODE_UPDATE_GRAPHICS);
 }
 
-void asc_node_update_transform(AscSceneNode *node) {
+void asc_scene_node_update_transform(AscSceneNode *node) {
     // fast skip if node is already marked
     if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
         return;
@@ -168,3 +171,15 @@
         asc_set_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM);
     }
 }
+
+void asc_scene_node_allocate_data(AscSceneNode *node, size_t n) {
+    if (node->user_data != NULL) {
+        asc_dprintf("WARNING: Node %"CX_PRIstr" already has user data!", CX_SFMT(node->name));
+        if (node->user_data_free_func != NULL) {
+            node->user_data_free_func((void*)node->user_data_allocator, node->user_data);
+        }
+    }
+    node->user_data = cxZallocDefault(n);
+    node->user_data_allocator = cxDefaultAllocator;
+    node->user_data_free_func = (cx_destructor_func2) cxFree;
+}
\ No newline at end of file
--- a/src/sprite.c	Sun Jul 13 17:17:15 2025 +0200
+++ b/src/sprite.c	Mon Jul 14 21:56:53 2025 +0200
@@ -138,13 +138,13 @@
     node->scale = ASC_VEC3F_1;
     asc_mat4f_unit(node->rotation);
 
-    asc_node_update(node);
+    asc_scene_node_update(node);
     return node;
 }
 
 void asc_sprite_set_size(AscSprite *sprite, asc_vec2u size) {
     sprite->width = size.width;
     sprite->height = size.height;
-    asc_node_update((AscSceneNode *) sprite);
+    asc_scene_node_update((AscSceneNode *) sprite);
 }
 
--- a/src/text.c	Sun Jul 13 17:17:15 2025 +0200
+++ b/src/text.c	Mon Jul 14 21:56:53 2025 +0200
@@ -86,7 +86,7 @@
         return;
     }
     if (asc_test_flag(text->base.flags, ASC_TEXT_CENTERED_FLAG)) {
-        asc_node_set_origin(node, ASC_VEC3F(surface->w / 2, 0, 0));
+        asc_scene_node_set_origin(node, ASC_VEC3F(surface->w / 2, 0, 0));
     }
 
     // Transfer Image Data
@@ -107,7 +107,7 @@
     SDL_FreeSurface(surface);
 
     // Schedule for transform update
-    asc_node_update_transform(node);
+    asc_scene_node_update_transform(node);
 }
 
 static void asc_text_draw(const AscCamera *camera, const AscSceneNode *node) {
@@ -182,7 +182,7 @@
 ) {
     asc_ptr_cast(AscSceneNode, snode, node);
     asc_set_flag_masked(snode->flags, ASC_TEXT_ALIGNMENT_MASK, alignment);
-    asc_node_update(snode);
+    asc_scene_node_update(snode);
 }
 
 void asc_text_centered(AscText *node, bool centered) {
@@ -192,12 +192,12 @@
     } else {
         asc_set_flag(snode->flags, ASC_TEXT_ALIGN_CENTERED);
     }
-    asc_node_update(snode);
+    asc_scene_node_update(snode);
 }
 
 void asc_text_max_width(AscText *node, unsigned max_width) {
     node->max_width = max_width;
-    asc_node_update((AscSceneNode*)node);
+    asc_scene_node_update((AscSceneNode*)node);
 }
 
 void asc_text_printf(
@@ -214,6 +214,6 @@
             ap
     );
     va_end(ap);
-    asc_node_update((AscSceneNode*)node);
+    asc_scene_node_update((AscSceneNode*)node);
 }
 
--- a/test/snake/snake.c	Sun Jul 13 17:17:15 2025 +0200
+++ b/test/snake/snake.c	Mon Jul 14 21:56:53 2025 +0200
@@ -44,6 +44,31 @@
 #define BACKDROP_SCENE asc_window_scene(0)
 #define MAIN_SCENE asc_window_scene(1)
 
+enum MoveDirection {
+    MOVE_UP,
+    MOVE_LEFT,
+    MOVE_DOWN,
+    MOVE_RIGHT
+};
+
+static asc_transform rotations[4];
+static asc_vec2f directions[4];
+
+typedef struct {
+    enum MoveDirection direction;
+} Spaceship;
+
+static void init_globals(void) {
+    asc_transform_identity(rotations[MOVE_UP]);
+    asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90));
+    asc_transform_roll(rotations[MOVE_RIGHT], asc_rad(90));
+    asc_transform_roll(rotations[MOVE_DOWN], asc_rad(180));
+    directions[MOVE_UP] = ASC_VEC2F(0, -1);
+    directions[MOVE_LEFT] = ASC_VEC2F(-1, 0);
+    directions[MOVE_DOWN] = ASC_VEC2F(0, 1);
+    directions[MOVE_RIGHT] = ASC_VEC2F(1, 0);
+}
+
 static void destroy_textures(void) {
     asc_texture_destroy(tex2d, TEX2D_COUNT);
 }
@@ -70,7 +95,7 @@
     if (asc_test_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED) || asc_active_window->resized) {
         asc_vec2u bottom_right = asc_active_window->dimensions;
         asc_vec2u text_size = ((AscText*)node)->dimension;
-        asc_node_set_position2f(node, ASC_VEC2F(
+        asc_scene_node_set_position2f(node, ASC_VEC2F(
                 (int) bottom_right.x - (int) text_size.width - 10,
                 (int) bottom_right.y - (int) text_size.height - 10
         ));
@@ -115,56 +140,30 @@
     asc_ui_add_node(node);
 }
 
-enum MoveDirection {
-    MOVE_UP,
-    MOVE_LEFT,
-    MOVE_DOWN,
-    MOVE_RIGHT
-};
-
-static asc_transform rotations[4];
-static asc_vec2f directions[4];
-
-typedef struct {
-    AscSceneNode *sprite;
-    enum MoveDirection direction;
-} Spaceship;
-
-static void turn_left(Spaceship *spaceship) {
-    spaceship->direction = (spaceship->direction + 1) % 4;
-    asc_node_set_rotation(spaceship->sprite, rotations[spaceship->direction]);
-}
-
-static void turn_right(Spaceship *spaceship) {
-    spaceship->direction = (spaceship->direction + 3) % 4;
-    asc_node_set_rotation(spaceship->sprite, rotations[spaceship->direction]);
+static void move_spaceship(AscBehavior *behavior) {
+    AscSceneNode *node = behavior->node;
+    Spaceship *spaceship = node->user_data;
+    float speed = 32.f * asc_context.frame_factor;
+    asc_vec2f movement = asc_vec2f_scale(directions[spaceship->direction], speed);
+    asc_scene_node_move2f(node, movement);
+    asc_scene_node_set_rotation(node, rotations[spaceship->direction]);
 }
 
 static Spaceship *create_spaceship(void) {
-    // TODO: this all belongs somewhere else, this is just quickly hacked into here for testing
-    asc_transform_identity(rotations[MOVE_UP]);
-    asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90));
-    asc_transform_roll(rotations[MOVE_RIGHT], asc_rad(90));
-    asc_transform_roll(rotations[MOVE_DOWN], asc_rad(180));
-    directions[MOVE_UP] = ASC_VEC2F(0, -1);
-    directions[MOVE_LEFT] = ASC_VEC2F(-1, 0);
-    directions[MOVE_DOWN] = ASC_VEC2F(0, 1);
-    directions[MOVE_RIGHT] = ASC_VEC2F(1, 0);
     AscSceneNode *sprite = asc_sprite(
         .name = "Player",
         .texture = TEXTURE_SHIP,
         .x = 250,
         .y = 300,
-        .width = 64,
-        .height = 64,
-        .origin_x = 32,
-        .origin_y = 32,
+        .width = 32,
+        .height = 32,
+        .origin_x = 16,
+        .origin_y = 16,
     );
     asc_scene_add_node(MAIN_SCENE, sprite);
-    // TODO: this is never freed at the moment
-    Spaceship *ship = cxZallocDefault(sizeof(Spaceship));
-    ship->sprite = sprite;
-    return ship;
+    asc_scene_node_allocate_data(sprite, sizeof(Spaceship));
+    asc_behavior_add(sprite, move_spaceship);
+    return sprite->user_data;
 }
 
 static asc_rect update_viewport_for_window_resize(asc_vec2u window_size) {
@@ -197,6 +196,9 @@
     asc_set_texture_path("../../test/snake/textures");
 #endif
 
+    // initialize globals
+    init_globals();
+
     // create window
     AscWindowSettings settings;
     asc_window_settings_init_defaults(&settings);
@@ -208,7 +210,7 @@
     init_textures();
 
     // initialize the scenes
-    const int game_field_size = 500;
+    const int game_field_size = 512;
     asc_scene_init(BACKDROP_SCENE,
         .type = ASC_CAMERA_ORTHO,
         .projection_update_func = asc_camera_ortho_update_size
@@ -244,10 +246,24 @@
 
         // player rotation
         if (asc_key_pressed(ASC_KEY(LEFT))) {
-            turn_left(spaceship);
+            if (spaceship->direction != MOVE_RIGHT) {
+                spaceship->direction = MOVE_LEFT;
+            }
         }
         if (asc_key_pressed(ASC_KEY(RIGHT))) {
-            turn_right(spaceship);
+            if (spaceship->direction != MOVE_LEFT) {
+                spaceship->direction = MOVE_RIGHT;
+            }
+        }
+        if (asc_key_pressed(ASC_KEY(UP))) {
+            if (spaceship->direction != MOVE_DOWN) {
+                spaceship->direction = MOVE_UP;
+            }
+        }
+        if (asc_key_pressed(ASC_KEY(DOWN))) {
+            if (spaceship->direction != MOVE_UP) {
+                spaceship->direction = MOVE_DOWN;
+            }
         }
 
         // debug-key for clearing the shader registry

mercurial