Mon, 14 Jul 2025 21:56:53 +0200
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