Thu, 17 Jul 2025 20:26:39 +0200
add a tiled game field
src/ascension/scene_node.h | file | annotate | diff | comparison | revisions | |
src/ascension/window.h | file | annotate | diff | comparison | revisions | |
src/window.c | file | annotate | diff | comparison | revisions | |
test/snake/snake.c | file | annotate | diff | comparison | revisions |
--- a/src/ascension/scene_node.h Thu Jul 17 20:15:56 2025 +0200 +++ b/src/ascension/scene_node.h Thu Jul 17 20:26:39 2025 +0200 @@ -272,6 +272,20 @@ asc_scene_node_update_transform(node); } +/** + * Sets the z-index of a 2D scene node. + * + * The index is relative to the parent nodes and by default one. + * This means, children of a 2D node by default stack onto the parent node. + * + * @param node the 2D node + * @param n the local z-index (default: 1) + */ +static inline void asc_scene_node_set_zindex(AscSceneNode *node, int n) { + node->position.z = n*ASC_SCENE_2D_DEPTH_OFFSET; + asc_scene_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;
--- a/src/ascension/window.h Thu Jul 17 20:15:56 2025 +0200 +++ b/src/ascension/window.h Thu Jul 17 20:26:39 2025 +0200 @@ -46,7 +46,7 @@ typedef struct asc_window_settings_s { AscGLContextSettings glsettings; - asc_vec2i dimensions; + asc_vec2u dimensions; const char *title; bool fullscreen; } AscWindowSettings;
--- a/src/window.c Thu Jul 17 20:15:56 2025 +0200 +++ b/src/window.c Thu Jul 17 20:26:39 2025 +0200 @@ -32,8 +32,8 @@ #include <GL/glew.h> void asc_window_settings_init_defaults(AscWindowSettings *settings) { - settings->dimensions.width = 800; - settings->dimensions.height = 600; + settings->dimensions.width = 800u; + settings->dimensions.height = 600u; settings->fullscreen = false; settings->glsettings.depth_size = 24; settings->glsettings.vsync = 1;
--- a/test/snake/snake.c Thu Jul 17 20:15:56 2025 +0200 +++ b/test/snake/snake.c Thu Jul 17 20:26:39 2025 +0200 @@ -56,8 +56,15 @@ typedef struct { enum MoveDirection direction; + /** + * The speed in tiles per second. + */ + float speed; } Spaceship; +static const unsigned game_field_size = 512; +static const unsigned game_field_tile_size = 32; + static void init_globals(void) { asc_transform_identity(rotations[MOVE_UP]); asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90)); @@ -80,6 +87,24 @@ asc_gl_context_add_cleanup_func(asc_active_glctx, destroy_textures); } +static void scale_backdrop(AscBehavior *behavior) { + // scale the backdrop to the size of the window + if (asc_active_window->resized) { + asc_ptr_cast(AscSprite, sprite, behavior->node); + asc_vec2u window_size = asc_active_window->dimensions; + asc_sprite_set_size(sprite, window_size); + } +} + +static void create_backdrop(void) { + AscSceneNode *node = asc_sprite( + .texture = TEXTURE_BACKDROP, + .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT + ); + asc_behavior_add(node, .func = scale_backdrop); + asc_scene_add_node(BACKDROP_SCENE, node); +} + static void update_fps_counter(AscBehavior *behavior) { asc_ptr_cast(AscText, node, behavior->node); static float last_fps = 0.f; @@ -102,24 +127,6 @@ } } -static void scale_backdrop(AscBehavior *behavior) { - // scale the backdrop to the size of the window - if (asc_active_window->resized) { - asc_ptr_cast(AscSprite, sprite, behavior->node); - asc_vec2u window_size = asc_active_window->dimensions; - asc_sprite_set_size(sprite, window_size); - } -} - -static void create_backdrop(void) { - AscSceneNode *node = asc_sprite( - .texture = TEXTURE_BACKDROP, - .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT - ); - asc_behavior_add(node, .func = scale_backdrop); - asc_scene_add_node(BACKDROP_SCENE, node); -} - static void create_fps_counter(void) { asc_font(ASC_FONT_REGULAR, 12); asc_ink_rgb(255, 255, 255); @@ -143,7 +150,7 @@ static void move_spaceship(AscBehavior *behavior) { AscSceneNode *node = behavior->node; Spaceship *spaceship = node->user_data; - float speed = 32.f * asc_context.frame_factor; + float speed = 32.f * spaceship->speed * 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]); @@ -153,19 +160,39 @@ AscSceneNode *sprite = asc_sprite( .name = "Player", .texture = TEXTURE_SHIP, - .x = 250, - .y = 300, - .width = 32, - .height = 32, - .origin_x = 16, - .origin_y = 16, + // TODO: introduce a function to set the position of a space ship + .x = game_field_tile_size * 8 - game_field_tile_size / 2, + .y = game_field_tile_size * 12 - game_field_tile_size / 2, + .width = game_field_tile_size, + .height = game_field_tile_size, + .origin_x = game_field_tile_size / 2, + .origin_y = game_field_tile_size / 2, ); asc_scene_add_node(MAIN_SCENE, sprite); - asc_scene_node_allocate_data(sprite, sizeof(Spaceship)); + Spaceship *ship = asc_scene_node_allocate_data(sprite, sizeof(Spaceship)); + ship->speed = 2.f; // start with 2 tiles/sec asc_behavior_add(sprite, move_spaceship); return sprite->user_data; } +static void create_gamefield() { + // TODO: create a proper data structure and a more interesting map than just a basic grid + AscSceneNode *gamefield = asc_scene_node_empty(); + for (unsigned x = 0; x < game_field_size; x+=game_field_tile_size) { + for (unsigned y = 0; y < game_field_size; y+=game_field_tile_size) { + asc_ink_rgb(0, 128, 255); + AscSceneNode *tile = asc_rectangle( + .x = x, .y = y, .filled = true, .thickness = 1, + .width = game_field_tile_size, .height = game_field_tile_size, + .border_color = ASC_RGB(64, 196, 255), + ); + asc_scene_node_link(gamefield, tile); + } + } + asc_scene_node_set_zindex(gamefield, -2); + asc_scene_add_node(MAIN_SCENE, gamefield); +} + static asc_rect update_viewport_for_window_resize(asc_vec2u window_size) { // Compute scaling and offsets unsigned viewport_size, offset_x = 0, offset_y = 0; @@ -203,6 +230,7 @@ AscWindowSettings settings; asc_window_settings_init_defaults(&settings); settings.title = "Snake"; + settings.dimensions = ASC_VEC2U(800, 800); asc_window_initialize(0, &settings); asc_ui_scale_auto(); @@ -210,7 +238,6 @@ init_textures(); // initialize the scenes - const int game_field_size = 512; asc_scene_init(BACKDROP_SCENE, .type = ASC_CAMERA_ORTHO, .projection_update_func = asc_camera_ortho_update_size @@ -218,7 +245,12 @@ asc_ink_rgb(0, 128, 90); asc_scene_init(MAIN_SCENE, .type = ASC_CAMERA_ORTHO, - .ortho.rect = ASC_RECT(0, 0, game_field_size, game_field_size), + .ortho.rect = ASC_RECT( + -game_field_tile_size/2, + -game_field_tile_size/2, + game_field_size+game_field_tile_size, + game_field_size+game_field_tile_size + ), .viewport_clear = true, .viewport_update_func = update_viewport_for_window_resize ); @@ -226,6 +258,9 @@ // backdrop for letterbox/pillarbox create_backdrop(); + // the game field + create_gamefield(); + // create UI elements create_fps_counter(); create_score_counter();