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

Auteur Sujet: [Résolu] Scrolling, view et tremblements  (Lu 2989 fois)

0 Membres et 1 Invité sur ce sujet

whityranger

  • Newbie
  • *
  • Messages: 9
    • Voir le profil
[Résolu] Scrolling, view et tremblements
« le: Janvier 27, 2014, 02:50:06 pm »
Bonjour à tous,

Je viens vous demander de l'aide car j'ai manifestement un problème d'affichage pour un sidescroller plateforme en 2D.
J'ai écrit une classe TileMap (très fortement) inspirée de celle présentée dans le tuto sur les vertexArray, afin d'alléger le dessin de la map au maximum. Le "monde 2D" dans lequel on pense le jeu a pour résolution naturelle de la fenêtre 512*384, et je gère le scrolling (et le redimensionnement si on change la résolution) à l'aide d'une vue, bref il me semble avoir appliqué les bons conseils des tutos.
Pour autant, lorsqu'on se déplace sur la map et que le scrolling joue, certains tiles s'affichent en tremblotant, ce qui est assez désagréable. J'ai testé cela sous 2 PC ubuntu et un windows 7, le problème y est toujours.
Donc je me demande ce que je fais de travers... je joins un petit code minimal reproduisant l'effet.

#include <iostream>
#include <SFML/Graphics.hpp>

using namespace std;
using namespace sf;

class TileMap : public Drawable, public Transformable {

private :  
  Vector2u mSize;              /**< Taille de la map en nombre de tiles */  
  sf::VertexArray mVertices;   /**< sf::VertexArray servant à définir un draw optimal */
  sf::Texture *mTileset;       /**< Pointeur vers la texture contenant le Tileset */

public :

  /** @brief Constructeur par défaut, ne fait presque rien : l'initialisation
   *         est faite lors de l'appel à load(MapName). */

  TileMap() : mTileset(nullptr) {}

  /** @brief Accesseur pour la taiille de la map. */
  inline Vector2u getSize() const { return mSize; }

  /** @brief Fonction pour charger la Map. Hardcodé pour l'exemple.
   *  @param text : Pointeur vers la texture associée. */

  void load(sf::Texture *text) {
    mTileset = text;
    // Hardcodé pour l'exemple
    std::vector< sf::Vector2f > textureCoordsTiles =
      { Vector2f(0,0),   Vector2f(0,16),  Vector2f(16,16), Vector2f(0,32),
        Vector2f(16,32), Vector2f(32,16), Vector2f(16,0),  Vector2f(0,48),
        Vector2f(16,48), Vector2f(32,32), Vector2f(32,48)  };
    uint tSize = 16;
    mSize = Vector2u(62,31);
    // On prépare mVertices
    mVertices.setPrimitiveType(sf::Quads);
    mVertices.resize(mSize.x * mSize.y * 4);
    vector< vector < int > > map;
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,5,5,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,5,5,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,5,5,5,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,6 });
    map.push_back({ 6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,6 });
    map.push_back({ 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1 });
    map.push_back({ 4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3 });
    map.push_back({ 5,5,5,5,8,5,5,5,5,7,7,5,5,5,5,5,5,7,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8,5,5,5,5,7,7,5,5,5,5,5,5,7,5,5,5,5,5,5,5,5,5,5,5,5,5,5 });
    map.push_back({ 5,5,5,5,5,5,5,5,5,5,5,8,5,7,5,5,8,5,5,5,5,5,5,7,5,5,5,7,5,5,8,5,5,5,5,5,5,5,5,5,5,8,5,7,5,5,8,5,5,5,5,5,5,7,5,5,5,7,5,5,8,5 });
    map.push_back({ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9 });
    map.push_back({ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 });
    for( int j=0 ; j<mSize.y ; ++j) {
      for( int i=0 ; i<mSize.x ; ++i ) {
        int label = map[j][i]; 
        // on choisit un quad
        sf::Vertex *quad = & mVertices[(i+j*mSize.x)*4];       
        // on définit ses quatre coins
        quad[0].position = sf::Vector2f(i * tSize, j * tSize);
        quad[1].position = sf::Vector2f((i + 1) * tSize, j * tSize);
        quad[2].position = sf::Vector2f((i + 1) * tSize, (j + 1) * tSize);
        quad[3].position = sf::Vector2f(i * tSize, (j + 1) * tSize);   
        // on définit ses quatre coordonnées de texture
        quad[0].texCoords = textureCoordsTiles[label];
        quad[1].texCoords = textureCoordsTiles[label] + sf::Vector2f(tSize,0);
        quad[2].texCoords = textureCoordsTiles[label] + sf::Vector2f(tSize,tSize);
        quad[3].texCoords = textureCoordsTiles[label] + sf::Vector2f(0,tSize);
      }
    }
  }

  /** @brief Doit être implémentée car héritage de sf::Drawable. */
  void draw(sf::RenderTarget& target, sf::RenderStates states) const {
    states.transform *= getTransform();
    states.texture = mTileset;
    target.draw(mVertices, states);
  }

};


