Bonjour à tous !
Ceci est mon premier projet avec la SFML, et même le premier véritable projet que je programme.
Il s'agit du célèbre
Jeu de la vie de Conway, codé de façon très minimaliste (aucune optimisation particulière, un algo naïf, et une interface très minimaliste elle aussi - et donc très moche).
Je viens ici essentiellement pour réclamer des commentaires sur mon code, car même si mon programme est fonctionnel, j'ai de gros doutes sur sa qualité (lisibilité, maintenance, efficacité, facilités d'évolutions). Ainsi j’apprécierais avec grand plaisir les critiques te conseils que vous pourriez me prodiguer.
Beaucoup de ces points ce concernent pas que la SFML, mais je crois, à raison, pouvoir trouver des spécialistes du C++ ici.
Voici quelques points (en vrac) que j'aimerais voir abordés (ne répondez qu'à ceux qui vous plaisent, et n'hésitez pas à en rajouter d'autres).
1) L'existence et l'implémentation de la fonction indiceValide(indice, conteneur) vous paraît-elle appropriée ?
2) Ais-je bien fait d'utiliser un VertexArray plutôt qu'un ensemble de RectangleShape ?
3) Jusque dans quelle mesure ma classe correspond t-elle aux critères OO ? Comment l'améliorer ?
4) Ais-je eu raison de travailler dans des tableaux unidimensionnels en calculant moi même mes indices pour simuler d'autres dimensions ?
5) Comment améliorer la lisibilité de mon code (conventions de codage, etc... ) ?
6/ Séparer l'affichage, le calcul de l'étape suivante, et la mise à jour du VertexArray vous paraît-elle une bonne idée ?
7) Ais-je raison de recalculer les indices de mes Vertex à chaque mise à jour ?
8/ Ais-je raison de séparer mon constructeur et l'initialisation de la grille à partir d'un fichier ? (Au passage je précise que j'ai fait le choix pour des raison de simplicité de ne pas respecter le format LIF et de m'appuyer sur un format "à ma sauce" pour accélérer la phase de test, la prise en compte de LIF est un exercice qui viendra après).
9) La résistance aux erreurs vous paraît-elle catastrophique ou juste horrible ?
10) D'autres remarques ?
Merci d'avance pour votre aide et vos conseils !
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <SFML/Graphics.hpp>
using namespace sf;
using namespace std;
vector<Vector2i> directions = {
Vector2i(0, 1), Vector2i(1, 0),
Vector2i(0, -1), Vector2i(-1, 0),
Vector2i(1, 1), Vector2i(-1, -1),
Vector2i(1, -1), Vector2i(-1, 1)
};
template<typename Conteneur>
inline bool indiceValide(int indice, const Conteneur& conteneur)
{
return (indice >= 0 && static_cast<unsigned int>(indice) < conteneur.size());
}
class JeuDeLaVie : public Drawable, public Transformable
{
public:
JeuDeLaVie(unsigned int _hauteur, unsigned int _largeur, unsigned int _tailleCellule) :
hauteur(_hauteur), largeur(_largeur), tailleCellule(_tailleCellule), parite(true)
{
sommets.setPrimitiveType(Quads);
sommets.resize(hauteur * largeur * 4);
grille[false].resize(hauteur * largeur, false);
grille[true].resize(hauteur * largeur, false);
}
void loadFromFile(const string& fileName)
{
ifstream file(fileName.c_str());
unsigned int nbBlocs;
file >> nbBlocs;
for (unsigned int bloc = 0; bloc < nbBlocs; ++bloc)
{
unsigned int abscisse, ordonnee, nbLignes, nbColonnes;
file >> abscisse >> ordonnee >> nbLignes >> nbColonnes;
char cellule;
for (unsigned int i = 0; i < nbLignes; ++i)
for (unsigned int j = 0; j < nbColonnes; ++j)
{
unsigned int indice = abscisse + j + (ordonnee + i) * largeur;;
file >> cellule;
if (cellule == 'O')
grille[parite][indice] = true;
}
}
updateVertexArray();
}
void evolve()
{
for (unsigned int i = 0; i < hauteur; ++i)
for (unsigned int j = 0; j < largeur; ++j)
{
unsigned int indice = (j + i * largeur);
unsigned int compteur = 0;
for (auto direction : directions)
{
int adjacent = j + direction.x + (i+direction.y)*largeur;
if (indiceValide(adjacent, grille[parite]) && grille[parite][adjacent])
++compteur;
}
if (compteur == 3)
grille[!parite][indice] = true;
else if (compteur < 2 || compteur > 3)
grille[!parite][indice] = false;
else
grille[!parite][indice] = grille[parite][indice];
}
parite = !parite;
updateVertexArray();
}
virtual void draw(RenderTarget& target, RenderStates states) const
{
states.transform = getTransform();
target.draw(sommets, states);
}
private:
void updateVertexArray()
{
for (unsigned int i = 0; i < hauteur; ++i)
for(unsigned int j = 0; j < largeur; ++j)
{
unsigned int indice = (j + i * largeur);
Color couleur = grille[parite][indice] ? Color::White : Color::Black;
Vertex * quad = &sommets[indice * 4];
quad[0].position = Vector2f(j * tailleCellule, i * tailleCellule);
quad[1].position = Vector2f((j + 1) * tailleCellule, i * tailleCellule);
quad[2].position = Vector2f((j + 1) * tailleCellule, (i + 1) * tailleCellule);
quad[3].position = Vector2f(j * tailleCellule, (i + 1) * tailleCellule);
for (unsigned int point = 0; point < 4; ++point)
quad[point].color = couleur;
}
}
VertexArray sommets;
vector<bool> grille[2];
const unsigned int hauteur;
const unsigned int largeur;
const unsigned int tailleCellule;
bool parite;
};
int main()
{
RenderWindow window(VideoMode(512, 512), "Jeu de la vie");
window.setVerticalSyncEnabled(true);
JeuDeLaVie gol(64, 64, 8);
gol.loadFromFile("exemple.GOL");
Clock clock;
while (window.isOpen())
{
Event event;
while(window.pollEvent(event))
{
if ((event.type == Event::Closed)
|| (event.type == Event::KeyPressed && event.key.code == Keyboard::Escape))
window.close();
}
Time elapsed = clock.getElapsedTime();
if (elapsed >= seconds(0.25f))
{
clock.restart();
gol.evolve();
}
window.clear(Color::White);
window.draw(gol);
window.display();
}
return 0;
}