From ce8284ab3962477c5cea94f6a016908d4d021936 Mon Sep 17 00:00:00 2001 From: En Yi Date: Mon, 25 Sep 2023 22:04:13 +0800 Subject: [PATCH] Implement level ending Internal Changelog: - Activate on collected chest == all chest - Add spawning level end entity - Level ending in sandbox will just reset the scene --- scenes/editor_scene.c | 33 +++++++++++++++++++++++++++++++-- scenes/engine/EC/EC.h | 2 +- scenes/ent_impl.h | 2 ++ scenes/game_systems.c | 41 +++++++++++++++++++++++++++++++++++++++++ scenes/game_systems.h | 1 + scenes/items_ent.c | 9 +++++++++ 6 files changed, 85 insertions(+), 3 deletions(-) diff --git a/scenes/editor_scene.c b/scenes/editor_scene.c index 3e02319..a8e3435 100644 --- a/scenes/editor_scene.c +++ b/scenes/editor_scene.c @@ -26,9 +26,10 @@ enum EntitySpawnSelection { SPAWN_CRATE_BOMB, SPAWN_BOULDER, SPAWN_WATER_RUNNER, + SPAWN_LEVEL_END, }; -#define MAX_SPAWN_TYPE 15 +#define MAX_SPAWN_TYPE 16 static unsigned int current_spawn_selection = 0; static bool metal_toggle = false; static bool crate_activation = false; @@ -58,6 +59,7 @@ static char* get_spawn_selection_string(enum EntitySpawnSelection sel) case SPAWN_CRATE_BOMB: return (metal_toggle) ? "metal bomb crate" : "wooden bomb crate"; case SPAWN_BOULDER: return "boulder"; case SPAWN_WATER_RUNNER: return "water runner"; + case SPAWN_LEVEL_END: return "level end"; default: return "unknown"; } } @@ -330,6 +332,12 @@ static void level_scene_render_func(Scene_t* scene) } } + sc_map_foreach_value(&scene->ent_manager.entities_map[LEVEL_END_TAG], p_ent) + { + CTransform_t* p_ct = get_component(p_ent, CTRANSFORM_COMP_T); + DrawCircleV(p_ct->position, tilemap.tile_size >> 1, (data->coins.current < data->coins.total)? RED : GREEN); + } + sc_map_foreach_value(&scene->ent_manager.entities_map[DYNMEM_ENT_TAG], p_ent) { CWaterRunner_t* p_runner = get_component(p_ent, CWATERRUNNER_T); @@ -597,6 +605,17 @@ static void toggle_block_system(Scene_t* scene) } } break; + case SPAWN_LEVEL_END: + { + Entity_t* p_ent = create_level_end(&scene->ent_manager, &scene->engine->assets); + if (p_ent != NULL) + { + CTransform_t* p_ct = get_component(p_ent, CTRANSFORM_COMP_T); + p_ct->position.x = (tile_idx % tilemap.width) * tilemap.tile_size + (tilemap.tile_size >> 1); + p_ct->position.y = (tile_idx / tilemap.width) * tilemap.tile_size + (tilemap.tile_size >> 1);; + } + } + break; case SPAWN_CHEST: if (data->coins.total < 65535) { @@ -717,6 +736,11 @@ static void restart_editor_level(Scene_t* scene) } } } + Entity_t* p_ent; + sc_map_foreach_value(&scene->ent_manager.entities_map[LEVEL_END_TAG], p_ent) + { + remove_entity(&scene->ent_manager, p_ent->m_id); + } update_entity_manager(&scene->ent_manager); for (size_t i = 0; i < tilemap.width; ++i) { @@ -828,6 +852,7 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed) change_scene(scene->engine, 0); } break; + case ACTION_NEXTLEVEL: case ACTION_RESTART: restart_editor_level(scene); break; @@ -862,7 +887,7 @@ void init_sandbox_scene(LevelScene_t* scene) BLACK, MAROON, ORANGE, ColorAlpha(RAYWHITE, 0.5), ColorAlpha(BLUE, 0.5), ColorAlpha(RAYWHITE, 0.5), YELLOW, crate_colour, crate_colour, crate_colour, crate_colour, crate_colour, crate_colour, - ColorAlpha(RAYWHITE, 0.5), ColorAlpha(RAYWHITE, 0.5) + ColorAlpha(RAYWHITE, 0.5), ColorAlpha(RAYWHITE, 0.5), ColorAlpha(RAYWHITE, 0.5) }; for (uint8_t i = 0; i < MAX_SPAWN_TYPE; ++i) { @@ -918,6 +943,9 @@ void init_sandbox_scene(LevelScene_t* scene) case SPAWN_WATER_RUNNER: DrawCircleV(Vector2Add(draw_pos, half_size), half_size.x, ColorAlpha(BLUE, 0.2)); break; + case SPAWN_LEVEL_END: + DrawCircleV(Vector2Add(draw_pos, half_size), half_size.x, GREEN); + break; case TOGGLE_AIR_POCKET: DrawRectangleLinesEx((Rectangle){draw_pos.x, draw_pos.y, SELECTION_TILE_SIZE, SELECTION_TILE_SIZE}, 2.0, ColorAlpha(BLUE, 0.5)); break; @@ -961,6 +989,7 @@ void init_sandbox_scene(LevelScene_t* scene) sc_array_add(&scene->scene.systems, &player_dir_reset_system); sc_array_add(&scene->scene.systems, &update_water_runner_system); sc_array_add(&scene->scene.systems, &player_respawn_system); + sc_array_add(&scene->scene.systems, &level_end_detection_system); sc_array_add(&scene->scene.systems, &toggle_block_system); // This avoid graphical glitch, not essential diff --git a/scenes/engine/EC/EC.h b/scenes/engine/EC/EC.h index 59e754d..fd9da1f 100644 --- a/scenes/engine/EC/EC.h +++ b/scenes/engine/EC/EC.h @@ -6,7 +6,7 @@ #include "sc/map/sc_map.h" #include "sc/queue/sc_queue.h" -#define N_TAGS 8 +#define N_TAGS 10 #define N_COMPONENTS 13 #define MAX_COMP_POOL_SIZE 1024 typedef struct EntityManager EntityManager_t; diff --git a/scenes/ent_impl.h b/scenes/ent_impl.h index bc4f1a0..5857eb8 100644 --- a/scenes/ent_impl.h +++ b/scenes/ent_impl.h @@ -9,6 +9,7 @@ typedef enum EntityTag { CRATES_ENT_TAG, CHEST_ENT_TAG, BOULDER_ENT_TAG, + LEVEL_END_TAG, DESTRUCTABLE_ENT_TAG, DYNMEM_ENT_TAG, } EntityTag_t; @@ -27,5 +28,6 @@ Entity_t* create_arrow(EntityManager_t* ent_manager, Assets_t* assets, uint8_t d Entity_t* create_bomb(EntityManager_t* ent_manager, Assets_t* assets, Vector2 launch_dir); Entity_t* create_explosion(EntityManager_t* ent_manager, Assets_t* assets); Entity_t* create_chest(EntityManager_t* ent_manager, Assets_t* assets); +Entity_t* create_level_end(EntityManager_t* ent_manager, Assets_t* assets); #endif // __ENT_IMPL_H diff --git a/scenes/game_systems.c b/scenes/game_systems.c index 89c2d0e..8c83d43 100644 --- a/scenes/game_systems.c +++ b/scenes/game_systems.c @@ -1732,3 +1732,44 @@ void camera_update_system(Scene_t* scene) if (min.x > 0) lvl_scene->data.cam.offset.x = width/2.0f - min.x; if (min.y > 0) lvl_scene->data.cam.offset.y = height/2.0f - min.y; } + +void level_end_detection_system(Scene_t* scene) +{ + LevelScene_t* lvl_scene = CONTAINER_OF(scene, LevelScene_t, scene); + if (lvl_scene->data.coins.current < lvl_scene->data.coins.total) return; + Entity_t* p_flag; + + TileGrid_t tilemap = lvl_scene->data.tilemap; + sc_map_foreach_value(&scene->ent_manager.entities_map[LEVEL_END_TAG], p_flag) + { + CTransform_t* p_ct = get_component(p_flag, CTRANSFORM_COMP_T); + unsigned int tile_idx = get_tile_idx( + p_ct->position.x, + p_ct->position.y, + tilemap.width + ); + + unsigned int other_ent_idx; + Entity_t* p_other_ent; + sc_map_foreach(&tilemap.tiles[tile_idx].entities_set, other_ent_idx, p_other_ent) + { + if (p_other_ent->m_tag != PLAYER_ENT_TAG) continue; + + CTransform_t* p_other_ct = get_component(p_other_ent, CTRANSFORM_COMP_T); + CBBox_t* p_other_bbox = get_component(p_other_ent, CBBOX_COMP_T); + + Vector2 overlap; + Vector2 pos = Vector2Subtract(p_ct->position,(Vector2){tilemap.tile_size >> 1, tilemap.tile_size >> 1}); + if ( + find_AABB_overlap( + pos, (Vector2){tilemap.tile_size, tilemap.tile_size}, + p_other_ct->position, p_other_bbox->size, &overlap + ) + ) + { + do_action(scene, ACTION_NEXTLEVEL, true); + } + } + + } +} diff --git a/scenes/game_systems.h b/scenes/game_systems.h index 2b6b8b7..c46ef04 100644 --- a/scenes/game_systems.h +++ b/scenes/game_systems.h @@ -24,5 +24,6 @@ void player_dir_reset_system(Scene_t* scene); void player_respawn_system(Scene_t* scene); void lifetimer_update_system(Scene_t* scene); void spike_collision_system(Scene_t* scene); +void level_end_detection_system(Scene_t* scene); #endif // __GAME_SYSTEMS_H diff --git a/scenes/items_ent.c b/scenes/items_ent.c index 809dabd..136bcc0 100644 --- a/scenes/items_ent.c +++ b/scenes/items_ent.c @@ -225,3 +225,12 @@ Entity_t* create_chest(EntityManager_t* ent_manager, Assets_t* assets) return p_chest; } + +Entity_t* create_level_end(EntityManager_t* ent_manager, Assets_t* assets) +{ + Entity_t* p_flag = add_entity(ent_manager, LEVEL_END_TAG); + if (p_flag == NULL) return NULL; + + add_component(p_flag, CTRANSFORM_COMP_T); + return p_flag; +}