int main() {

  int tileSize=16, windowBaseWidth=512, windowBaseHeight=384;
  int nonScrollWidth = 128, nonScrollHeight = 64;
  RenderWindow window(VideoMode(windowBaseWidth,windowBaseHeight), "Test", Style::Titlebar|Style::Close);  
  // Options
  window.setFramerateLimit(60);
  window.setVerticalSyncEnabled(false);
  window.setMouseCursorVisible(false);
  window.setKeyRepeatEnabled(false);

  TileMap map;
  Texture text;
  text.loadFromFile("tileset.png");
  map.load(&text);

  RectangleShape rect(Vector2f(3*tileSize,3*tileSize));
  rect.setFillColor(sf::Color::Green);
  rect.setOrigin(50,50);
  rect.setPosition(400,200);

  while (window.isOpen()) {
    Event event;
    Keyboard kbd;
    while (window.pollEvent(event)) {
      if (event.type == Event::Closed)
        window.close();
    }
    if ( kbd.isKeyPressed(Keyboard::Key::Up) )         rect.move(0,-10);
    else if ( kbd.isKeyPressed(Keyboard::Key::Down) )  rect.move(0,10);
    else if ( kbd.isKeyPressed(Keyboard::Key::Left) )  rect.move(-10,0);
    else if ( kbd.isKeyPressed(Keyboard::Key::Right) ) rect.move(10,0);
 
    window.clear();
    window.draw(map);
    window.draw(rect);
    // gestion du scrolling avec une vue
    View view= window.getView();  
    Vector2f scroll, pos=rect.getPosition();
    if ( pos.x - view.getCenter().x - nonScrollWidth > 0 )
      scroll.x = pos.x - view.getCenter().x - nonScrollWidth ;
    else if ( pos.x - view.getCenter().x + nonScrollWidth < 0 )
      scroll.x = pos.x - view.getCenter().x + nonScrollWidth;
    if ( pos.y - view.getCenter().y - nonScrollHeight > 0 )
      scroll.y = pos.y - view.getCenter().y - nonScrollHeight;
    else if ( pos.y - view.getCenter().y + nonScrollHeight < 0 )
      scroll.y = pos.y - view.getCenter().y + nonScrollHeight;
    view.move(scroll);
    // bords de la map
    float minX = windowBaseWidth/2,
      maxX = map.getSize().x*tileSize - windowBaseWidth/2,
      minY = windowBaseHeight/2,
      maxY = map.getSize().y*tileSize - windowBaseHeight/2;
    if      ( view.getCenter().x < minX ) view.setCenter(minX,view.getCenter().y);
    else if ( view.getCenter().x > maxX ) view.setCenter(maxX,view.getCenter().y);
    if      ( view.getCenter().y < minY ) view.setCenter(view.getCenter().x,minY);
    else if ( view.getCenter().y > maxY ) view.setCenter(view.getCenter().x,maxY);
   
    window.setView(view);
    window.display();
  }
  return 0;
}
 

Quelqu'un aurait-il une idée de ce qui ne va pas ici ?

Merci d'avance
« Modifié: Mai 09, 2014, 11:47:04 am par whityranger »

Arneast

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
    • E-mail
Re : Scrolling, view et tremblements
« Réponse #1 le: Janvier 27, 2014, 06:29:34 pm »
Salut !
Cela ne me surprendrai pas que les types de tes variables soient la source du tremblotement.
Je vois pas mal d'entier et de float s’emmêler... ça peut cacher des sales coups.
Je dis juste ça au feeling, ton code est suffisamment gros pour me faire fuir immédiatement. :D

