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

Auteur Sujet: tile map probleme  (Lu 5895 fois)

0 Membres et 1 Invité sur ce sujet

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
tile map probleme
« le: Avril 21, 2016, 05:34:38 pm »
Bonjour !

Avec des amis je me suis lancé dans un petit jeu (un rts), seulement j'ai quelques soucis avec l'affichage de la tile map qui à la fâcheuse tendance à clignoter dès lors que je bouge ma souris, et le seul moyen que j'ai trouvé pour résoudre ce problème est de mettre la méthode qui affiche les tiles dans la boucle principale ce qui fait alors chuter mon framerate à 0. Par ailleurs si vous avez des conseils pour amélioree mon code je suis preneur :)
voici mon code:

MapGen.h (la classe qui gère la map):
#include <SFML/system.hpp>
#include <SFML/window.hpp>
#include <SFML/graphics.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

class MapGen
{

    public:

        MapGen(int tailleX, int tailleY);//la taille en tiles
        MapGen(int tailleX, int tailleY, bool surcharge);//le bool surcharge ne sert qu'a surchager le constructeur
        std::vector<std::vector<int> > getMap() const;//renvoie le vector 2d de la map
        bool isCrossable(int x, int y) const;//retourne true si la tile aux coords données est traversable par des unitées
        void load(sf::RenderWindow* window, int windowSizeX, int windowSizeY);//charge les tiles
        void setView(sf::RenderWindow* window);//definit la vue
        void loopView(sf::RenderWindow* window);//a mettre dans la boucle principale, permet de déplacer la vue avec la souris
        ~MapGen();

    protected:

        int const m_tailleX;
        int const m_tailleY;
        int m_viewSpeed;
        float m_tileSizeX, m_tileSizeY;
        std::vector<std::vector<int> > m_mapp;//un tableau 2d qui contient sous forme de int les tiles de la map
        sf::View m_mainView;
};


MapGen.cpp:
#include "MapGen.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
#include <fstream>
#include <SFML/system.hpp>
#include <SFML/window.hpp>
#include <SFML/graphics.hpp>


MapGen::MapGen(int tailleX, int tailleY) : m_tailleX(tailleX), m_tailleY(tailleY), m_mapp(tailleX, std::vector<int>(tailleY,0)),
m_mainView(sf::Vector2f(0,0), sf::Vector2f(1920,1080))
{
    srand(time(0));//seed (à améliorer)

    //génération aléatoire chaotique
    for(int i(0); i<m_tailleX; i++)//double boucle pour un tableau 2d
    {
       for(int j(0); j<m_tailleY; j++)
        {
            m_mapp[i][j] = rand() % 4;
            std::cout << m_mapp[i][j];
        }
        std::cout << std::endl;
    }

}

//génération de la map à partir d'un fichier (preque plus buggué)
MapGen::MapGen(int tailleX, int tailleY, bool surcharge) : m_tailleX(tailleX), m_tailleY(tailleY), m_mapp(tailleX, std::vector<int>(tailleY,0))
,m_mainView(sf::Vector2f(500,500), sf::Vector2f(700,800))
{
    std::ifstream f_customMap("");
    if(f_customMap)//si on reussi à lire le fichier
    {
        char mapTab[tailleX][tailleY];//tableau qui contiendra la map
        while(!f_customMap.eof())//lecture du fichier jusqu'a la fin
        {
            for(int i(0);i<m_tailleX;i++)
            {
               for(int j(0);j<m_tailleY;j++)
                {
                    //à lire important !!!!!!
                    //bug:
                    //la dernière valeur du tableau (en bas a gauche) ne doit pas etre écrite dans le fichier
                    //sa valeur sera donc toujours de 0
                    //sinon gros bugs sur les valeurs
                            f_customMap.get(mapTab[i][j]);
                            m_mapp[i][j] = atoi(&mapTab[i][j]);//la fonction atoi transforme le char en int
                            std::cout << m_mapp[i][j]<< " ";
                }
                std::cout << std::endl;
            }
        }
        //std::cout << *mapTab;
    }
    else
    {
        std::cout << "erreur, le fichier n'a pas pu etre lu" << std::endl;
    }

}

