Amélioration des interactions
This commit is contained in:
		
							parent
							
								
									77c5bd2876
								
							
						
					
					
						commit
						603c2fff65
					
				|  | @ -5,6 +5,9 @@ | |||
| #include "level.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 | ||||
|  * niveaux du jeu | ||||
|  | @ -12,25 +15,38 @@ | |||
| class Editor : public Level { | ||||
| private: | ||||
|     std::vector<ObjectPtr> selection; | ||||
|     sf::Vector2f drag_start; | ||||
|     sf::Vector2f drag_end; | ||||
|     DragMode drag_mode; | ||||
|     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 | ||||
|      */ | ||||
|     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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Met à jour la sélection avec la position donnée : | ||||
|      * - si la position correspond à un objet, si cet objet n'est | ||||
|      *   pas sélectionné on le sélectionne, sinon on le désélectionne | ||||
|      * - si la sélection est modifiée, renvoie true, sinon false | ||||
|      * Ajoute l'objet donné (par position ou par pointeur) | ||||
|      * à la sélection | ||||
|      * | ||||
|      * - 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 | ||||
|  |  | |||
							
								
								
									
										202
									
								
								src/editor.cpp
								
								
								
								
							
							
						
						
									
										202
									
								
								src/editor.cpp
								
								
								
								
							|  | @ -5,7 +5,10 @@ | |||
| #include "block.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)) {} | ||||
| 
 | ||||
| Editor::~Editor() {} | ||||
|  | @ -30,21 +33,84 @@ void Editor::frame() { | |||
|         // lorsque l'on clique dans l'éditeur
 | ||||
|         if (event.type == sf::Event::MouseButtonPressed) { | ||||
|             sf::Vector2f position(event.mouseButton.x, event.mouseButton.y); | ||||
|             ObjectPtr pointed_object = getObject(position); | ||||
| 
 | ||||
|             if (event.mouseButton.button == sf::Mouse::Left) { | ||||
|                 // clic gauche : on met à jour la sélection,
 | ||||
|                 // si aucune mise à jour n'est à faire, on ajoute un objet
 | ||||
|                 if (!updateSelection(position)) { | ||||
|                     addObject(position); | ||||
|                 // clic + shift : sélection par rectangle de sélection
 | ||||
|                 if (manager.isKeyPressed(sf::Keyboard::LShift)) { | ||||
|                     drag_start = 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) { | ||||
|                 // 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
 | ||||
|         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
 | ||||
|             if (event.key.code == sf::Keyboard::Space) { | ||||
|                 testLevel(); | ||||
|  | @ -65,6 +131,17 @@ void Editor::draw() { | |||
|     sf::RenderWindow& window = manager.getWindow(); | ||||
|     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
 | ||||
|     widget_timer.setTimeLeft(getTotalTime()); | ||||
|     widget_timer.draw(sf::Vector2f(window_view.getSize().x / 2 - 50, 0)); | ||||
|  | @ -76,10 +153,22 @@ void Editor::draw() { | |||
|     window.draw(menu); | ||||
| } | ||||
| 
 | ||||
| void Editor::addObject(sf::Vector2f position) { | ||||
| ObjectPtr Editor::getObject(sf::Vector2f position) { | ||||
|     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.x = round(position.x); | ||||
|     position.y = round(position.y); | ||||
|  | @ -101,63 +190,68 @@ void Editor::addObject(sf::Vector2f position) { | |||
| 
 | ||||
|     if (!overlaps) { | ||||
|         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) { | ||||
|     std::vector<ObjectPtr>& objects = getObjects(); | ||||
|     int remove_object_index = -1; | ||||
|     removeObject(getObject(position)); | ||||
| } | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < objects.size(); i++) { | ||||
|         if (objects[i]->getAABB()->contains(position)) { | ||||
|             remove_object_index = i; | ||||
| void Editor::select(ObjectPtr object, SelectionMode mode) { | ||||
|     if (object == nullptr) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     bool already_selected = std::count(selection.begin(), selection.end(), object) > 0; | ||||
| 
 | ||||
|     // dans les modes REPLACE et FLIP, on remplace l'ancienne sélection
 | ||||
|     // pour REPLACE, on sélectionne forcément l'objet
 | ||||
|     // pour FLIP, on le sélectionne s'il ne l'est pas, on le désélectionne sinon
 | ||||
|     if (mode == SelectionMode::REPLACE || mode == SelectionMode::FLIP) { | ||||
|         for (unsigned int i = 0; i < selection.size(); i++) { | ||||
|             selection[i]->setSelected(false); | ||||
|         } | ||||
| 
 | ||||
|         selection.clear(); | ||||
| 
 | ||||
|         // on resélectionne l'objet ssi. on force la sélection
 | ||||
|         // ou s'il n'était pas déjà sélectionné
 | ||||
|         if (!already_selected || mode == SelectionMode::REPLACE) { | ||||
|             object->setSelected(true); | ||||
|             selection.push_back(object); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
|     // 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); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool Editor::updateSelection(sf::Vector2f position) { | ||||
|     std::vector<ObjectPtr>& objects = getObjects(); | ||||
|     bool has_changed = false; | ||||
|     bool multi = manager.isKeyPressed(sf::Keyboard::LShift); | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < objects.size(); i++) { | ||||
|         if (objects[i]->getAABB()->contains(position)) { | ||||
|             has_changed = true; | ||||
| 
 | ||||
|             // si l'objet n'est pas sélectionné, on le sélectionne
 | ||||
|             // sinon on le désélectionne
 | ||||
|             if (std::count(selection.begin(), selection.end(), objects[i]) > 0) { | ||||
|                 objects[i]->setSelected(false); | ||||
|                 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++) { | ||||
|                         selection[i]->setSelected(false); | ||||
|                     } | ||||
| 
 | ||||
|                     selection.clear(); | ||||
|                 } | ||||
| 
 | ||||
|                 selection.push_back(objects[i]); | ||||
|                 objects[i]->setSelected(true); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return has_changed; | ||||
| void Editor::select(sf::Vector2f position, SelectionMode mode) { | ||||
|     select(getObject(position), mode); | ||||
| } | ||||
| 
 | ||||
| void Editor::testLevel() { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue