--- a/test/snake/snake.c Sun Jul 20 23:31:40 2025 +0200 +++ b/test/snake/snake.c Mon Jul 21 21:28:34 2025 +0200 @@ -52,7 +52,7 @@ }; static asc_transform rotations[4]; -static asc_vec2f directions[4]; +static asc_vec2i directions[4]; typedef struct { enum MoveDirection direction; @@ -63,7 +63,7 @@ float speed; } Spaceship; -static const unsigned game_field_size = 512; +static const unsigned game_field_size = 16; static const unsigned game_field_tile_size = 32; static void init_globals(void) { @@ -71,10 +71,10 @@ 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); + directions[MOVE_UP] = ASC_VEC2I(0, -1); + directions[MOVE_LEFT] = ASC_VEC2I(-1, 0); + directions[MOVE_DOWN] = ASC_VEC2I(0, 1); + directions[MOVE_RIGHT] = ASC_VEC2I(1, 0); } static void destroy_textures(void) { @@ -153,29 +153,39 @@ static void move_spaceship(AscBehavior *behavior) { AscSceneNode *node = behavior->node; Spaceship *spaceship = node->user_data; - const float ts = (float) game_field_tile_size; - const float speed = ts * spaceship->speed * asc_context.frame_factor; - const asc_vec2f dvec = directions[spaceship->direction]; - const asc_vec2f movement = asc_vec2f_scale(dvec, speed); + 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 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) { - // no change of direction - keep moving + // move without changing the direction asc_scene_node_move2f(node, movement); } else { - // identify the tile we are currently in - int x = (int) (node->position.x / ts); - int y = (int) (node->position.y / ts); - const asc_vec2f tcenter = ASC_VEC2F(x*ts, y*ts); - // calculate the (squared) distance to the tile's center - float cdist = asc_vec2f_sqrlen(asc_vec2f_sub(tcenter, ASC_VEC2F(node->position.x, node->position.y))); - // if it is less than squared length of the movement vector, snap to the center and rotate - // TODO: think about if we should allow changing direction only when we haven't passed the center yet - if (cdist < asc_vec2f_sqrlen(dvec)) { - asc_scene_node_set_position2f(node, tcenter); + // determine axis + // and check if we are about to cross the center + // this relies on positive positions! + bool rotate = false; + if (movement.x == 0) { + // vertical movement + const int y0 = (int)node->position.y / ts; + const int y1 = (int)(node->position.y+movement.y) / ts; + rotate = y0 != y1 && asc_sgn(y1-y0) == dir.y; + } else { + // horizontal movement + const int x0 = (int)node->position.x / ts; + const int x1 = (int)(node->position.x+movement.x) / ts; + rotate = x0 != x1 && asc_sgn(x1-x0) == dir.x; + } + if (rotate) { + // 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]); - // TODO: this is losing some speed - improve the calculation and add partial movement after rotation } else { - // too far away from center, continue normal movement + // changing the direction not permitted, yet, continue movement asc_scene_node_move2f(node, movement); } } @@ -203,10 +213,10 @@ 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) { + for (unsigned x = 1; x <= game_field_size; x++) { + for (unsigned y = 1; y <= game_field_size; y++) { AscSceneNode *tile = asc_rectangle( - .x = x, .y = y, .filled = true, .thickness = 1, + .x = x*game_field_tile_size, .y = y*game_field_tile_size, .filled = true, .thickness = 1, .origin_x = game_field_tile_size / 2, .origin_y = game_field_tile_size / 2, .width = game_field_tile_size, .height = game_field_tile_size, .color = ASC_RGB(0, 128, 255), @@ -270,11 +280,9 @@ ); asc_scene_init(MAIN_SCENE, .type = ASC_CAMERA_ORTHO, - .ortho.rect = ASC_RECT( - -game_field_tile_size, - -game_field_tile_size, - game_field_size+game_field_tile_size, - game_field_size+game_field_tile_size + .ortho.rect = ASC_RECT(0, 0, + (game_field_size+1)*game_field_tile_size, + (game_field_size+1)*game_field_tile_size ), .viewport_clear = true, .clear_color = ASC_RGB(0, 128, 90), @@ -306,6 +314,7 @@ } // player rotation + // TODO: queue up to two movement commands (for sharp 90° turns) if (asc_key_pressed(ASC_KEY(LEFT))) { if (spaceship->direction != MOVE_RIGHT) { spaceship->target_direction = MOVE_LEFT;