Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Graph de scene, les transformations ne se combinent pas!  (Lu 2371 fois)

0 Membres et 1 Invité sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Graph de scene, les transformations ne se combinent pas!
« le: Septembre 21, 2013, 10:15:29 am »
Salut.
J'ai essayé de faire un graph de scene plus complexe, un genre de design à base de composant, avec un composant racine contenant la transformation de toute entité. (donc toute entité transformable et dessinable hérite de ce composant, ce composant est invisible, il ne contient que la transformation de l'entité, c'est en fait la classe Transformable que j'ai fait à ma sauce.)
#ifndef DYNAMIC_DRAWABLE_ENTITY
#define DYNAMIC_DRAWABLE_ENTITY

#include <SFML/Graphics.hpp>
#include "vec2f.h"
class DynamicDrawableEntity : public sf::Drawable {
public :

    FloatRect getLocalBounds() {
        return localBounds;
    }
    void setCenter(Vec2f center) {
        Vec2f t = center - m_center ;
        move(t);
        needToUpdate = true;
        inverseNeedToUpdate = true;
    }
    Vec2f getCenter() {
        return m_center;
    }
    void setPosition(Vec2f position) {
        Vec2f t = position - m_position;
        move(t);
        needToUpdate = true;
        inverseNeedToUpdate = true;
    }
    Vec2f getSize() {
        return m_size;
    }
    Vec2f getPosition() {
        return m_position;
    }
    void setRotation (float angle) {
        m_rotation = static_cast<float>(fmod(angle, 360));
        if (m_rotation < 0)
            m_rotation += 360.f;
        angle  = -m_rotation * 3.141592654f / 180.f;
        needToUpdate = true;
        inverseNeedToUpdate = true;
        FloatRect bounds = getGlobalBounds();
        m_size.x = bounds.width;
        m_size.y = bounds.height;
        Vec2f delta (m_size.x / bounds.width * m_origin.x, m_size.y / bounds.height * m_origin.y);
        m_position = m_center - delta;
        onRotate(angle);
    }
    void setScale(Vec2f scale) {
        m_scale = scale;
        needToUpdate = true;
        inverseNeedToUpdate = true;
        FloatRect bounds = getGlobalBounds();
        m_size.x = bounds.width;
        m_size.y = bounds.height;
        m_position = m_center - m_scale * m_origin;
        onScale(scale);
    }
    void scale(Vec2f s) {
        setScale(m_scale * s);
    }
    void rotate (float angle) {
        setRotation(m_rotation + angle);
    }
    void move (Vec2f t) {
        m_position += t;
        m_center += t;
        needToUpdate = true;
        inverseNeedToUpdate = true;
        onMove(t);
    }
    void setOrigin(Vec2f origin) {
       Vec2f t = origin - m_origin;
       m_origin = origin;
       m_center += t;
       needToUpdate = true;
       inverseNeedToUpdate = true;
    }

    Vec2f getScale() {
        return m_scale;
    }
    float getRotation() {
        return m_rotation;
    }
    Vec2f getOrigin() {
        return m_origin;
    }
    void setSize (Vec2f size) {
        setScale(size / m_size);
        needToUpdate = true;
        inverseNeedToUpdate = true;
    }

    FloatRect getGlobalBounds() {
        FloatRect globalBounds = getTransform().transformRect(localBounds);
        return globalBounds;
    }
    const sf::Transform& getTransform() const {
         // Recompute the combined transform if needed
        if (needToUpdate) {

            float angle  = -m_rotation * 3.141592654f / 180.f;
            float cosine = static_cast<float>(std::cos(angle));
            float sine   = static_cast<float>(std::sin(angle));
            float sxc    = m_scale.x * cosine;
            float syc    = m_scale.y * cosine;
            float sxs    = m_scale.x * sine;
            float sys    = m_scale.y * sine;
            float tx     = -m_origin.x * sxc - m_origin.y * sys + m_center.x;
            float ty     =  m_origin.x * sxs - m_origin.y * syc + m_center.y;

            const_cast<DynamicDrawableEntity*>(this)->m_transform = sf::Transform( sxc, sys, tx,
                                      -sxs, syc, ty,
                                      0.f, 0.f, 1.f);
            const_cast<DynamicDrawableEntity*>(this)->needToUpdate = false;
        }
        return m_transform;
    }
    const sf::Transform& getInverseTransform()
    {
        // Recompute the inverse transform if needed
        if (inverseNeedToUpdate)
        {
            const_cast<DynamicDrawableEntity*>(this)->m_inverseTransform = getTransform().getInverse();
            const_cast<DynamicDrawableEntity*>(this)->inverseNeedToUpdate = false;
        }

        return m_inverseTransform;
    }
protected :
    DynamicDrawableEntity(Vec2f position, Vec2f size, Vec2f origin) {
        localBounds = FloatRect(position.x, position.y, size.x, size.y);
        m_position = position;
        m_size = size;
        m_center = Vec2f (m_position.x + origin.x, m_position.y + origin.y);
        m_origin = origin;
        m_scale = Vec2f(1.f, 1.f);
        m_rotation = 0;

        needToUpdate = true;
        inverseNeedToUpdate = true;
    }
    virtual void onRotate(float angle) {}
    virtual void onScale(Vec2f s) {}
    virtual void onMove(Vec2f t) {}
private :
    FloatRect localBounds;
    Vec2f m_position, m_size, m_center,m_scale,m_origin;
    float m_rotation;
    sf::Transform m_transform;
    sf::Transform m_inverseTransform;
    bool needToUpdate, inverseNeedToUpdate;
};
#endif // TRANSF_ENTITY
 

