Amélioration des interactions

This commit is contained in:
Mattéo Delabre 2016-04-07 20:59:08 +02:00
parent 77c5bd2876
commit 603c2fff65
2 changed files with 171 additions and 61 deletions

View File

@ -5,6 +5,9 @@
#include "level.hpp" #include "level.hpp"
#include "util/widget_timer.hpp" #include "util/widget_timer.hpp"
enum class DragMode {NONE, PLACE_OBJECTS, SELECT_RECT, SELECT_BULK};
enum class SelectionMode {REPLACE, FLIP, ADD};
/** /**
* La classe Editor permet l'édition de * La classe Editor permet l'édition de
* niveaux du jeu * niveaux du jeu
@ -12,25 +15,38 @@
class Editor : public Level { class Editor : public Level {
private: private:
std::vector<ObjectPtr> selection; std::vector<ObjectPtr> selection;
sf::Vector2f drag_start;
sf::Vector2f drag_end;
DragMode drag_mode;
WidgetTimer widget_timer; WidgetTimer widget_timer;
/**
* Renvoie l'objet pointé à la position donnée
* ou nullptr si aucun
*/
ObjectPtr getObject(sf::Vector2f position);
/** /**
* Ajoute un objet du type actuel à la position donnée * Ajoute un objet du type actuel à la position donnée
*/ */
void addObject(sf::Vector2f position); ObjectPtr addObject(sf::Vector2f position);
/** /**
* Supprime les objets passant par la position donnée * Supprime l'objet à la position donnée ou passé par pointeur
*/ */
void removeObject(ObjectPtr object);
void removeObject(sf::Vector2f position); void removeObject(sf::Vector2f position);
/** /**
* Met à jour la sélection avec la position donnée : * Ajoute l'objet donné (par position ou par pointeur)
* - si la position correspond à un objet, si cet objet n'est * à la sélection
* pas sélectionné on le sélectionne, sinon on le désélectionne *
* - si la sélection est modifiée, renvoie true, sinon false * - REPLACE : remplace toute sélection précédente
* - FLIP : sélectionne l'élément s'il ne l'est pas, sinon le désélectionne
* - ADD : rajoute à la sélection courante
*/ */
bool updateSelection(sf::Vector2f position); void select(ObjectPtr object, SelectionMode mode);
void select(sf::Vector2f position, SelectionMode mode);
/** /**
* Lance le test du niveau * Lance le test du niveau

View File

@ -5,7 +5,10 @@
#include "block.hpp" #include "block.hpp"
#include "constants.hpp" #include "constants.hpp"
Editor::Editor(Manager& manager) : Level(manager), const sf::Color SELECTION_COLOR = sf::Color(33, 33, 33, 40);
const sf::Color SELECTION_BORDER_COLOR = sf::Color(33, 33, 33, 127);
Editor::Editor(Manager& manager) : Level(manager), drag_mode(DragMode::NONE),
widget_timer(manager, true, std::bind(&Editor::setTotalTime, this, std::placeholders::_1)) {} widget_timer(manager, true, std::bind(&Editor::setTotalTime, this, std::placeholders::_1)) {}
Editor::~Editor() {} Editor::~Editor() {}
@ -30,21 +33,84 @@ void Editor::frame() {
// lorsque l'on clique dans l'éditeur // lorsque l'on clique dans l'éditeur
if (event.type == sf::Event::MouseButtonPressed) { if (event.type == sf::Event::MouseButtonPressed) {
sf::Vector2f position(event.mouseButton.x, event.mouseButton.y); sf::Vector2f position(event.mouseButton.x, event.mouseButton.y);
ObjectPtr pointed_object = getObject(position);
if (event.mouseButton.button == sf::Mouse::Left) { if (event.mouseButton.button == sf::Mouse::Left) {
// clic gauche : on met à jour la sélection, // clic + shift : sélection par rectangle de sélection
// si aucune mise à jour n'est à faire, on ajoute un objet if (manager.isKeyPressed(sf::Keyboard::LShift)) {
if (!updateSelection(position)) { drag_start = position;
addObject(position); drag_end = position;
drag_mode = DragMode::SELECT_RECT;
continue;
}
// clic sur un objet : démarrage de la sélection libre
if (pointed_object != nullptr) {
if (manager.isKeyPressed(sf::Keyboard::LControl)) {
drag_start = position;
drag_end = position;
drag_mode = DragMode::SELECT_BULK;
select(pointed_object, SelectionMode::ADD);
} else {
select(pointed_object, SelectionMode::FLIP);
}
}
// clic gauche dans le vide : démarrage du placement
// en drag&ndrop
else {
drag_start = position;
drag_end = position;
drag_mode = DragMode::PLACE_OBJECTS;
select(addObject(position), SelectionMode::REPLACE);
} }
} else if (event.mouseButton.button == sf::Mouse::Right) { } else if (event.mouseButton.button == sf::Mouse::Right) {
// clic droit : on supprime l'objet pointé // clic droit : on supprime l'objet pointé
removeObject(position); removeObject(pointed_object);
} }
} }
// lorsqu'on déplace la souris
if (event.type == sf::Event::MouseMoved) {
sf::Vector2f position(event.mouseMove.x, event.mouseMove.y);
ObjectPtr pointed_object = getObject(position);
drag_end = position;
// mode placement d'objets
if (drag_mode == DragMode::PLACE_OBJECTS && pointed_object == nullptr) {
select(addObject(position), SelectionMode::ADD);
}
// mode sélection libre : on l'objet à la sélection
if (drag_mode == DragMode::SELECT_BULK) {
select(position, SelectionMode::ADD);
}
}
// lorsqu'on relâche un clic dans l'éditeur
if (event.type == sf::Event::MouseButtonReleased) {
sf::Vector2f position(event.mouseButton.x, event.mouseButton.y);
drag_mode = DragMode::NONE;
}
// gestion des touches // gestion des touches
if (event.type == sf::Event::KeyPressed) { if (event.type == sf::Event::KeyPressed) {
// appui sur suppr : suppression des blocs sélectionnés
if (event.key.code == sf::Keyboard::Delete) {
std::vector<ObjectPtr>& objects = getObjects();
for (unsigned int i = 0; i < selection.size(); i++) {
objects.erase(std::remove(
objects.begin(), objects.end(), selection[i]
), objects.end());
}
selection.clear();
}
// appui sur espace : test du niveau en cours d'édition // appui sur espace : test du niveau en cours d'édition
if (event.key.code == sf::Keyboard::Space) { if (event.key.code == sf::Keyboard::Space) {
testLevel(); testLevel();
@ -65,6 +131,17 @@ void Editor::draw() {
sf::RenderWindow& window = manager.getWindow(); sf::RenderWindow& window = manager.getWindow();
sf::View window_view = manager.getWindowView(); sf::View window_view = manager.getWindowView();
// dessin du rectangle de sélection
if (drag_mode == DragMode::SELECT_RECT) {
sf::RectangleShape selection_rect(drag_end - drag_start);
selection_rect.setPosition(drag_start);
selection_rect.setFillColor(SELECTION_COLOR);
selection_rect.setOutlineThickness(2.f);
selection_rect.setOutlineColor(SELECTION_BORDER_COLOR);
window.draw(selection_rect);
}
// dessin du widget timer // dessin du widget timer
widget_timer.setTimeLeft(getTotalTime()); widget_timer.setTimeLeft(getTotalTime());
widget_timer.draw(sf::Vector2f(window_view.getSize().x / 2 - 50, 0)); widget_timer.draw(sf::Vector2f(window_view.getSize().x / 2 - 50, 0));
@ -76,10 +153,22 @@ void Editor::draw() {
window.draw(menu); window.draw(menu);
} }
void Editor::addObject(sf::Vector2f position) { ObjectPtr Editor::getObject(sf::Vector2f position) {
std::vector<ObjectPtr>& objects = getObjects(); std::vector<ObjectPtr>& objects = getObjects();
// si demandé, on arrondit à l'unité de grille la plus proche for (unsigned int i = 0; i < objects.size(); i++) {
if (objects[i]->getAABB()->contains(position)) {
return objects[i];
}
}
return nullptr;
}
ObjectPtr Editor::addObject(sf::Vector2f position) {
std::vector<ObjectPtr>& objects = getObjects();
// on arrondit à l'unité de grille la plus proche
position /= Constants::GRID; position /= Constants::GRID;
position.x = round(position.x); position.x = round(position.x);
position.y = round(position.y); position.y = round(position.y);
@ -101,63 +190,68 @@ void Editor::addObject(sf::Vector2f position) {
if (!overlaps) { if (!overlaps) {
objects.push_back(object); objects.push_back(object);
updateSelection(position); return object;
} }
return nullptr;
}
void Editor::removeObject(ObjectPtr object) {
if (object == nullptr) {
return;
}
std::vector<ObjectPtr>& objects = getObjects();
// on supprime l'objet de la sélection
selection.erase(std::remove(
selection.begin(), selection.end(), object
), selection.end());
// on supprime l'objet de la liste d'objets
objects.erase(std::remove(
objects.begin(), objects.end(), object
), selection.end());
} }
void Editor::removeObject(sf::Vector2f position) { void Editor::removeObject(sf::Vector2f position) {
std::vector<ObjectPtr>& objects = getObjects(); removeObject(getObject(position));
int remove_object_index = -1;
for (unsigned int i = 0; i < objects.size(); i++) {
if (objects[i]->getAABB()->contains(position)) {
remove_object_index = i;
}
}
if (remove_object_index >= 0) {
selection.erase(std::remove(
selection.begin(), selection.end(), objects[remove_object_index]
), selection.end());
objects.erase(objects.begin() + remove_object_index);
}
} }
bool Editor::updateSelection(sf::Vector2f position) { void Editor::select(ObjectPtr object, SelectionMode mode) {
std::vector<ObjectPtr>& objects = getObjects(); if (object == nullptr) {
bool has_changed = false; return;
bool multi = manager.isKeyPressed(sf::Keyboard::LShift); }
for (unsigned int i = 0; i < objects.size(); i++) { bool already_selected = std::count(selection.begin(), selection.end(), object) > 0;
if (objects[i]->getAABB()->contains(position)) {
has_changed = true;
// si l'objet n'est pas sélectionné, on le sélectionne // dans les modes REPLACE et FLIP, on remplace l'ancienne sélection
// sinon on le désélectionne // pour REPLACE, on sélectionne forcément l'objet
if (std::count(selection.begin(), selection.end(), objects[i]) > 0) { // pour FLIP, on le sélectionne s'il ne l'est pas, on le désélectionne sinon
objects[i]->setSelected(false); if (mode == SelectionMode::REPLACE || mode == SelectionMode::FLIP) {
selection.erase(std::remove(
selection.begin(), selection.end(), objects[i]
), selection.end());
} else {
// avant de sélectionner le nouvel objet, on
// vide la sélection si on n'est pas en mode multi
if (!multi) {
for (unsigned int i = 0; i < selection.size(); i++) { for (unsigned int i = 0; i < selection.size(); i++) {
selection[i]->setSelected(false); selection[i]->setSelected(false);
} }
selection.clear(); selection.clear();
}
selection.push_back(objects[i]); // on resélectionne l'objet ssi. on force la sélection
objects[i]->setSelected(true); // ou s'il n'était pas déjà sélectionné
} if (!already_selected || mode == SelectionMode::REPLACE) {
object->setSelected(true);
selection.push_back(object);
} }
} }
return has_changed; // dans le mode ADD, on rajoute juste l'objet à la sélection
if (mode == SelectionMode::ADD && !already_selected) {
object->setSelected(true);
selection.push_back(object);
}
}
void Editor::select(sf::Vector2f position, SelectionMode mode) {
select(getObject(position), mode);
} }
void Editor::testLevel() { void Editor::testLevel() {