std::vector<std::vector<int> > MapGen::getMap() const
{
    return m_mapp;
}

bool MapGen::isCrossable(int x, int y) const
{
        if(m_mapp[x][y] == 0)
            return true;
        else
            return false;
}

void MapGen::load(sf::RenderWindow* window, int windowSizeX, int windowSizeY)//chargement des tiles
{

    std::string r_dirtTile1("C:/Users/blackbird/Dropbox/rts/Graphs/Rendu/Tile Export/TileMaps_Animation 1_00.png"), r_dirtTile2("C:/Users/blackbird/Dropbox/rts/Graphs/Rendu/Tile Export/TileMaps_Animation 1_01.png")
    , r_dirtTile3("C:/Users/blackbird/Dropbox/rts/Graphs/Rendu/Tile Export/TileMaps_Animation 1_02.png"), r_dirtTile4("C:/Users/blackbird/Dropbox/rts/Graphs/Rendu/Tile Export/TileMaps_Animation 1_03.png"),
     r_dirtTile5("C:/Users/blackbird/Dropbox/rts/Graphs/Rendu/Tile Export/TileMaps_Animation 1_04.png");

   // tileSizeX = windowSizeX/m_tailleX;//on définit la taille des tiles en fonction de celle de la fenetre
   // tileSizeY = windowSizeY/m_tailleY;//rappel: m_taille ==> taille de la map en tiles
    m_tileSizeX = m_tileSizeY = 16*4;
    //std::cout << "taille des tiles: " << tileSizeX << std::endl << tileSizeY << std::endl;
    sf::RectangleShape tile1[m_tailleX][m_tailleY];//tableau qui contient les tiles
    sf::RectangleShape rect;
    sf::Texture t_dirtTile1, t_dirtTile2, t_dirtTile3, t_dirtTile4, t_dirtTile5;
    t_dirtTile1.loadFromFile(r_dirtTile1);
    t_dirtTile2.loadFromFile(r_dirtTile2);
    t_dirtTile3.loadFromFile(r_dirtTile3);
    t_dirtTile4.loadFromFile(r_dirtTile4);
    t_dirtTile5.loadFromFile(r_dirtTile5);

    for(int i(0);i<m_tailleX;i++)
    {
        for(int j(0);j<m_tailleY;j++)
        {
                    tile1[i][j].setSize(sf::Vector2f(m_tileSizeX, m_tileSizeY));
                    tile1[i][j].setPosition(j * m_tileSizeX,i* m_tileSizeY);

                    if(m_mapp[i][j] == 0)//les couleurs seront remplacé par les textures
                    {//tile1[i][j].setFillColor(sf::Color::Yellow);
                        tile1[i][j].setTexture(&t_dirtTile1);
                        if (!t_dirtTile1.loadFromFile(r_dirtTile1))
                        {
                                std::cout << "erreur,";
                        }
                    }
                    else if(m_mapp[i][j] == 1)
                    {//tile1[i][j].setFillColor(sf::Color::Green);
                        tile1[i][j].setTexture(&t_dirtTile2);
                        if (!t_dirtTile2.loadFromFile(r_dirtTile2))
                        {
                                std::cout << "erreur,";
                        }
                    }
                    else if(m_mapp[i][j] == 2)
                    {//tile1[i][j].setFillColor(sf::Color::Blue);
                        tile1[i][j].setTexture(&t_dirtTile3);
                        if (!t_dirtTile3.loadFromFile(r_dirtTile3))
                        {
                                std::cout << "erreur,";
                        }
                    }
                    else if(m_mapp[i][j] == 3)
                    {//tile1[i][j].setFillColor(sf::Color::Red);
                        tile1[i][j].setTexture(&t_dirtTile4);
                        if (!t_dirtTile4.loadFromFile(r_dirtTile4))
                        {
                                std::cout << "erreur,";
                        }
                    }
                    else
                    {//tile1[i][j].setFillColor(sf::Color(200,50,30));
                        tile1[i][j].setTexture(&t_dirtTile5);
                        if (!t_dirtTile5.loadFromFile(r_dirtTile5))
                        {
                                std::cout << "erreur,";
                        }
                    }
                    if(tile1[i][j].getPosition().x <=  m_mainView.getCenter().x + m_mainView.getSize().x && tile1[i]   [j].getPosition().y >=  m_mainView.getCenter().y - m_mainView.getSize().y)
                {//on ne dessin que les tiles qui se trouvent dans la vue
                    window->draw(tile1[i][j]);
                }
        }

    }

}

void MapGen::setView(sf::RenderWindow* window)
{
        window->setView(m_mainView);
}

void MapGen::loopView(sf::RenderWindow* window)
{//si la souris est au bord de l'écran, on fait bouger la vue
    m_viewSpeed = 30;//vitesse de déplacement de la vue (avec le clavier seulement !!!)
    //si les coordonnées de la souris en x sont à 100 pixels près du bord de l'écran/la view on déplace la view
    if(sf::Mouse::getPosition().x + 100 >= m_mainView.getSize().x)// && m_mainView.getCenter().x <= m_tailleX*m_tileSizeX)
    {
        m_mainView.move(100,0);//on déplace la vue de 100 pixels vers la droite
        window->setView(m_mainView);//on met à jour la vue pour que les changements soient visibles
    }
    //même chose avec les coordonées en y
    if(sf::Mouse::getPosition().y + 100 >= m_mainView.getSize().y)// && m_mainView.getCenter().x <= m_tailleY*m_tailleY)
    {
        m_mainView.move(0,100);
         window->setView(m_mainView);
    }
    //toujours pareil mais pou déplacer la view dans l'autre sens
    if(sf::Mouse::getPosition().x - 100 <= 0 && m_mainView.getCenter().x >= 0)
    {
        m_mainView.move(-100,0);
         window->setView(m_mainView);
    }
    if(sf::Mouse::getPosition().y - 100 <= 0 && m_mainView.getCenter().x >= 0)
    {
        m_mainView.move(0,-100);
         window->setView(m_mainView);
    }

//------------------------
//déplacement de la vue avec le clavier

    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Z))
    {
        m_mainView.move(0,-m_viewSpeed);
        std::cout << "hello world" << std::endl;
        window->setView(m_mainView);
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
    {
        m_mainView.move(0,m_viewSpeed);
        std::cout << "hello world" << std::endl;
        window->setView(m_mainView);
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
    {
        m_mainView.move(m_viewSpeed,0);
        std::cout << "hello world" << std::endl;
        window->setView(m_mainView);
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
    {
        m_mainView.move(-m_viewSpeed,0);
        std::cout << "hello world" << std::endl;
        window->setView(m_mainView);
    }

}


MapGen::~MapGen()
{

}

et enfin le main.cpp:
#include <SFML/system.hpp>
#include <SFML/window.hpp>
#include <SFML/graphics.hpp>
#include <iostream>
#include <ctime>
#include <cstdlib>
#include "MapGen.h"
/*
    génération procédurale de la map && lecture de fichier

*/


int main()
{
   
    //tests

    MapGen terrain(85, 85);//1er probleme: si la taille donnée est trop grande, cela provoque une chute de fps
 //avec une taille plus faible 20,20 par ex, le framerate reste acceptable
    sf::RenderWindow window(sf::VideoMode(1920,1080), "hello world");
    window.setFramerateLimit(60);
    terrain.load(&window, 1920, 1080);
    terrain.setView(&window);
    while(window.isOpen())
    {

        sf::Event event;
        while (window.pollEvent(event))
        {
            // évènement "fermeture demandée" : on ferme la fenêtre
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
                window.clear();
                terrain.loopView(&window);//méthode qui permet de déplacer la vue
                terrain.load(&window, 1920, 1080);//affiche les tiles
                window.display();
        }
    }
    return 0;
}
 

ps: Je m'excuse si mon code est brouillon et illisible  :-\
« Modifié: Avril 29, 2016, 08:55:34 pm par blackbird »

Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
Re : tile map probleme
« Réponse #1 le: Avril 22, 2016, 12:25:35 am »
Ton affichage est dans ta boucle d'événements.
pour le reste j'ai pas regardé. juste ton main.cpp.

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #2 le: Avril 22, 2016, 03:40:24 pm »
Sauf erreur de ma part la seule méthode à être dans la boucle d'évenement est "loopView" qui sert au déplacement de la vue et non à l'affichage des tiles, (l'autre méthode qui était en commentaire servait effectivement à l'affichage des tiles, je la retire pour éviter d'autres confusions).

Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
Re : tile map probleme
« Réponse #3 le: Avril 22, 2016, 06:23:44 pm »
       
Citer
sf::Event event;
        while (window.pollEvent(event))
        {
            // évènement "fermeture demandée" : on ferme la fenêtre
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
             
                terrain.loopView(&window);


                window.display();

        }
    }

ce qui est en rouge n'est pas absolument pas bon. je n'ai pas regardé le coeur de ton code. mais ton soucis commence déjà par là , window.display() est l'affichage. décale l'accolade du dessous au dessus de terrain.loopview(...).

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #4 le: Avril 22, 2016, 07:34:47 pm »
Ah d'accord, je n'avais pas bien compris ce que tu voulait dire  :-X, cependant cela n'arrange pas du tout mon problème: les tiles clignotent toujours et ce même lorsque je ne bouge pas ma souris. Néanmoins merci de ta réponse :)

Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
Re : tile map probleme
« Réponse #5 le: Avril 22, 2016, 10:06:27 pm »
Il manque aussi un clear sur ta fenetre.
  • while event(){...}
  • Clear
  • Draw ( sprite , shape , etc... )
  • Display

et vire les interaction de la souris , les trucs du genre :
 if(sf::Mouse::getPosition().y + 100 >= m_mainView.getSize().y && m_mainView.getCenter().x <= m_tailleY*m_tailleY)

C'est pas très clair au premier coup d'oeil et sa pue le bug à plein nez. donc, commente les moveview un peu partout... ;)


blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #6 le: Avril 23, 2016, 03:05:42 pm »
Il manque aussi un clear sur ta fenetre.
while event(){...}
Clear
Draw ( sprite , shape , etc... )
Display


Donc je devrait plutôt écrire cela dans mon main ? En mettant la méthode qui charge les tiles dans la boucle principale ?
while(window.isOpen())
    {

        sf::Event event;
        while (window.pollEvent(event))
        {
            // évènement "fermeture demandée" : on ferme la fenêtre
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }
                window.clear();
                terrain.load(&window, 1920, 1080);
                terrain.loopView(&window);
                window.display();

    }

Et pour l'interaction avec la souris c'est un point que j'aimerais garder dans le jeu, toute cette partie là est donc à réécrire ?
Je vais ajouter des commentaires sur les views   ;)

Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
Re : tile map probleme
« Réponse #7 le: Avril 23, 2016, 03:11:00 pm »
oula, tu load sur chaque frame , c'est pas bon non plus. je t'ai dis de viré tes interactions de souris/clavier temporairement pour voir si c'est cela qui bug en plus de ton main() moisi ^^.

