Skip to content

Commit

Permalink
feat(tutorial): flappy bird score counter
Browse files Browse the repository at this point in the history
  • Loading branch information
naezith authored and Milerius committed Nov 3, 2019
1 parent 7dc4963 commit e15ecbd
Showing 1 changed file with 54 additions and 8 deletions.
62 changes: 54 additions & 8 deletions tutorials/flappy-bird/step_8/flappy-bird.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <antara/gaming/sfml/resources.manager.hpp>
#include <antara/gaming/world/world.app.hpp>
#include <antara/gaming/graphics/component.sprite.hpp>
#include <iostream>

//! For convenience
using namespace antara::gaming;
Expand All @@ -26,6 +27,7 @@ struct flappy_bird_constants {
// Controls
const input::mouse_button jump_button{input::mouse_button::left};
// Player
const float player_pos_x{400.0f};
const float gravity{2000.f};
const float jump_force{500.f};

Expand Down Expand Up @@ -63,20 +65,43 @@ struct pipe {
}
};

// Column is made of two pipes
struct column {
//! Entities representing the Flappy Bird pipes
pipe top_pipe{entt::null};
pipe bottom_pipe{entt::null};

// Is score taken from this column
bool scored{false};

void destroy(entt::registry &registry, entt::entity entity) {
top_pipe.destroy(registry);
bottom_pipe.destroy(registry);
registry.destroy(entity);
}
};

// Score
struct score {
int value;
int max_score;
};

//! Contains all the function that will be used for logic and factory
namespace {
// Factory to create score entity
entt::entity create_score(entt::registry &registry) {
// Create a fresh entity for a new column
auto entity = registry.create();

// Create score
registry.assign<score>(entity, 0, 0);
registry.assign<entt::tag<"high_score"_hs>>(entity);
registry.assign<entt::tag<"game_scene"_hs>>(entity);

return entity;
}

// Factory for pipes, requires to know if it's a top one, position x of the column, and the gap starting position Y
pipe create_pipe(entt::registry &registry, bool is_top, float pos_x, float gap_start_pos_y) {
// Retrieve constants
Expand Down Expand Up @@ -235,7 +260,7 @@ namespace {

auto entity = graphics::blueprint_sprite(registry,
graphics::sprite{constants.player_image_name.c_str()},
transform::position_2d{canvas_width * 0.2f, canvas_height * 0.2f});
transform::position_2d{constants.player_pos_x, canvas_height * 0.2f});
registry.assign<antara::gaming::graphics::layer<5>>(entity);
registry.assign<entt::tag<"player"_hs>>(entity);
registry.assign<entt::tag<"game_scene"_hs>>(entity);
Expand All @@ -247,7 +272,7 @@ namespace {

class column_logic final : public ecs::logic_update_system<column_logic> {
public:
explicit column_logic(entt::registry &registry) noexcept : system(registry) { }
explicit column_logic(entt::registry &registry, entt::entity score_) noexcept : system(registry), score_entity(score_) { }

void update() noexcept final {
auto& registry = entity_registry_;
Expand All @@ -260,10 +285,21 @@ class column_logic final : public ecs::logic_update_system<column_logic> {
auto& col = registry.get<column>(entity);

// Move pipes, and check if they are out of the screen
bool col_out_of_screen = move_pipe(registry, col.top_pipe) || move_pipe(registry, col.bottom_pipe);
float column_pos_x = move_pipe(registry, col.top_pipe);
move_pipe(registry, col.bottom_pipe);

// Increase score by one
if(!col.scored && column_pos_x < constants.player_pos_x) {
score& sc = registry.get<score>(score_entity);
if(++sc.value > sc.max_score) sc.max_score = sc.value;
registry.assign_or_replace<score>(score_entity, sc);

// Set column as scored
col.scored = true;
}

// If column is out of the screen
if(col_out_of_screen) {
if(column_pos_x < -constants.column_distance) {
// Remove this column
col.destroy(registry, entity);

Expand All @@ -274,6 +310,8 @@ class column_logic final : public ecs::logic_update_system<column_logic> {
}

private:
entt::entity score_entity;

// Find the most far pipe's position X
float furthest_pipe_position(entt::registry &registry) {
float furthest = 0.f;
Expand All @@ -290,7 +328,7 @@ class column_logic final : public ecs::logic_update_system<column_logic> {
}

// Move the pipe and return if it's out of the screen
bool move_pipe(entt::registry &registry, pipe& pipe) {
float move_pipe(entt::registry &registry, pipe& pipe) {
// Retrieve constants
const auto constants = registry.ctx<flappy_bird_constants>();

Expand All @@ -309,7 +347,7 @@ class column_logic final : public ecs::logic_update_system<column_logic> {
registry.assign_or_replace<transform::position_2d>(pipe.cap, new_pos_x, cap_pos.y());

// Return the info about if this pipe is out of the screen
return new_pos_x < -constants.column_thickness * 2.0f;
return new_pos_x;
}
};

Expand Down Expand Up @@ -391,6 +429,7 @@ class game_scene final : public scenes::base_scene {
registry.set<flappy_bird_constants>();

//! Create the columns
score_entity = create_score(registry);
create_background(registry);
init_dynamic_objects(registry);
}
Expand Down Expand Up @@ -435,7 +474,7 @@ class game_scene final : public scenes::base_scene {
auto player = create_player(registry);

//! Create systems
system_manager.create_system<column_logic>();
system_manager.create_system<column_logic>(score_entity);
system_manager.create_system<player_logic>(player);

// Disable physics and everything at start
Expand Down Expand Up @@ -470,6 +509,12 @@ class game_scene final : public scenes::base_scene {
}

void reset_game() {
// Reset score
score& sc = entity_registry_.get<score>(score_entity);
sc.value = 0;
entity_registry_.assign_or_replace<score>(score_entity, sc);

// Destroy all
destroy_all();
this->need_reset = true;
}
Expand All @@ -485,6 +530,7 @@ class game_scene final : public scenes::base_scene {
ecs::system_manager& system_manager;

// States
entt::entity score_entity;
bool started_playing{false};
bool player_died{false};
bool game_over{false};
Expand All @@ -500,7 +546,7 @@ struct flappy_bird_world : world::app {
auto &graphic_system = system_manager_.create_system<sfml::graphic_system>();

//! Load our resources system
entity_registry_.set<antara::gaming::sfml::resources_system>(entity_registry_);
entity_registry_.set<sfml::resources_system>(entity_registry_);

//! Load our input system with the window from the graphical system
system_manager_.create_system<sfml::input_system>(graphic_system.get_window());
Expand Down

0 comments on commit e15ecbd

Please sign in to comment.