Thu, 31 Jul 2025 22:14:27 +0200
improve structure of the game code and add a function to set the player position
test/snake/snake.c | file | annotate | diff | comparison | revisions |
--- a/test/snake/snake.c Thu Jul 31 20:40:48 2025 +0200 +++ b/test/snake/snake.c Thu Jul 31 22:14:27 2025 +0200 @@ -61,12 +61,14 @@ * The speed in tiles per second. */ float speed; -} Spaceship; + asc_vec2i new_position; + bool reset_position; +} Player; static const unsigned game_field_size = 16; static const unsigned game_field_tile_size = 32; -static void init_globals(void) { +static void globals_init(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)); @@ -77,18 +79,18 @@ directions[MOVE_RIGHT] = ASC_VEC2I(1, 0); } -static void destroy_textures(void) { +static void textures_destroy(void) { asc_texture_destroy(tex2d, TEX2D_COUNT); } -static void init_textures(void) { +static void textures_init(void) { asc_texture_init_2d(tex2d, TEX2D_COUNT); asc_texture_from_file(TEXTURE_SHIP, "ship.png"); asc_texture_from_file(TEXTURE_BACKDROP, "backdrop.png"); - asc_gl_context_add_cleanup_func(asc_active_glctx, destroy_textures); + asc_gl_context_add_cleanup_func(asc_active_glctx, textures_destroy); } -static void scale_backdrop(AscBehavior *behavior) { +static void backdrop_scale(AscBehavior *behavior) { // scale the backdrop to the size of the window if (asc_active_window->resized) { asc_ptr_cast(AscSprite, sprite, behavior->node); @@ -97,16 +99,16 @@ } } -static void create_backdrop(void) { +static void backdrop_create(void) { AscSceneNode *node = asc_sprite( .texture = TEXTURE_BACKDROP, .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT, ); - asc_behavior_add(node, .func = scale_backdrop); + asc_behavior_add(node, .func = backdrop_scale); asc_scene_add_node(BACKDROP_SCENE, node); } -static void update_fps_counter(AscBehavior *behavior) { +static void fps_counter_update(AscBehavior *behavior) { asc_ptr_cast(AscText, node, behavior->node); static float last_fps = 0.f; if (fabsf(asc_context.frame_rate - last_fps) > 1) { @@ -115,7 +117,7 @@ } } -static void tie_fps_counter_to_corner(AscBehavior *behavior) { +static void fps_counter_tie_to_corner(AscBehavior *behavior) { // TODO: this should be replaced with some sort of UI layout manager AscSceneNode *node = behavior->node; if (asc_test_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED) || asc_active_window->resized) { @@ -128,18 +130,18 @@ } } -static void create_fps_counter(void) { +static void fps_counter_create(void) { AscSceneNode *node = asc_text( .name = "FPS Counter", .color = ASC_RGB(255, 255, 255), .font = asc_font(ASC_FONT_REGULAR, 12), ); - asc_behavior_add(node, .func = update_fps_counter, .interval = asc_seconds(1)); - asc_behavior_add(node, tie_fps_counter_to_corner); + asc_behavior_add(node, .func = fps_counter_update, .interval = asc_seconds(1)); + asc_behavior_add(node, fps_counter_tie_to_corner); asc_ui_add_node(node); } -static void create_score_counter(void) { +static void score_counter_create(void) { AscSceneNode *node = asc_text( .name = "Score Counter", .x = 10, .y = 10, @@ -150,16 +152,28 @@ asc_ui_add_node(node); } -static void move_spaceship(AscBehavior *behavior) { +static void player_move(AscBehavior *behavior) { AscSceneNode *node = behavior->node; - Spaceship *spaceship = node->user_data; + Player *player = node->user_data; + + // check if the position is set programmatically + if (player->reset_position) { + asc_scene_node_set_position2f(node, + ASC_VEC2F( + game_field_tile_size * player->new_position.x, + game_field_tile_size * player->new_position.y)); + player->reset_position = false; + return; + } + + // normal movement const int ts = (int) game_field_tile_size; const float fts = (float) ts; - const float speed = fts * spaceship->speed * asc_context.frame_factor; - const asc_vec2i dir = directions[spaceship->direction]; + const float speed = fts * player->speed * asc_context.frame_factor; + const asc_vec2i dir = directions[player->direction]; const asc_vec2f movement = asc_vec2f_scale(asc_vec2_itof(dir), speed); // check if we are supposed to change the direction - if (spaceship->direction == spaceship->target_direction) { + if (player->direction == player->target_direction) { // move without changing the direction asc_scene_node_move2f(node, movement); } else { @@ -182,8 +196,8 @@ // snap position to the center of the tile node->position.x = roundf(node->position.x / fts) * fts; node->position.y = roundf(node->position.y / fts) * fts; - spaceship->direction = spaceship->target_direction; - asc_scene_node_set_rotation(node, rotations[spaceship->direction]); + player->direction = player->target_direction; + asc_scene_node_set_rotation(node, rotations[player->direction]); } else { // changing the direction not permitted, yet, continue movement asc_scene_node_move2f(node, movement); @@ -191,26 +205,30 @@ } } -static Spaceship *create_spaceship(void) { +static void player_position(Player *pl, int x, int y) { + pl->new_position.x = x; + pl->new_position.y = y; + pl->reset_position = true; +} + +static Player *player_create(void) { AscSceneNode *sprite = asc_sprite( .name = "Player", .texture = TEXTURE_SHIP, - // TODO: introduce a function to set the position of a space ship - .x = game_field_tile_size * 8, - .y = game_field_tile_size * 12, .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); - 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; + Player *player = asc_scene_node_allocate_data(sprite, sizeof(Player)); + player_position(player, 12, 8); + player->speed = 2.f; // start with 2 tiles/sec + asc_behavior_add(sprite, player_move); + return player; } -static void create_gamefield() { +static void gamefield_create() { // 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 = 1; x <= game_field_size; x++) { @@ -229,7 +247,7 @@ asc_scene_add_node(MAIN_SCENE, gamefield); } -static asc_rect update_viewport_for_window_resize(asc_vec2u window_size) { +static asc_rect main_scene_viewport_update(asc_vec2u window_size) { // margins const unsigned margin = 10; @@ -275,7 +293,7 @@ } // initialize globals - init_globals(); + globals_init(); // create the window AscWindowSettings settings; @@ -286,7 +304,7 @@ asc_window_set_size(0, ASC_VEC2U(700+ui_scale*200, 700)); // load textures - init_textures(); + textures_init(); // initialize the scenes asc_scene_init(BACKDROP_SCENE, "backdrop", @@ -301,21 +319,21 @@ ), .viewport_clear = true, .clear_color = ASC_RGB(0, 128, 90), - .viewport_update_func = update_viewport_for_window_resize + .viewport_update_func = main_scene_viewport_update ); // backdrop for letterbox/pillarbox - create_backdrop(); + backdrop_create(); // the game field - create_gamefield(); + gamefield_create(); // create UI elements - create_fps_counter(); - create_score_counter(); + fps_counter_create(); + score_counter_create(); // create spaceship - Spaceship *spaceship = create_spaceship(); + Player *spaceship = player_create(); // Main Loop do {