Gestion d'une collection de donnée importante

Cherche des pistes sur la meilleure méthode à suivre

a marqué ce sujet comme résolu.

Bonjour à tous,

Dans le cadre d’un développement de jeu vidéo, je cherche à faire une tile map 2D aléatoire sur des grandes dimensions. J’ai partitionné ma map en différents chunks de tuiles. Du coup j’arrive à charger/générer des chunks assez rapidement et je les stockes de nouveau sur le disque dur une fois qu’ils sont trop loin de mon joueur pour en garder qu’une quantité limité en mémoire (pour l’instant 25)

Cependant le soucis vient dès que je souhaite faire des biomes. Pour cela, je détermine des centres avec un positionnement pseudo-aléatoire par rapport à une grille. Je défini un espacement par défaut entre chaque centre auquel je viens ajouter un offset aléatoire. Ces centres contiennent aussi de la donnée concernant différents paramètres (par soucis de simplicité, seulement le type de biome pour le moment)

Lorsque je génère par la suite un chunk, pour chaque tuile composant ce chunk je récupère les centres à priori les plus proches via leur positionnement de base dans le maillage et ensuite je détermine dans cet ensemble restreint le centre de biome le plus proche et j’associe à la tuile les infos de ce centre

Pour éviter de garder une grille énorme en mémoire, je pensais à la stocker dans un fichier sur le DD. Je cherche cependant une solution à la fois "facile" à utiliser et la plus rapide et efficace en mémoire (cette solution n’existe peut-être pas). Pour l’instant j’ai trouvé les deux extrêmes : créer un fichier par centre de biome ou mettre tous les biomes dans un seul fichier. Le problème que je vois avec le premier c’est juste le nombre énorme de fichier qui va se créer. Cependant, ça sera très simple à utiliser par la suite. J’aurais juste besoin de récupérer le fichier correspondant aux quelques centres de biomes dont j’ai pour le moment besoin. La deuxième me semble pas idéale non plus. Elle est probablement la plus compacte mais me semble compliqué à être utilisé car trouver un centre dans le fichier impliquerait de la parcourir entièrement (au pire du cas)

Du coup, je viens vers vous pour d’autres idées d’implémentation possible permettant soit le stockage sur DD de manière simple et optimisé ou une manière de garder ça en mémoire sans faire ramer mon jeu comme pas possible.

Vous trouverez le code de génération ci-dessous :

// CHUNK_SIZE = 16
// MAP_SIZE = 500
// MIN_DISTANCE_VORONOI_CENTER = 10
// TILE_SIZE = 32px, pour l'affichage, du coup une tile peut-être considéré comme une unité
// voronoiCenters = std::map<int,std::map<int,std::unique_ptr<BiomeCenter>>

// génération des centres
// biomeDistribution(rd) = jet aléatoire entre 1 et 4 pour un type de biome
int nbTiles = CHUNK_SIZE * MAP_SIZE;
int nbTilesOffset = (nbTiles % MIN_DISTANCE_VORONOI_CENTER) / 2;
int limit = nbTiles / (2 * MIN_DISTANCE_VORONOI_CENTER) + nbTilesOffset;

for (int i = -limit; i < limit; i++) {
    for (int j = -limit; j < limit; j++) {
        double xoffset = distribution(rd);
        double yoffset = distribution(rd);

        voronoiCenters[i][j] = std::make_unique<BiomeCenter>(
            (i)*MIN_DISTANCE_VORONOI_CENTER + nbTilesOffset + xoffset,
            (j)*MIN_DISTANCE_VORONOI_CENTER + nbTilesOffset + yoffset,
            biomeDistribution(rd));
    }
}



// Génération d'un chunk

for (int i = 0; i < CHUNK_SIZE; i++) {
    for (int j = 0; j < CHUNK_SIZE; j++) {
        double centerX = pos.x + TILE_SIZE * i;
        double centerY = pos.y + TILE_SIZE * j;
        centerX += TILE_SIZE / 2;
        centerY += TILE_SIZE / 2;
        std::vector<BiomeCenter*> centers =
            parent->getNearestPoints(centerX / TILE_SIZE, centerY / TILE_SIZE);

        BiomeCenter* nearest = centers[0];
        double minDist = dist(nearest->x * TILE_SIZE, nearest->y * TILE_SIZE, centerX, centerY);
        for (auto& c : centers) {
            double distance = dist(c->x * TILE_SIZE, c->y * TILE_SIZE, centerX, centerY);
            if (distance < minDist) {
                nearest = c;
                minDist = distance;
            }
        }
        tiles.push_back(std::make_unique<Tile>(
            glm::vec2(pos.x + TILE_SIZE * i, pos.y + TILE_SIZE * j), nearest->type));
    }
}


// getNearestPoint() :

int x = indexI / MIN_DISTANCE_VORONOI_CENTER; // coords du centre situé le plus proche en haut à gauche de la tuile
int y = indexJ / MIN_DISTANCE_VORONOI_CENTER;

std::vector<BiomeCenter*> nearestPoints;
for (int i = -1; i < 3; i++) {
    for (int j = -1; j < 3; j++) {
        if (voronoiCenters.find(x + i) != voronoiCenters.end() &&
            voronoiCenters.at(x + i).find(y + j) != voronoiCenters.at(x + i).end()) {
            nearestPoints.push_back(voronoiCenters.at(i + x).at(y + j).get());
        }
    }
}

return nearestPoints;

//BiomeCenter