un programme ou jeu à généralement ce schéma :


Main() {

 // init screen , load , etc...

 while event{
 // traitement des events
 }

 update()

 clear()
 draw()
 display()
 }
 

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #8 le: Avril 23, 2016, 03:23:32 pm »
C'est à peu près sur ce schéma que j'était partit seulement avec ce code (sans le déplacement de l'écran) :
 MapGen terrain(85, 85);
    sf::RenderWindow window(sf::VideoMode(1920,1080), "hello world");
    window.setFramerateLimit(60);
    terrain.load(&window, 1920, 1080);
    terrain.setView(&window);
   
    while(window.isOpen())
    {

        sf::Event event;
        while (window.pollEvent(event))
        {
            // évènement "fermeture demandée" : on ferme la fenêtre
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }
                window.clear();
                window.display();

    }
    return 0;
}
 

 J'obtient un écran noir, c'est pour cela que j'avais viré la méthode clear, par ailleurs je ne vois pas à quoi renvoie "draw", si ce n'est pas l'affichage des textures  ???

Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
Re : tile map probleme
« Réponse #9 le: Avril 23, 2016, 04:34:15 pm »
normal que c'est noir, tu ne dessines rien  :o
tu fait des draw entre clear & display, relis les tutos, il te manques vraisemblablement des bases. ;)

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #10 le: Avril 25, 2016, 12:18:05 pm »
C'est vrai que je me suis un peu précipité sur le projet et j'ai quelque peu brûlé les étapes  ::)
Je vais aller relire les tutos de ce pas  ;D

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #11 le: Avril 29, 2016, 11:42:10 am »
Bon ,au final en reprenant mon code de départ j'ai à peu près compris d'où vient le problème, il s'agit en fait de la taille de la map, si elle est trop élevé provoque une chute de framerate,cependant je n'ai aucune idée de comment résoudre ce probleme a moins de réécrire complètement mon code (sans la certitude qu'un autre code marchera mieux).

G.

  • Hero Member
  • *****
  • Messages: 1593
    • Voir le profil
Re : tile map probleme
« Réponse #12 le: Avril 29, 2016, 12:14:15 pm »
Essaie de ne dessiner que ce qui est dans ta vue, avec une tilemap c'est très facile.
Si tu draw un truc hors écran, ça utilise quand même des ressources.

Il y a aussi la solution d'utiliser des sf::VertexArray, qui sont plus rapides à dessiner que plusieurs sprites (un seul appel à draw au lieu de plein) mais plus difficiles à prendre en main.
« Modifié: Avril 29, 2016, 12:15:49 pm par G. »

blackbird

  • Newbie
  • *
  • Messages: 8
    • Voir le profil
Re : tile map probleme
« Réponse #13 le: Avril 29, 2016, 09:02:25 pm »
salut G, alors j'ai suivi ton conseil de n'afficher que les tiles présents dans ma vue avec ce bout de code:
if(tile1[i][j].getPosition().x <=  m_mainView.getCenter().x + m_mainView.getSize().x && tile1[i][j].getPosition().y >=  m_mainView.getCenter().y - m_mainView.getSize().y)//on teste si la tile en question est dans la vue
                {
                    window->draw(tile1[i][j]);//si oui on l'affiche
                }
tu peut voir le code complet dans mon premier post, je le met à jour à chaque modification.
Cependant je ne constate aucune différences au niveau des perfs, est-ce mon code qui est mauvais ?
Tu penses que les vertex pourraient régler ce probleme ?
merci de ton aide en tous cas :)

