Gestion de la sélection en externe des objets & multisélection
This commit is contained in:
parent
83e644a0e8
commit
cb3e02ff4a
|
@ -1,6 +1,7 @@
|
|||
#ifndef __PTF_GAME_HPP__
|
||||
#define __PTF_GAME_HPP__
|
||||
|
||||
#include <unordered_map>
|
||||
#include "level.hpp"
|
||||
|
||||
/**
|
||||
|
@ -9,7 +10,25 @@
|
|||
*/
|
||||
class Editor : public Level {
|
||||
private:
|
||||
ObjectPtr selected_object;
|
||||
std::unordered_map<ObjectPtr, bool> selection;
|
||||
|
||||
/**
|
||||
* Ajoute un objet du type actuel à la position donnée
|
||||
*/
|
||||
void addObject(sf::Vector2f position);
|
||||
|
||||
/**
|
||||
* Supprime les objets passant par la position donnée
|
||||
*/
|
||||
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
|
||||
*/
|
||||
bool updateSelection(sf::Vector2f position);
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
|
@ -18,9 +18,6 @@ private:
|
|||
|
||||
mutable float inv_mass;
|
||||
|
||||
sf::Sprite selection_sprite;
|
||||
bool is_selected;
|
||||
|
||||
float mass;
|
||||
float charge;
|
||||
float restitution;
|
||||
|
@ -195,16 +192,6 @@ public:
|
|||
* Modifie la couche d'affichage de l'objet
|
||||
*/
|
||||
void setLayer(int set_layer);
|
||||
|
||||
/**
|
||||
* Récupère si l'objet est actuellement sélectionné
|
||||
*/
|
||||
bool isSelected() const;
|
||||
|
||||
/**
|
||||
* Sélectionne ou désélectionne l'objet
|
||||
*/
|
||||
void setSelected(bool set_selected);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
176
src/editor.cpp
176
src/editor.cpp
|
@ -1,10 +1,9 @@
|
|||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "editor.hpp"
|
||||
#include "block.hpp"
|
||||
#include "constants.hpp"
|
||||
|
||||
Editor::Editor(Manager& manager) : Level(manager), selected_object(nullptr) {
|
||||
Editor::Editor(Manager& manager) : Level(manager) {
|
||||
// activation de la synchronisation verticale
|
||||
// car, dans l'éditeur, nous n'avons besoin que de dessiner
|
||||
// (pas de mise à jour physique)
|
||||
|
@ -15,7 +14,6 @@ Editor::~Editor() {}
|
|||
|
||||
void Editor::frame() {
|
||||
const std::vector<sf::Event>& events = manager.getEvents();
|
||||
std::vector<ObjectPtr>& objects = getObjects();
|
||||
|
||||
for (unsigned int i = 0; i < events.size(); i++) {
|
||||
const sf::Event& event = events[i];
|
||||
|
@ -23,77 +21,18 @@ 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);
|
||||
bool selection_changed = false;
|
||||
|
||||
if (event.mouseButton.button == sf::Mouse::Left) {
|
||||
// recherche d'un objet intersectant la position cliquée
|
||||
// et le sélectionne si c'est le cas
|
||||
for (unsigned int i = 0; i < objects.size(); i++) {
|
||||
if (objects[i]->getAABB()->contains(position)) {
|
||||
selection_changed = true;
|
||||
|
||||
// si l'objet n'est pas sélectionné, on le sélectionne
|
||||
// sinon on le désélectionne
|
||||
if (objects[i]->isSelected()) {
|
||||
objects[i]->setSelected(false);
|
||||
selected_object = nullptr;
|
||||
} else {
|
||||
// désélection du précédent objet (si applicable)
|
||||
if (selected_object != nullptr) {
|
||||
selected_object->setSelected(false);
|
||||
}
|
||||
|
||||
selected_object = objects[i];
|
||||
objects[i]->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// si aucune opération de sélection, on
|
||||
// crée un nouvel objet à la position cliquée
|
||||
if (!selection_changed) {
|
||||
// on désélectionne tout objet sélectionné
|
||||
if (selected_object != nullptr) {
|
||||
selected_object->setSelected(false);
|
||||
selected_object = nullptr;
|
||||
}
|
||||
|
||||
position /= Constants::GRID;
|
||||
position.x = round(position.x);
|
||||
position.y = round(position.y);
|
||||
position *= Constants::GRID;
|
||||
|
||||
std::shared_ptr<Object> object = std::shared_ptr<Object>(new Block);
|
||||
object->setPosition(position);
|
||||
|
||||
// avant d'ajouter l'objet, on vérifie qu'il ne soit
|
||||
// pas superposé à un autre
|
||||
float overlaps = false;
|
||||
|
||||
for (unsigned int i = 0; i < objects.size(); i++) {
|
||||
if (objects[i]->getAABB()->intersects(*object->getAABB())) {
|
||||
overlaps = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!overlaps) {
|
||||
objects.push_back(object);
|
||||
}
|
||||
// clic gauche : on met à jour la sélection,
|
||||
// si aucune mise à jour n'est à faire, on ajoute un objet
|
||||
if (!updateSelection(position)) {
|
||||
addObject(position);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.mouseButton.button == sf::Mouse::Right) {
|
||||
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) {
|
||||
objects.erase(objects.begin() + remove_object_index);
|
||||
}
|
||||
// clic droit : on supprime l'objet pointé
|
||||
removeObject(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,10 +42,105 @@ void Editor::frame() {
|
|||
|
||||
void Editor::draw() {
|
||||
Level::draw();
|
||||
sf::RenderWindow& window = manager.getWindow();
|
||||
sf::View window_view = manager.getWindowView();
|
||||
sf::Color selection_color(255, 50, 41);
|
||||
|
||||
// on dessine des carrés de sélection autour des objets sélectionnés
|
||||
for (auto iter = selection.begin(); iter != selection.end(); iter++) {
|
||||
sf::VertexArray selection(sf::LinesStrip, 5);
|
||||
std::unique_ptr<sf::FloatRect> aabb = iter->first->getAABB();
|
||||
|
||||
selection[0].position = sf::Vector2f(aabb->left - .5f, aabb->top - .5f);
|
||||
selection[0].color = selection_color;
|
||||
selection[1].position = sf::Vector2f(aabb->left + aabb->width + .5f, aabb->top - .5f);
|
||||
selection[1].color = selection_color;
|
||||
selection[2].position = sf::Vector2f(aabb->left + aabb->width + .5f, aabb->top + aabb->height + .5f);
|
||||
selection[2].color = selection_color;
|
||||
selection[3].position = sf::Vector2f(aabb->left - .5f, aabb->top + aabb->height + .5f);
|
||||
selection[3].color = selection_color;
|
||||
selection[4].position = sf::Vector2f(aabb->left - .5f, aabb->top - .5f);
|
||||
selection[4].color = selection_color;
|
||||
|
||||
window.draw(selection);
|
||||
}
|
||||
|
||||
// menu
|
||||
sf::RectangleShape menu(sf::Vector2f(manager.getWindowView().getSize().x, 64));
|
||||
menu.setPosition(sf::Vector2f(0, manager.getWindowView().getSize().y - 64));
|
||||
sf::RectangleShape menu(sf::Vector2f(window_view.getSize().x, 64));
|
||||
menu.setPosition(sf::Vector2f(0, window_view.getSize().y - 64));
|
||||
|
||||
manager.getWindow().draw(menu);
|
||||
window.draw(menu);
|
||||
}
|
||||
|
||||
void Editor::addObject(sf::Vector2f position) {
|
||||
std::vector<ObjectPtr>& objects = getObjects();
|
||||
|
||||
// si demandé, on arrondit à l'unité de grille la plus proche
|
||||
position /= Constants::GRID;
|
||||
position.x = round(position.x);
|
||||
position.y = round(position.y);
|
||||
position *= Constants::GRID;
|
||||
|
||||
// TODO: ajouter un objet du type choisi, pas uniquement de bloc
|
||||
std::shared_ptr<Object> object = std::shared_ptr<Object>(new Block);
|
||||
object->setPosition(position);
|
||||
|
||||
// avant d'ajouter l'objet, on vérifie qu'il ne soit
|
||||
// pas superposé à un autre
|
||||
float overlaps = false;
|
||||
|
||||
for (unsigned int i = 0; i < objects.size(); i++) {
|
||||
if (objects[i]->getAABB()->intersects(*object->getAABB())) {
|
||||
overlaps = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!overlaps) {
|
||||
objects.push_back(object);
|
||||
updateSelection(position);
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::removeObject(sf::Vector2f position) {
|
||||
std::vector<ObjectPtr>& objects = getObjects();
|
||||
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(objects[remove_object_index]);
|
||||
objects.erase(objects.begin() + remove_object_index);
|
||||
}
|
||||
}
|
||||
|
||||
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 (selection.count(objects[i])) {
|
||||
selection.erase(objects[i]);
|
||||
} else {
|
||||
// avant de sélectionner le nouvel objet, on
|
||||
// vide la sélection si on n'est pas en mode multi
|
||||
if (!multi) {
|
||||
selection.clear();
|
||||
}
|
||||
|
||||
selection[objects[i]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return has_changed;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const unsigned int Object::PROP_LAYER = 6;
|
|||
|
||||
Object::Object() :
|
||||
acceleration(0, 0), velocity(0, 0), position(0, 0),
|
||||
inv_mass(-1.f), is_selected(false),
|
||||
inv_mass(-1.f),
|
||||
|
||||
// valeurs par défaut pour les propriétés
|
||||
// de tous les objets du jeu
|
||||
|
@ -128,18 +128,7 @@ sf::Vector2f Object::getForces(
|
|||
return forces;
|
||||
}
|
||||
|
||||
void Object::draw(Manager& manager) {
|
||||
// si l'objet est sélectionné, dessin de la texture de sélection
|
||||
if (isSelected()) {
|
||||
selection_sprite.setOrigin(sf::Vector2f(22, 22));
|
||||
selection_sprite.setPosition(getPosition());
|
||||
selection_sprite.setTexture(
|
||||
manager.getResourceManager().getTexture("selection.png")
|
||||
);
|
||||
|
||||
manager.getWindow().draw(selection_sprite);
|
||||
}
|
||||
}
|
||||
void Object::draw(Manager& manager) {}
|
||||
|
||||
void Object::updateVelocity(
|
||||
const Manager& manager, const std::vector<ObjectPtr>& objects, float delta
|
||||
|
@ -326,25 +315,6 @@ void Object::setLayer(int set_layer) {
|
|||
layer = set_layer;
|
||||
}
|
||||
|
||||
bool Object::isSelected() const {
|
||||
return is_selected;
|
||||
}
|
||||
|
||||
void Object::setSelected(bool set_selected) {
|
||||
is_selected = set_selected;
|
||||
}
|
||||
|
||||
bool ObjectCompare::operator()(ObjectPtr const &t1, ObjectPtr const &t2) const {
|
||||
// détermine la priorité de dessin des objets
|
||||
// - si un objet est sélectionné, il est prioritaire
|
||||
// - sinon, l'objet de la plus haute couche est prioritaire
|
||||
if (t1->isSelected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t2->isSelected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return t1->getLayer() > t2->getLayer();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue