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.