Cpl.Bator

  • Hero Member
  • *****
  • Messages: 540
    • Voir le profil
Re : tile map probleme
« Réponse #14 le: Avril 29, 2016, 11:23:56 pm »
tu load en même temps que tu affiche ??  :o
Tu m'étonnes que sa rame , je ne parle même pas des fuites de mémoire potentielles.

void MapGen::load(sf::RenderWindow* window, int windowSizeX, int windowSizeY)//chargement des tiles

Pourquoi tu passe un pointeur en paramètre ? & pourquoi passer la fenetre SFML dans un load ?

sf::RenderTarget& target fait aussi bien l'affaire dans le cadre d'un affichage, l'avantage, tu peu passer un sf::RenderWindow en paramètre , ou une sf::RenderTexture dans le cadre d'un rendu sur texture.

j'ai l'impression qu'il te manque toutes les bases , en C/C++ , et en dev de jeu.
Tu dois chargé une seule fois tes médias , un peu comme mon pseudo code plus haut. là, tu mélanges tout. le clavier , l'affichage, le loading, bref, ton code est bordélique.

pour afficher uniquement ce que tu voit , c'est hyper simple, mais je reprendrais une citation connue : "Premature optimization is the root of all evil" , vire ton load dans ta boucle principale , fait comme mon pseudo code plus haut & je t'expliquerais comment n'affiché uniquement les tiles visible sur ta vue courante.



 

anything