De cette racine je fait dérivé des noeuds qui sont toutes les entités transformable, et ces noeud peuvent ontenir des noeud enfants qui sont d'autres entités transfomable.

Bref voici par exemple la classe Tile qui est un noeud :
tile.h :
#ifndef TILE
#define TILE
#include "dynamicDrawableEntity.h"

class Tile : public DynamicDrawableEntity {
    public :
        Tile (sf::Texture &image, Vec2f position, Vec2f size, sf::IntRect subRect);
        virtual void draw (sf::RenderTarget &target, sf::RenderStates states) const;
    private :
        sf::Sprite sprite;
};
#endif
 
tile.cpp :
#include "tile.h"



using namespace sf;
using namespace std;

/*Gère les différents tiles, cette classe contient un Sprite.
*/

//Crée un tile, avec une image passée en paramètre.
Tile::Tile (sf::Texture &image, Vec2f position, Vec2f size, IntRect subRect) : DynamicDrawableEntity (position, size, size * 0.5f) {
    sprite.setTexture(image);
    sprite.setTextureRect(subRect);
    float factorX = size.x / (float) subRect.width;
    float factorY = size.y / (float) subRect.height;

    setScale(Vec2f(factorX, factorY));

}

void Tile::draw(RenderTarget &target, RenderStates states) const {
    target.draw(sprite, getTransform());
}
 

Et enfin la classe Wall qui est aussi un noeud mais qui contient un noeud enfant qui est la tile du mur :

#ifndef WALL
#define WALL
#include "tile.h"
class Wall : public DynamicDrawableEntity {
    public :
        Wall (Tile *tile) : DynamicDrawableEntity (tile->getPosition(), tile->getSize(), tile->getSize() * 0.5f)  {
            this->tile = tile;
        }
        Tile* getTile() {
            return tile;
        }


        virtual void draw (RenderTarget &target, RenderStates states) const {
            target.draw(*tile, getTransform());
        }

        virtual ~Wall () {
           delete tile;
        }
    private :
        Wall (const Wall &wall);
        Tile *tile;
};

#endif
 

Malheureusement quand je fait des transformations sur le mur, elles ne se combinent pas avec les transforations que je fais sur la tile, par exemple, lorsque je fais une rotation sur la tile elle se fait bien mais lorsque je refais une rotation sur le mur ensuite la tile reste à la même place hors qu'elle ne devrait pas. :/

Bref voici le main :
#include <SFML/Graphics.hpp>
#include "wall.h"
int main () {
     // création de la fenêtre
    sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
    sf::Texture *text = new sf::Texture();
    text->loadFromFile("murs.png");
    Tile *t = new Tile(*text, Vec2f(100, 100), Vec2f (130, 130), sf::IntRect(100, 0, 100, 100));
    t->setRotation(45);
    Wall *wall = new Wall(t);
    wall->setRotation(-45);
    // on fait tourner le programme tant que la fenêtre n'a pas été fermée
    while (window.isOpen())
    {
        // on traite tous les évènements de la fenêtre qui ont été générés depuis la dernière itération de la boucle
        sf::Event event;
        sf::View view(sf::FloatRect(0, 0, 800, 600));
        //view.move(-400, -300);
        while (window.pollEvent(event))
        {
            // fermeture de la fenêtre lorsque l'utilisateur le souhaite
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // effacement de la fenêtre en noir
        window.clear(sf::Color::Black);


        // c'est ici qu'on dessine tout
        window.setView(view);
        window.draw(*wall);
        // fin de la frame courante, affichage de tout ce qu'on a dessiné
        window.display();
    }
    delete text;
    delete wall;
    return 0;
}
 

Voila.
« Modifié: Septembre 21, 2013, 10:17:19 am par Lolilolight »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Messages: 4321
    • Voir le profil
    • E-mail
Re : Graph de scene, les transformations ne se combinent pas!
« Réponse #1 le: Septembre 21, 2013, 10:56:04 am »
Mon intention n'est pas d'être méchant, mais...

tldr.


Quand tu as un bug, tu écartes des parties du code jusqu'à ce que le bug soit clairement identifié. Applique la même stratégie pour tes messages ici: courts et concis. Sinon personne ne va prendre le temps de te lire.
SFML / OS X developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Graph de scene, les transformations ne se combinent pas!
« Réponse #2 le: Septembre 21, 2013, 11:06:30 am »
Bon j'ai trouvé, en fait il fallait remplacer ça :
target.draw(sprite, getTransform());
 
Par ça :
states.transform  = states.transform * getTransform();
target.draw(sprite, states);
 
Dans les fonctions draw des classes tile et wall.

C'est juste la fonction draw racourcie donc qui ne marchait pas.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Graph de scene, les transformations ne se combinent pas!
« Réponse #3 le: Septembre 21, 2013, 01:19:43 pm »
C'est pas la fonction qui ne marchait pas, c'est toi qui passait de mauvais paramètres.

Ensuite, il suffisait de lire la documentation, cette pratique est courante est très bien expliquée avec des exemples.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Graph de scene, les transformations ne se combinent pas!
« Réponse #4 le: Septembre 21, 2013, 03:20:12 pm »
Ha oui juste j'avais pas bien lu la doc. (Faut que l'entité passée dans draw hérite de sf::Transformable pour que les transformations soient combinées en utilisant ce prototype de la fonction draw.)
« Modifié: Septembre 21, 2013, 03:22:00 pm par Lolilolight »