whityranger

  • Newbie
  • *
  • Messages: 9
    • Voir le profil
Re : Scrolling, view et tremblements
« Réponse #2 le: Janvier 28, 2014, 09:51:26 am »
Salut,

Le coup des types de valeur, je vois mal comment ça peut poser problème, puisque je convertis des int en float et pas l'inverse. Si la classe View fonctionnait avec des int, ça simplifierait la question, mais c'est même pas si logique.

Pour aider à comprendre, j'ai fait une capture écran qui montre assez bien le problème :
- tout en haut de la map, une ligne entière de tiles est décalée sur la droite par rapport au reste
- au-dessus de la tête des squelettes, re-décalage d'une rangée de la map sur la droite
- le squelette de gauche, ben... c'est assez visible en fait :) là où c'est fort, c'est que sa hitbox l'a suivi
À savoir que je fais ici 5 appels à window.draw : un pour la Map (définie par un tableau de Vertex donc), un pour chaque squelette, un pour chacune des hitbox.

Quant au fait que le code minimaliste soit trop long ben... je peux difficilement faire plus court, sauf en générant une map aléatoire/régulière. Là y a quand même 32 lignes dans TileMap::load qui ne servent qu'à hardcoder la map, si on les saute parce qu'elles sont pas très intéressantes, le code est plus si long...

Voilà, j'espère que quelqu'un qui connaît un peu les entrailles de SFML aura une idée de ce qui se passe...

Merci d'avance

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Scrolling, view et tremblements
« Réponse #3 le: Janvier 28, 2014, 10:01:43 am »
Plusieurs remarques vite fait :

- Pourquoi mettre en place la vue après avoir dessiné la map ? (tu auras toujours une trame de décalage)
- Essaye d'activer la synchronisation verticale plutôt que d'utiliser une limite de framerate arbitraire
- Le fait d'instancier sf::Keyboard c'est pas terrible ;)
Laurent Gomila - SFML developer

whityranger

  • Newbie
  • *
  • Messages: 9
    • Voir le profil
Re : Scrolling, view et tremblements
« Réponse #4 le: Janvier 28, 2014, 11:29:57 am »
Merci pour la réponse,

- mettre la vue en place avant le dessin de la map (et même avant le clear) ne règle malheureusement pas le problème
- J'ai essayé avec la vsync : ça semble régler le problème pour le code minimaliste (mais pas le vrai code) et uniquement en fullscreen, autrement dit ça ne change pas grand-chose
- Euh oui, dans le vrai code je ne l'instancie pas, je sais pas pourquoi j'ai fait ça ici...  :-\

Bref, j'ai du mal à savoir d'où pourrait venir le problème...

whityranger

  • Newbie
  • *
  • Messages: 9
    • Voir le profil
Re : Scrolling, view et tremblements
« Réponse #5 le: Mai 02, 2014, 03:35:31 pm »
Bonjour à tous,

Je reviens après une longue absence pour mettre le sujet en résolu, et dire de quoi il s'agissait.
Donc au final, comme je m'y attendais le problème ne venait pas de mon code. En revanche, j'ai beaucoup creusé (sans succès) du côté des pilotes graphiques, et ce n'est pas là non plus le problème. En fait, le compositeur graphique de xubuntu gère mal la vsync de façon naturelle (peut-être que ça vaudrait le coup de mettre une note à ce propos dans la doc, à Laurent de décider), c'est donc pas lié à SFML. On peut facilement régler ça en utilisant un compositeur de fenêtres autre, comme compiz, ou compton (plus léger). Je mets un lien vers un tuto expliquant le problème et comment paramétrer compton pour le régler : http://forum.ubuntu-fr.org/viewtopic.php?pid=16657191
À noter que le problème n'existe ni sous ubuntu, ni sous kubuntu.
Et pour le fait que ça ne marchait pas sous windows, en fait le pote qui avait fait le test pour moi avait mal compris e problème et en fait, ça marchait très bien sous windows... désolé pour ce quiproquo.

Voilà, j'espère que la résolution du topic pourra en aider d'autres, sur le forum anglophone un autre mec avait eu le problème je crois (mais pas la solution).

PS : désolé, je trouve pas l'option pour passer le thread en résolu...
« Modifié: Mai 02, 2014, 03:37:54 pm par whityranger »