TileSet : Map de tiles

Une classe TileSet vous permettant de rapidement créer votre map à partir d'images ou de cases de couleur.

Nous réutiliserons la classe 'Frame' : Frame

Le code:

TileSet.hpp

#ifndef ZIGO_TILESET
#define ZIGO_TILESET
 
#include <map>
#include "Frame.hpp"
 
class TileSet : public sf::Drawable
{
    public:
 
    // Par defaut
    TileSet(float NewTileWidth = 0, float NewTileHeight = 0);
 
    // Par copie
    TileSet(const TileSet& Cpy);
 
    // destructeur
    virtual ~TileSet();
 
    // Largeur des Tiles
    void SetTileWidth(float NewTileWidth);
 
    // Hauteur des Tiles
    void SetTileHeight(float NewTileHeight);
 
    // Largeur des Tiles
    float GetTileWidth() const;
 
    // Hauteur des Tiles
    float GetTileHeight() const;
 
    // Taille des Tiles
    void SetTileSize(float NewTileWidth, float NewTileHeight);
 
    // Taille des Tiles
    void SetTileSize(const sf::Vector2f& TileSize);
 
    // Taille des Tiles
    sf::Vector2f GetTileSize() const;
 
    // Affichage
    virtual void Render(const sf::RenderWindow& Window) const;
 
    // retoune l'abcisse tableau
    int ScreenXToTileX(float ScreenX);
 
    // retourne l'ordonnée tableau
    int ScreenYToTileY(float ScreenY);
 
    // Accès au Type de la case X, Y
    int& operator () (int X, int Y);
 
    // Accès au Type de la case X, Y : constant
    int operator () (int X, int Y) const;
 
    // retourne la Frame de type 'Key'
    const Frame& GetType(int Key);
 
    // enregistre une nouvelle Frame pour le type 'Key'
    void SetType(int Key, const Frame& NewType);
 
    // Nombre de Tiles dans la map
    size_t Size() const;
 
    // Nombre de types différents
    size_t TypeNb() const;
 
    // Plus tard, nous pourrons ajouter différentes fonctions liées au fait qu'une 'Anim' est une ressource
    // Par exemple : LoadFromFile, SaveToFile etc...
 
    private:
    float TileWidth;
    float TileHeight;
    std::map<int, std::map<int, int> > myTile;
    std::map<int, Frame> myType;
};
 
#endif

TileSet.cpp

#include "TileSet.hpp"
 
// Par defaut
TileSet::TileSet(float NewTileWidth, float NewTileHeight)
{
    TileWidth = NewTileWidth;
    TileHeight = NewTileHeight;
}
 
// Par copie
TileSet::TileSet(const TileSet& Cpy):
sf::Drawable(Cpy)
{
    TileWidth = Cpy.TileWidth;
    TileHeight = Cpy.TileHeight;
    myType = Cpy.myType;
    myTile = Cpy.myTile;
}
 
// destructeur
TileSet::~TileSet()
{
 
}
 
// Largeur des Tiles
void TileSet::SetTileWidth(float NewTileWidth)
{
    TileWidth = NewTileWidth;
}
 
// Hauteur des Tiles
void TileSet::SetTileHeight(float NewTileHeight)
{
    TileHeight = NewTileHeight;
}
 
// Largeur des Tiles
float TileSet::GetTileWidth() const
{
    return TileWidth;
}
 
// Hauteur des Tiles
float TileSet::GetTileHeight() const
{
    return TileHeight;
}
 
// Taille des Tiles
void TileSet::SetTileSize(float NewTileWidth, float NewTileHeight)
{
    TileWidth = NewTileWidth;
    TileHeight = NewTileHeight;
}
 
// Taille des Tiles
void TileSet::SetTileSize(const sf::Vector2f& TileSize)
{
    TileWidth = TileSize.x;
    TileHeight = TileSize.y;
}
 
// Taille des Tiles
sf::Vector2f TileSet::GetTileSize() const
{
    return sf::Vector2f(TileWidth, TileHeight);
}
 
// Affichage
void TileSet::Render(const sf::RenderWindow& Window) const
{
    // On parcoure le tableau
    for (std::map<int, std::map<int, int> >::const_iterator it = myTile.begin(); it != myTile.end(); ++it)
    {
        for (std::map<int, int>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2)
        {
            std::map<int, Frame>::const_iterator TypeIt = myType.find( it2->second );
 
            // Si le type de tile éxiste
            if (TypeIt != myType.end())
            {
 
            // On dessine une tile
            glMatrixMode(GL_MODELVIEW);
                glPushMatrix();
 
                    glTranslatef(it->first * TileWidth, it2->first * TileHeight, 0);
 
                    glColor4ub(TypeIt->second.Color.r, TypeIt->second.Color.g, TypeIt->second.Color.b, TypeIt->second.Color.a);
 
                // Si on doit y afficher une image
                if (TypeIt->second.Image != NULL)
                {
                    sf::Rect<float> Rect = TypeIt->second.Image->GetTexCoords(TypeIt->second.Rect);
 
                    TypeIt->second.Image->Bind();
 
                    glBegin(GL_QUADS);
                        glTexCoord2f(Rect.Left,  Rect.Top);    glVertex2f(0,     0);
                        glTexCoord2f(Rect.Left,  Rect.Bottom); glVertex2f(0,     TileHeight);
                        glTexCoord2f(Rect.Right, Rect.Bottom); glVertex2f(TileWidth, TileHeight);
                        glTexCoord2f(Rect.Right, Rect.Top);    glVertex2f(TileWidth, 0);
                    glEnd();
 
                }
                // Sinon
                else
                {
                    // Disable texturing
                    glDisable(GL_TEXTURE_2D);
 
                    // Draw the colored rectangle
                    glBegin(GL_QUADS);
                        glVertex2f(0,     0);
                        glVertex2f(0,     TileHeight);
                        glVertex2f(TileWidth, TileHeight);
                        glVertex2f(TileWidth, 0);
                    glEnd();
                }
 
                glMatrixMode(GL_MODELVIEW);
                    glPopMatrix();
            }
        }
    }
}
 
