Amélioration des interactions
This commit is contained in:
parent
77c5bd2876
commit
603c2fff65
|
@ -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
|
||||||
|
|
202
src/editor.cpp
202
src/editor.cpp
|
@ -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++) {
|
void Editor::select(ObjectPtr object, SelectionMode mode) {
|
||||||
if (objects[i]->getAABB()->contains(position)) {
|
if (object == nullptr) {
|
||||||
remove_object_index = i;
|
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) {
|
// dans le mode ADD, on rajoute juste l'objet à la sélection
|
||||||
selection.erase(std::remove(
|
if (mode == SelectionMode::ADD && !already_selected) {
|
||||||
selection.begin(), selection.end(), objects[remove_object_index]
|
object->setSelected(true);
|
||||||
), selection.end());
|
selection.push_back(object);
|
||||||
|
|
||||||
objects.erase(objects.begin() + remove_object_index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Editor::updateSelection(sf::Vector2f position) {
|
void Editor::select(sf::Vector2f position, SelectionMode mode) {
|
||||||
std::vector<ObjectPtr>& objects = getObjects();
|
select(getObject(position), mode);
|
||||||
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::testLevel() {
|
void Editor::testLevel() {
|
||||||
|
|
Loading…
Reference in New Issue