--- a/demo/snake/snake.c Sun Nov 16 22:00:13 2025 +0100 +++ b/demo/snake/snake.c Sun Nov 16 23:02:11 2025 +0100 @@ -58,10 +58,15 @@ static asc_vec2i directions[4]; typedef struct { + AscSceneNode *node; asc_color color; enum MoveDirection direction; enum MoveDirection target_direction; /** + * The number of tiles this player can look. + */ + float view_distance; + /** * The speed in tiles per second. */ float speed; @@ -473,6 +478,8 @@ ); asc_scene_add_node(MAIN_SCENE, node); Player *player = asc_scene_node_allocate_data(node, sizeof(Player)); + player->node = node; + player->view_distance = 7.f; // start with 7 tiles player->speed = 3.f; // start with 3 tiles/sec player->number = 1; player->health = 100; @@ -491,8 +498,7 @@ return player; } -static asc_rect main_scene_viewport_update(asc_vec2u window_size) { - +static void main_scene_viewport_update(AscCamera *camera, asc_vec2u window_size) { // margins const unsigned margin = 16; @@ -505,7 +511,8 @@ // check if there is still a viewport left and chicken out when not if (window_size.width < rw || window_size.height < rh) { - return ASC_RECT(0, 0, 0, 0); + camera->viewport = ASC_RECT(0, 0, 0, 0); + return; } window_size.width -= rw; window_size.height -= rh; @@ -525,7 +532,30 @@ offset_y += margin; // Set the viewport to the scaled and centered region - return ASC_RECT(offset_x, offset_y, viewport_size, viewport_size); + camera->viewport = ASC_RECT(offset_x, offset_y, viewport_size, viewport_size); +} + +static void main_scene_camera_update(AscCamera *camera) { + // follow the player + // TODO: for hot seat / split screen updates we need to attach custom data to the camera + // s.t. the camera knows which player to follow + const Player *player = game.players[0]; + + const AscSceneNode *player_node = player->node; + const float view_distance = player->view_distance; + const float cam_view_distance = (1+view_distance) * GAME_FIELD_TILE_SIZE; + const float proj_size = 2 * cam_view_distance; + + // TODO: create camera API to avoid direct access to the matrices + + // update the projection matrix + asc_mat4f_ortho_update_size(camera->projection, proj_size, proj_size); + + // update the view matrix + asc_vec2f pos = asc_scene_node_get_position2f(player_node); + pos.x = -pos.x + cam_view_distance; + pos.y = -pos.y + cam_view_distance; + asc_transform_translate2f(camera->view, pos); } int main(void) { @@ -553,23 +583,19 @@ AscCamera backdrop_camera; asc_camera_init(&backdrop_camera, .type = ASC_CAMERA_ORTHO, - .projection_update_func = asc_camera_ortho_update_size + .viewport_update_func = asc_camera_ortho_update_size ); asc_scene_init(BACKDROP_SCENE, "backdrop", &backdrop_camera); backdrop_create(); // Initialize the main scene - const unsigned initial_view_distance = 10; AscCamera main_camera; asc_camera_init(&main_camera, .type = ASC_CAMERA_ORTHO, - .ortho.rect = ASC_RECT(0, 0, - initial_view_distance*2*GAME_FIELD_TILE_SIZE, - initial_view_distance*2*GAME_FIELD_TILE_SIZE - ), .viewport_clear = true, .clear_color = ASC_RGBi(0, 32, 16), - .viewport_update_func = main_scene_viewport_update + .viewport_update_func = main_scene_viewport_update, + .update_func = main_scene_camera_update ); asc_scene_init(MAIN_SCENE, "main", &main_camera);