// retoune l'abscisse tableau
int TileSet::ScreenXToTileX(float ScreenX)
{
    return static_cast<int>(ScreenX/TileWidth);
}
 
// retourne l'ordonnée tableau
int TileSet::ScreenYToTileY(float ScreenY)
{
    return static_cast<int>(ScreenY/TileHeight);
}
 
// Accès au Type de la case X, Y
int& TileSet::operator () (int X, int Y)
{
    return myTile[X][Y];
}
 
// Accès au Type de la case X, Y : constant
int TileSet::operator () (int X, int Y) const
{
    std::map<int, std::map<int, int> >::const_iterator It = myTile.find( X );
 
    if (It != myTile.end())
    {
        std::map<int, int>::const_iterator It2 = It->second.find( Y );
        if (It2 != It->second.end())
            return It2->second;
        else
            return 0;
    }
    else
        return 0;
}
 
// retourne la Frame de type 'Key'
const Frame& TileSet::GetType(int Key)
{
    return myType[Key];
}
 
// Enregistre une nouvelle Frame pour le type 'Key'
void TileSet::SetType(int Key, const Frame& NewType)
{
    myType[Key] = NewType;
}
 
// Nombre de Tiles dans la map
size_t TileSet::Size() const
{
    return myTile.size();
}
 
// Nombre de types différents
size_t TileSet::TypeNb() const
{
    return myType.size();
}
 
// Plus tard, nous pourrons ajouter différentes fonctions liées au fait qu'une 'Anim' est une ressource
// Par exemple : LoadFromFile, SaveToFile etc...

Utilisation

Un TileSet est un tableau à 2 dimensions, stockant le type de tile pour une coordonnée X,Y. Avant de créer votre map, enregistrez d'abord les différents types de tiles qui devront être affichés. Pour cela rien de plus simple : myTileSet.SetType( TYPE , Frame(&myImage, mySubRect, myColor) ); Après cela, définissez vos cases une a une tout aussi simplement : myTileSet( X , Y ) = TYPE;

Exemple

On utilise cette image (désolé de la mocheté de la chose, c'est juste pour l'exemple!):

Le code:

#include "TileSet.hpp"
 
int main()
{
 
    sf::RenderWindow Window(sf::VideoMode(800, 600, 32), "Test");
 
    // On charge les texture de la map
    sf::Image MapImage;
    MapImage.LoadFromFile("map.png");
 
    // On créé un TileSet
    TileSet myTileSet;
 
    // On définit les type de Tile
    myTileSet.SetType(0, Frame(&MapImage, sf::Rect<int>(0, 0, 64, 64))); // Plaine
    myTileSet.SetType(1, Frame(&MapImage, sf::Rect<int>(0, 64,64, 128))); // Roche
    myTileSet.SetType(2, Frame(&MapImage, sf::Rect<int>(64, 64, 128, 128))); // Neige-glace
    myTileSet.SetType(3, Frame(&MapImage, sf::Rect<int>(64, 0,128, 64))); // Eau
 
    Frame TestColor;
    TestColor.Color = sf::Color::Red;
 
    // Une frame sans image mais de couleur rouge
    myTileSet.SetType(4, TestColor);
 
    // On définit la taille des Tiles
    myTileSet.SetTileSize(64, 64);
 
    // On remplit le tableau de 'plaine'
    for (int y = 0; y < 5; y++)
        for (int x = 0; x < 5; x++)
            myTileSet(x, y) = 0;
 
    // On décor la map...
 
    // Un peit lac
    myTileSet(0, 0) = 3;
    myTileSet(0, 1) = 3;
    myTileSet(1, 1) = 3;
    myTileSet(1, 0) = 3;
 
    // Un rocher
    myTileSet(1, 2) = 1;
 
    // de la neige
    myTileSet(2, 2) = 2;
    myTileSet(2, 3) = 2;
    myTileSet(3, 3) = 2;
    myTileSet(3, 2) = 2;
 
    // Une case rouge!
    myTileSet(4, 4) = 4;
 
    // La boucle habituelle
    sf::Event Event;
    bool isRunning = true;
    while (isRunning)
    {
        while (Window.GetEvent(Event))
        {
            switch(Event.Type)
            {
                case sf::Event::Closed:
                isRunning = false;
                break;
 
                case sf::Event::KeyReleased:
                switch(Event.Key.Code)
                {
                    case sf::Key::Escape:
                    isRunning = false;
                    break;
                }
 
                break;
            }
        }
 
        Window.Draw(myTileSet);
 
        Window.Display();
    }
 
    return EXIT_SUCCESS;
}

Commentaires

A l'avenir, on pourra intégrer des fonctions de lecture/écriture sur le disque pour sauvegarder la map.

Je tiens simplement à mettre en garde que ce système n'est pas optimisé. Voir mon commentaire ici.

 
fr/sources/tileset.txt · Last modified: 2008/11/24 18:20 by hiura
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki