X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=fishladder.c;h=7cda200bd7727d537cc849e214f27d7c3c3e5ec1;hb=e00ea4ccba1891970699f9b5b78ba1ebaada2974;hp=4ff74588763a3990458addab078b3b00a87c1d42;hpb=313de221328d756742ddc6f52386d9ddae067e7c;p=fishladder.git diff --git a/fishladder.c b/fishladder.c index 4ff7458..7cda200 100644 --- a/fishladder.c +++ b/fishladder.c @@ -1,9 +1,39 @@ // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved -//#define VG_STEAM +#define VG_STEAM +#define VG_STEAM_APPID 1218140U #include "vg/vg.h" #include "fishladder_resources.h" +/* + Todo for release: + Tutorial levels: + 1. Transport + 2. Split + 3. Merge (and explode) + 4. Principle 1 (divide colours) + 5. Principle 2 (combine colours) + + Trainee levels: + Simple maths (x3) + Colour ordering (x2) + Routing problems (x2) + + Medium levels: + Reverse order + + New things to program: + UI text element renderer (SDF) DONE(sorta) + Particle system thing for ball collision + Level descriptions / titles HALF + Row Gridlines for I/O + Play button / Speed controller + + + After release: + +*/ + const char *level_pack_1[] = { "level0", "level1", @@ -245,7 +275,8 @@ enum e_fish_state k_fish_state_soon_dead = -1, k_fish_state_dead = 0, k_fish_state_alive, - k_fish_state_bg + k_fish_state_bg, + k_fish_state_soon_alive }; struct world @@ -270,6 +301,7 @@ struct world int simulating; int sim_run, max_runs; + float sim_speed; float frame_lerp; struct cell_terminal @@ -323,13 +355,12 @@ struct world int num_fishes; - char map_name[128]; + char map_name[64]; struct career_level *ptr_career_level; u32 score; u32 completed; u32 time; - } world = {}; static void map_free(void) @@ -371,9 +402,9 @@ static int map_load( const char *str, const char *name ) // Scan for width for(;; world.w ++) { - if( str[world.w] == ';' ) + if( c[world.w] == ';' ) break; - else if( !str[world.w] ) + else if( !c[world.w] ) { vg_error( "Unexpected EOF when parsing level\n" ); return 0; @@ -706,6 +737,7 @@ static void map_serialize( FILE *stream ) int main( int argc, char *argv[] ) { vg_init( argc, argv, "Marble Computing | SPACE: Test | LeftClick: Toggle tile | RightClick: Drag wire" ); + return 0; } static int console_credits( int argc, char const *argv[] ) @@ -1234,7 +1266,7 @@ void vg_update(void) world.tile_y = floorf( world.tile_pos[1] ); // Tilemap editing - if( !world.simulating ) + if( !world.simulating && !gui_want_mouse() ) { v2_copy( vg_mouse_ws, drag_to_co ); @@ -1356,6 +1388,7 @@ void vg_update(void) world.sim_frame = 0; world.sim_start = vg_time; world.sim_run = 0; + world.sim_speed = 2.5f; for( int i = 0; i < world.w*world.h; i ++ ) world.data[ i ].state &= ~FLAG_FLIP_FLOP; @@ -1367,7 +1400,7 @@ void vg_update(void) // Fish ticks if( world.simulating ) { - while( world.sim_frame < (int)((vg_time-world.sim_start)*2.0f) ) + while( world.sim_frame < (int)((vg_time-world.sim_start)*world.sim_speed) ) { //vg_info( "frame: %u\n", world.sim_frame ); sfx_set_playrnd( &audio_random, &audio_system_balls_switching, 0, 9 ); @@ -1394,6 +1427,9 @@ void vg_update(void) if( fish->state == k_fish_state_soon_dead ) fish->state = k_fish_state_dead; + if( fish->state == k_fish_state_soon_alive ) + fish->state = k_fish_state_alive; + if( fish->state < k_fish_state_alive ) continue; @@ -1488,7 +1524,7 @@ void vg_update(void) fish->state = world_check_pos_ok( fish->pos )? k_fish_state_bg: k_fish_state_dead; } - v2i_add( fish->pos, fish->dir, fish->pos ); + //v2i_add( fish->pos, fish->dir, fish->pos ); } else if( fish->state == k_fish_state_bg ) { @@ -1505,7 +1541,9 @@ void vg_update(void) if( cell_entry->config == k_cell_type_con_r || cell_entry->config == k_cell_type_con_u || cell_entry->config == k_cell_type_con_l || cell_entry->config == k_cell_type_con_d ) { - fish->state = k_fish_state_alive; + sw_set_achievement( "CAN_DO_THAT" ); + + fish->state = k_fish_state_soon_alive; fish->dir[0] = 0; fish->dir[1] = 0; @@ -1535,6 +1573,7 @@ void vg_update(void) if( fish->state == k_fish_state_alive ) { + v2i_add( fish->pos, fish->dir, fish->pos ); struct cell *cell_current = pcell( fish->pos ); if( cell_current->state & FLAG_IS_TRIGGER ) @@ -1559,23 +1598,58 @@ void vg_update(void) } // Third pass (collisions) + struct fish *fi, *fj; + for( int i = 0; i < world.num_fishes; i ++ ) { - if( world.fishes[i].state == k_fish_state_alive ) + fi = &world.fishes[i]; + + if( fi->state == k_fish_state_alive ) { + int continue_again = 0; + for( int j = i+1; j < world.num_fishes; j ++ ) { - if( (world.fishes[j].state == k_fish_state_alive) && - (world.fishes[i].pos[0] == world.fishes[j].pos[0]) && - (world.fishes[i].pos[1] == world.fishes[j].pos[1]) ) + fj = &world.fishes[j]; + + if( (fj->state == k_fish_state_alive) ) { - // Shatter death (+0.5s) - world.fishes[i].state = k_fish_state_soon_dead; - world.fishes[j].state = k_fish_state_soon_dead; - world.fishes[i].death_time = 0.5f; - world.fishes[j].death_time = 0.5f; + v2i fi_prev; + v2i fj_prev; + + v2i_sub( fi->pos, fi->dir, fi_prev ); + v2i_sub( fj->pos, fj->dir, fj_prev ); + + int + collide_next_frame = ( + (fi->pos[0] == fj->pos[0]) && + (fi->pos[1] == fj->pos[1]))? 1: 0, + collide_this_frame = ( + (fi_prev[0] == fj->pos[0]) && + (fi_prev[1] == fj->pos[1]) && + (fj_prev[0] == fi->pos[0]) && + (fj_prev[1] == fi->pos[1]) + )? 1: 0; + + if( collide_next_frame || collide_this_frame ) + { + sw_set_achievement( "BANG" ); + + // Shatter death (+0.5s) + float death_time = collide_this_frame? 0.0f: 0.5f; + + fi->state = k_fish_state_soon_dead; + fj->state = k_fish_state_soon_dead; + fi->death_time = death_time; + fj->death_time = death_time; + + continue_again = 1; + break; + } } } + if( continue_again ) + continue; } } @@ -1654,6 +1728,10 @@ void vg_update(void) world.sim_frame = 0; world.sim_start = vg_time; world.num_fishes = 0; + + for( int i = 0; i < world.w*world.h; i ++ ) + world.data[ i ].state &= ~FLAG_FLIP_FLOP; + continue; } else @@ -1671,6 +1749,9 @@ void vg_update(void) } else { + if( world.sim_run > 0 ) + sw_set_achievement( "GOOD_ENOUGH" ); + vg_error( "Level failed :(\n" ); } @@ -1690,7 +1771,7 @@ void vg_update(void) } float scaled_time = 0.0f; - scaled_time = (vg_time-world.sim_start)*2.0f; + scaled_time = (vg_time-world.sim_start)*world.sim_speed; world.frame_lerp = scaled_time - (float)world.sim_frame; // Update positions @@ -1884,6 +1965,27 @@ void vg_render(void) } + // Level title + ui_begin( &ui_global_ctx, 512, 256 ); + + ui_global_ctx.override_colour = 0xff9a8a89; + //ui_text( &ui_global_ctx, world.map_title, 6, 0 ); + ui_global_ctx.override_colour = 0xffffffff; + + ui_resolve( &ui_global_ctx ); + + m3x3f world_text; + m3x3_copy( vg_pv, world_text ); + m3x3_translate( world_text, (v3f){ 1.55f, 1.9f, 0.0f } ); + m3x3_rotate( world_text, VG_PIf*0.5f ); + m3x3_scale( world_text, (v3f){0.01f,-0.01f,0.01f} ); + + ui_draw( &ui_global_ctx, world_text ); + + // Main + // ========================================================================================= + + use_mesh( &world.tile ); SHADER_USE( shader_tile_main ); m2x2f subtransform; @@ -2230,12 +2332,63 @@ void vg_render(void) level_ui_space[1] -= 0.01f; draw_numbers( level_ui_space, i ); } - - //use_mesh( &world.numbers ); - //draw_numbers( (v3f){ 0.0f, -0.5f, 0.1f }, 128765 ); } void vg_ui(void) { - ui_test(); + ui_global_ctx.cursor[0] = 0; + ui_global_ctx.cursor[1] = 0; + ui_global_ctx.cursor[2] = 256; + + gui_fill_y(); + + ui_global_ctx.id_base = 4 << 16; + + gui_new_node(); + { + gui_fill_rect( ui_global_ctx.cursor, 0xff5577ff ); + + gui_text( "MARBLE COMPUTING", 4, 0 ); + + ui_global_ctx.cursor[1] += 45; + ui_global_ctx.cursor[3] = 709; + + // Level scroll view + gui_new_node(); + { + gui_fill_rect( ui_global_ctx.cursor, 0xffff7729 ); + gui_set_clip( ui_global_ctx.cursor ); + + ui_global_ctx.cursor[2] = 16; + gui_align_right(); + + static struct ui_scrollbar sb = { + .bar_height = 400 + }; + ui_scrollbar( &ui_global_ctx, &sb, 0 ); + + ui_global_ctx.cursor[2] = 240; + ui_global_ctx.cursor[3] = 50; + gui_align_left(); + + ui_px content_height = vg_list_size(cmp_levels_basic)*ui_global_ctx.cursor[3]; + ui_global_ctx.cursor[1] -= ui_calculate_content_scroll( &sb, content_height ); + + for( int i = 0; i < vg_list_size(cmp_levels_basic); i ++ ) + { + struct cmp_level *lvl_info = &cmp_levels_basic[i]; + + gui_new_node(); + { + gui_fill_rect( ui_global_ctx.cursor, i&0x1?0xff23fce45:0xff8722f8 ); + gui_text( lvl_info->title, 3, 0 ); + } + gui_end_down(); + } + + gui_release_clip(); + } + gui_end_down(); + } + gui_end(); }