From be628dc7f9c32ca84674c8717f07cc15a40f333c Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Sun, 1 Apr 2018 13:46:47 +0200 Subject: Improve selecting. --- src/common.hpp | 12 +++++++++- src/game/game.cpp | 65 +++++++++++++++++++++++++++++++++++++++++--------- src/game/interface.cpp | 36 ++++++++++++++++++++++++---- src/math.hpp | 10 ++++++++ src/render.cpp | 9 +++++-- 5 files changed, 114 insertions(+), 18 deletions(-) diff --git a/src/common.hpp b/src/common.hpp index fcda5e5..0f51590 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -248,8 +248,15 @@ namespace game { die_t(size_t count_, size_t sides_, size_t bonus_); }; + enum { + SELECT_NEW, + SELECT_OR, + SELECT_XOR + }; + class state_t { void group_say(std::string text); + void select_unit(unit_t *unit, int type); public: world::world_t world; @@ -274,7 +281,7 @@ namespace game { void resume(void); // These are called by the interface. - void select(rectf_t rect); + void select(rectf_t rect, int type); bool populate_pie_menu(std::vector &items); void command(v2f_t x, int number); void spawn_soldier(v2f_t x); @@ -323,6 +330,7 @@ namespace interface { struct { bool selecting = false; + int type; rectf_t rect; } select; @@ -394,6 +402,8 @@ namespace render { } text_align_t; void register_tile(uint8_t type, const char *top, const char *side, float height); + bool rendering_order(const world::entity_t *x, const world::entity_t *y); + bool visibility_order(const world::entity_t *x, const world::entity_t *y); class state_t { sf::RenderWindow *window; diff --git a/src/game/game.cpp b/src/game/game.cpp index f21bccd..27db5e5 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -91,7 +91,6 @@ void state_t::start(void) soldier->place(&world, v2f_t(1.5, 0.5)); soldier = new unit_soldier_t(this); soldier->place(&world, v2f_t(2.5, 0.5)); - select(rectf_t(v2f_t(0.5, 0.5), v2f_t(2.5, 0.5))); resume(); } @@ -105,12 +104,53 @@ void state_t::group_say(std::string text) interface->print(text::get(text::SAY_GROUP) + ": " + text); } -void state_t::select(rectf_t x) +void state_t::select_unit(unit_t *unit, int type) { - selection_cookie++; - selected_units.clear(); + switch (type) { + case SELECT_NEW: + case SELECT_OR: + if (unit->selected == selection_cookie) + return; + else + goto do_select; + + case SELECT_XOR: + if (unit->selected == selection_cookie) + goto do_deselect; + else + goto do_select; + } + +do_select: + unit->selected = selection_cookie; + selected_units.insert(unit); + return; + +do_deselect: + unit->selected = selection_cookie - 1; + selected_units.erase(unit); +} + +void state_t::select(rectf_t rect, int type) +{ + size_t before; + bool select_one; + std::list ents; + + before = selected_units.size(); - for (world::entity_t *ent : world.get_render_entities(x)) { + if (type == SELECT_NEW) { + selection_cookie++; + selected_units.clear(); + } + + select_one = rect.area() < 0.2f; + + ents = world.get_render_entities(rect); + if (select_one) + ents.sort(render::visibility_order); + + for (world::entity_t *ent : ents) { unit_t *unit; if (ent->type != ET_UNIT) @@ -121,14 +161,17 @@ void state_t::select(rectf_t x) if (!unit->controllable) continue; - unit->selected = selection_cookie; - selected_units.insert(unit); + select_unit(unit, type); + if (select_one) + break; } - if (selected_units.size() == 1) - (*selected_units.begin())->say(text::get(text::SAY_READY)); - else if (selected_units.size() > 1) - group_say(text::get(text::SAY_READY_GROUP)); + if (selected_units.size() > before) { + if (selected_units.size() == 1) + (*selected_units.begin())->say(text::get(text::SAY_READY)); + else if (selected_units.size() > 1) + group_say(text::get(text::SAY_READY_GROUP)); + } } enum { diff --git a/src/game/interface.cpp b/src/game/interface.cpp index 25d256c..8a02e98 100644 --- a/src/game/interface.cpp +++ b/src/game/interface.cpp @@ -114,6 +114,15 @@ void pie_menu_t::update(v2f_t mouse) } } +static int get_selection_type(void) +{ + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LControl)) + return game::SELECT_OR; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift)) + return game::SELECT_XOR; + return game::SELECT_NEW; +} + void state_t::tick(double dt) { vec_t window_size; @@ -205,7 +214,7 @@ void state_t::tick(double dt) switch (event.mouseButton.button) { case sf::Mouse::Button::Left: if (select.selecting) - game->select(select.rect); + game->select(select.rect, select.type); select.selecting = false; break; @@ -279,8 +288,10 @@ void state_t::tick(double dt) } } - if (select.selecting) + if (select.selecting) { + select.type = get_selection_type(); select.rect[1] = wmouse; + } pie_menu.update(mouse); } @@ -327,8 +338,25 @@ void state_t::render_to(render::state_t *render) std::stringstream ss; double fps; - if (select.selecting) - render->render_hlrect(select.rect, sf::Color(60, 60, 150)); + if (select.selecting) { + sf::Color color; + + switch (select.type) { + case SELECT_NEW: + color = sf::Color(60, 60, 150); + break; + + case SELECT_OR: + color = sf::Color(60, 150, 60); + break; + + case SELECT_XOR: + color = sf::Color(150, 150, 60); + break; + } + + render->render_hlrect(select.rect, color); + } window->setView(sf::View(sf::FloatRect(0, 0, w, h))); em = std::max(w, h) * 0.017; diff --git a/src/math.hpp b/src/math.hpp index 9b909cf..7cbd829 100644 --- a/src/math.hpp +++ b/src/math.hpp @@ -352,6 +352,16 @@ public: return min; } + T area(void) const + { + T area = 1; + + for (size_t i = 0; i < N; i++) + area *= dim(i); + + return area; + } + rect_t norm(void) const { rect_t r; diff --git a/src/render.cpp b/src/render.cpp index 96153f9..beda97b 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -200,7 +200,7 @@ rectf_t state_t::window_in_world_space(void) return window_bounds(window); } -bool entity_order(const world::entity_t *x, const world::entity_t *y) +bool rendering_order(const world::entity_t *x, const world::entity_t *y) { if (x->render_layer < y->render_layer) return true; @@ -210,6 +210,11 @@ bool entity_order(const world::entity_t *x, const world::entity_t *y) return x->render_bounds[1][1] < y->render_bounds[1][1]; } +bool visibility_order(const world::entity_t *x, const world::entity_t *y) +{ + return !rendering_order(x, y); +} + void state_t::render(game::state_t *game) { rectf_t bounds; @@ -222,7 +227,7 @@ void state_t::render(game::state_t *game) sectors[1] = world::sector_index_at(bounds[1]); ents = game->world.get_render_entities(bounds); - ents.sort(entity_order); + ents.sort(rendering_order); ent = ents.begin(); for (world::coord_t sy = sectors[0][1]; sy <= sectors[1][1]; sy++) -- cgit