JeuWeb - Crée ton jeu par navigateur
Comment gérer une carte de 500*500 cases dans une bdd ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Comment gérer une carte de 500*500 cases dans une bdd ? (/showthread.php?tid=4625)

Pages : 1 2 3


Comment gérer une carte de 500*500 cases dans une bdd ? - PommeCassis - 07-03-2010

Bonjour, je me pose quelques questions pour la conception de mon jeu. Dans celui-ci chaque case devra contenir des informations diverses sur le terrain, qui influenceront directement les personnages des joueurs. Ces données seront de plus amenés a changer souvent.

Par exemple pour illustrer, certains classes/races pourront maudire la terre. Un personnage non mort-vivant ou n’ayant pas une compétence adéquate sur ce type de case, subira un malus de force en fonction du degré de « malédiction » du terrain. Le terrain peut aussi contenir d’autres choses, des bâtiments construits par les joueurs, des obstacles diverses, etc… (je sais je suis dingue :hahaSmile

Sachant que ces compétences pour altérer le terrain seront très fréquentes puisque faisant partie de la base du gameplay, la bdd sera surement fortement sollicité. Je vois pas trop comment concevoir une telle base de données qui soit de plus optimisée.

Une structure comme celle-ci pourrait elle convenir ? Ou trop gourmande en ressource ?

`id` INT NOT NULL AUTO_INCREMENT ,
`x INT NOT NULL,
`y` INT NOT NULL,
`occupation_id` INT NOT NULL ,
`etat_id` INT NOT NULL ,
`effet_id` INT NOT NULL ,

Une autre question, a votre avis quel framework en php je devrai utiliser pour ça ?

Ps: je précise que le SQL c’est pas spécialement mon truc, mais je fais ca surtout pour m’améliorer, alors n’hésitez pas à me signaler si des choses semblent bizarres dans ce que je raconte.

Merci d’avance


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - Sephi-Chan - 07-03-2010

Pour commencer, un petit conseil : n'appelle pas ta table "cases" ou "case", c'est un mot clé réservé (comme "force") par MySQL et ça te posera des problèmes (y compris dans le nommage de tes variables/classes). Je te conseille plutôt le terme "tuile" (en anglais tile, tiles au pluriel), habituel dans les jeux de plateau.

Le défaut de ton approche, c'est qu'on peut n'avoir qu'un effet et qu'un état par case.

Admettons le cas suivant :
  • Le joueur mort-vivant maudit un lopin de terre ;
  • Un elfe de la nuit voit ça et — choqué — décide d'entamer une prière à la déesse de la lune pour y déverser la lumière ;
  • Un élémentaire de glace apparaît, éclate l'elfe et le mort-vivant puis gèle le sol ;

Comment fais-tu ? Le sol a 3 états qui auront probablement tous une durée différente.

Il vaut mieux mettre en place une relation N, N avec une table pour les états (states), une table pour les tuiles (tiles) et une table de relation states_tiles qui dispose des colonnes :
  • state_id, qui fait référence à l'un des états de la table states ;
  • tile_id, qui fait référence à l'une de tes 250000 tuiles Wink

En bonus, tu peux mettre des colonnes annexes, telles que :
  • La date à laquelle l'état a été posé ;
  • La durée de l'état (en nombre de tours ou bien en minutes, selon le type de jeu) ;
  • L'identifiant du joueur qui a causé cet état ;
  • La "puissance" de l'état. Pour reprendre ton exemple, un terrain maudit avec une puissance de 10 est tellement maudit qu'on peut y invoquer un démon sans pénalité !

Voilà, voilà !


Sephi-Chan


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - Zamentur - 07-03-2010

Concernant la question sur les performance:
Ce sera pas trop gourmand si tu mets les index sur x et y, c'est ce que j'avais fait pour Ragol et çà avait accéléré les pages d'1/4 du temps (et je parle pas du gain de temps sur la génération du gps: passage de 8s à 2s).

Bon j'ai 400km à faire donc je vais laisser les autres répondre et je repasserais


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - Aleskweb - 07-03-2010

Hum si tu veut gerer tout a la fois, l'explode est pour toi.
Bon c'est un peu fait maison mais par exemple tu peu gerer autant d'état que tu veu. Voici comment s'organise le champ, appellons le "etat"

idetat1/durée1 ! idetat2/durée2 ! idetat3/durée3 tu peu aller jusqua autant d'etat que tu veu gerer simultanément
(j'ai mis des espaces entre chaque "!" pour la lisibilité, il te faudras les enlever)
ensuite je t'explique en gros le fonctionnement de explode
$requette = faire la requette du champ etat
$etat=explode("!";$requette);

donc a ce moment la $etat devient un array
donc:
$etat[0] équivaudras a "idetat1/durée1";
$etat[1] équivaudras a "idetat2/durée2"
etc...

Tu fais ensuite de meme pour dissocier l'etat et la durée :
$currentetat= explode("/";$etat[0]);
Donc $currentetat[0] sera egal a idetat1 et $currentetat[0] a duree1


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - PommeCassis - 07-03-2010

Merci beaucoup tout le monde

(07-03-2010, 06:02 PM)Sephi-Chan a écrit : Pour commencer, un petit conseil : n'appelle pas ta table "cases" ou "case", c'est un mot clé réservé (comme "force") par MySQL et ça te posera des problèmes (y compris dans le nommage de tes variables/classes). Je te conseille plutôt le terme "tuile" (en anglais tile, tiles au pluriel), habituel dans les jeux de plateau.
Merci pour cette précision, je ne savais pas et justement dans ma bdd fait sous workbench j’avais mis « cases ». :$

(07-03-2010, 06:02 PM)Sephi-Chan a écrit : Le défaut de ton approche, c'est qu'on peut n'avoir qu'un effet et qu'un état par case.

Admettons le cas suivant :
  • Le joueur mort-vivant maudit un lopin de terre ;
  • Un elfe de la nuit voit ça et — choqué — décide d'entamer une prière à la déesse de la lune pour y déverser la lumière ;
  • Un élémentaire de glace apparaît, éclate l'elfe et le mort-vivant puis gèle le sol ;

Comment fais-tu ? Le sol a 3 états qui auront probablement tous une durée différente.

Il vaut mieux mettre en place une relation N, N avec une table pour les états (states), une table pour les tuiles (tiles) et une table de relation states_tiles qui dispose des colonnes :
  • state_id, qui fait référence à l'un des états de la table states ;
  • tile_id, qui fait référence à l'une de tes 250000 tuiles Wink
Euh oui effectivement ces relations sont quasiment obligatoires ici mais je sais pas pourquoi dans mon esprit j’étais déjà parti dans un truc loufoque, comme à mon habitude. Enfin bref je vais opter pour cette solution.
En tout cas ton exemple correspond bien à ce que j'ai envie de faire :haha:

(07-03-2010, 08:27 PM)Zamentur a écrit : Concernant la question sur les performance:
Ce sera pas trop gourmand si tu mets les index sur x et y, c'est ce que j'avais fait pour Ragol et çà avait accéléré les pages d'1/4 du temps (et je parle pas du gain de temps sur la génération du gps: passage de 8s à 2s).
Ça me parait indispensable, un gain d'1/4 c'est énorme. Cela est il bien supporté par des frameworks ? (depuis que j'ai gouté aux framework je peux plus m'en passer)

@ Aleskweb > Cela semble moins gourmand en ressource mais je ne pourrai pas gérer autant d’effet que je le souhaite avec cette solution. Certains états seront très courants et pourraient bénéficier de cette technique mais je vais pas rajouter une table intermédiaire ou ajouter des tas de colonnes juste pour les effets plus rares. Ça serait pas très propre je pense.

Encore merci pour toutes vos réponses, j'y vois déjà plus clair maintenant


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - Sephi-Chan - 07-03-2010

Si tu n'as pas besoin de faire des recherches sur les critères de tes états, tu peux aussi stocker un tableau sérialisé (je te conseille JSON puisque natif dans PHP) d'objets State (gros avantage de la POO). Pour ça, tu auras simplement une colonne states de type text dans ta table tiles.

Et c'est propre, au moins (la sérialisation à la main, c'est pourri). Aleskweb, si tu en utilises de telles pratiques dans tes projets, je te conseiller de passer la sérialisation JSON. Smile


Sephi-Chan


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - QuentinC - 07-03-2010

Petite remarque à propos de la sérialisation JSON : si on sérialise un objet, son type n'est pas conservé... donc il faut faire attention.


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - Bananutz - 08-03-2010

Sinon pour optimiser un poil:

Int
SMALLINT (max 1xxxxx)
TINYINT (max 127)

Ta base gagnera un poil sur la recherche d'un champ.


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - Sephi-Chan - 08-03-2010

Le choix des types de colonnes, c'est surtout du bon sens. D'autant que je ne crois pas que ça influe sur les performances. Smile

(07-03-2010, 11:37 PM)QuentinC a écrit : Petite remarque à propos de la sérialisation JSON : si on sérialise un objet, son type n'est pas conservé... donc il faut faire attention.

Rho… C'te langage de péon ! Plus sérieusement, il faut alors utiliser serialize() et unserialize().

La seule subtilité dont je me souviens, c'est qu'il faut que la définition de classe ai été définie avant. C'est assez évident, en fait. Par contre, je ne sais pas si l'autoload fonctionne bien (quel aberration d'avoir à se poser la question…), les user notes ne vont pas dans le même sens.


<?php

class Person {
protected $name;

function __construct($name){
$this->name = $name;
}

public function getName(){
return $this->name;
}
}

$romain = new Person('Romain');
var_dump($romain);

$serialized_romain = serialize($romain);

$romain_bis = unserialize($serialized_romain);
var_dump($romain_bis);

Affiche :


object(Person)#1 (1) {
["name:protected"]=>
string(6) "Romain"
}
object(Person)#2 (1) {
["name:protected"]=>
string(6) "Romain"
}

Brrr quelle verbosité ! J'retourne à Ruby, moi. :p


Sephi-Chan


RE: Comment gérer une carte de 500*500 cases dans une bdd ? - barst - 08-03-2010

J'ai déjà rencontré le problème d'une map trop grande et j'avais opté pour une solution de stockage mixe :
- en fichier
- en base

J'étais parti du principe que la typologie de ma map ne changera pas souvent => ce qui est de l'eau devrait normalement resté de l'eau, et ce qui est du sable et de la terre également
Donc la typologie entière de ma map était stockée dans des fichiers

Ensuite, je ne stockais en base que ce qu'il y avait de particulier pour une case => un sort transformant le sol temporairement, ou un objet posé à cet endroit.

Avec ce type de stockage mixe, la taille de ma base de donnée a fortement baissé et les temps d'exécution ont été nettement améliorés.

Pour le stockage sous forme de fichier, une notation JSON d'un tableau à double entrée [X][Y]=[type de sol] est très pratique et rapide à charger.
Au lieu de tout tocker dans un seul fichier, je découpais la maop entière en zone, et j'avais une zone par fichier.