struct BiomeCenter {
    double x;
    double y;
    int type;

    BiomeCenter(double mX, double mY, int mType) : x(mX), y(mY), type(mType) {}
    BiomeCenter() : x(0), y(0), type(0) {}

    friend std::istream& operator>>(std::istream& in, BiomeCenter& c) {
        in >> c.x;
        in >> c.y;
        in >> c.type;

        return in;
    }

    friend std::ostream& operator<<(std::ostream& out, BiomeCenter& c) {
        out << c.x << " ";
        out << c.y << " ";
        out << c.type << " ";

        return out;
    }
};

Merci d’avance pour votre aide, ça fait 1 semaine non stop que je me casse la tête sur ce problème X/

+0 -0

Si j’ai bien compris, tu as un certain nombre de points (les centres de biomes) qui sont créés à intervalles réguliers (+un peu d’aléatoire) et tu voudrais un moyen que permet de stocker ces points sur le disque tout en conservant un moyen efficace pour récupérer les points dans une zone donnée.

Si tu sais que la carte à une taille maximum, il est possible de diviser ta carte en zones de différentes tailles. Par exemple, une zone de niveau 0 représente la carte complète et est composé de N² zones de niveau 1, chacune composé de N² zones de niveau 2, etc… jusqu’au niveau k qui représente une chunk/tile (suivant ce qu’il te faut). Tu peux alors stocker dans ton fichier la zone 0 avec N² pointeurs vers la position dans le ficher de chaque zone de niveau 1 (si elles existes) et continuer jusqu’à arriver aux zone de niveau k.

De manière concrète, si tu veux créer une carte de 8x8 tiles avec chaque zone contenant 4 sous-zones (énumérés de gauche à droite et de haut en bas) avec le point (0, 0) en haut à gauche, voici le fichier que tu as si tu veux sauvegarder une valeur dans le point (3, 5):

0: Zone(niveau=0, haut_gauche=-1, haut_droit=1, bas_gauche=-1, bas_droit=-1)
1: Zone(niveau=1, haut_gauche=-1, haut_droit=-1, bas_gauche=2, bas_droit=-1)
2: Zone(niveau=2, haut_gauche=-1, haut_droit=-1, bas_gauche=-1, bas_droit=3)
3: Valeur(ta valeur)

Mettons que tu veuilles ajouter une valeur aux coordonné (3, 6), il te faut créer une nouvelle zone de niveau 2 en bas à gauche de ta zone de niveau 1:

0: Zone(niveau=0, haut_gauche=-1, haut_droit=1, bas_gauche=-1, bas_droit=-1)
1: Zone(niveau=1, haut_gauche=-1, haut_droit=-1, bas_gauche=2, bas_droit=4)
2: Zone(niveau=2, haut_gauche=-1, haut_droit=-1, bas_gauche=-1, bas_droit=3)
3: Valeur(ta valeur)
4: Zone(niveau=2, haut_gauche=-1, haut_droit=-1, bas_gauche=5, bas_droit=-1)
5: Valeur(nouvelle valeur)

Il est possible d’ajuster le nombre de subdivisions que chaque zone possède pour réduire la profondeur de ton arbre, ce qui permet de réduire le nombre de lecture de disque dont tu auras besoin pour récupérer une valeur, mais qui augmentera le stockage lié aux zones non-créés (tous les pointeurs -1).

Au passage, je te conseille vraiment d’estimer la quantité de mémoire/disque dont tu as besoin pour chaque élément que tu manipules. Faire ça te permettra de savoir très rapidement si une approche semble viable ou non (par exemple, est-ce que stocker tous les biomes en mémoire est possible?).

Hello,

JE n’ai pas regardé ton algorithme en détail et ne peux donc pas te conseiller là-dessus.

Par contre un conseil que je peux te donner sur l’aspect scokage, c’est d’utiliser un fichier mappé en mémoire. Le principe de base du fichier mappé en mémoire c’est que tu manipules un fichier comme de simples pointeurs en mémoire, et c’est l’OS qui choisit quand il charge/décharge les pages. Du coup tu peux manipuler une grand quantité de données en te posant moins de questions. C’est presque totalement transparent. Pour avoir déjà essayé avec des fichiers de 4 Go, ça fonctionne bien.

Avantage, pas de sérialisation/désérialisation à faire. Inconvénients, la taille du fichier doit être fixée à l’avance et donc tu dois prévoir ton système en conséquence, en ayant des chunks de taille fixe (et si possible puissances de 2 pour limiter l’espace perdu).

+0 -0

Du coup j’ai calculé la taille de ce que j’aurais besoin de stocker avec des paramètres pareils :

  • J’ai une grille de 500 * 16 / 10 = 800 de côté
  • Ma structure est composée de deux doubles et un int : 20 octets

Ce qui fait un résultat de 12,21 Go … J’ai donc préféré me tourner vers autre chose car cela me dérange de générer un fichier aussi lourd

Mais je retiens ta solution Berdes pour le quadtree enregistré dans un fichier texte, ça me reservira peut-être plus tard

J’avais déjà entendu parler du mappage d’un fichier en mémoire. C’était un peu une solution de dernier recours dans le cas où j’arrivais pas à faire autrement.

Du coup pour l’instant je vais essayer de me tourner vers un seed de random generator auquel j’ajoute la position du point que je veux créer pour faire les différents tirages. Ça sera beaucoup plus léger je pense

Merci à vous deux néanmoins pour vos réponses :)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte