Comment stocker et afficher efficacement une carte de tuiles sur le Web?

9

À propos de

Ce sont en fait deux questions en une. Tout d'abord, je cherche un moyen de stocker efficacement de grandes quantités de données de tuiles. L'autre aspect concerne l'interrogation de l'ensemble de données et l'affichage des vignettes. Permettez-moi de vous donner quelques informations en premier.

Nous créons un jeu de magnat multijoueur basé sur un navigateur utilisant la bibliothèque CraftyJS pour le rendre sur Canvas. En arrière-plan de l'interface graphique, nous exécutons Yii Framework sur PHP et tout cela se connecte à un générateur de carte aléatoire Python et à un moteur de jeu.

Voici à quoi ressemble le premier rendu de carte approximatif: http://i.imgur.com/khAXtl.png

Stockage des données cartographiques

Le monde du jeu est généré aléatoirement à chaque démarrage du jeu. La taille est de 100x100 tuiles hexagonales pour chaque joueur. Cela signifie que pour une partie à trois joueurs, 90 000 tuiles sont créées. Actuellement, je viens de créer un tableau JavaScript à partir duquel je rends la carte.

Cela fonctionne bien pour le rendu, mais pour tout type d'interaction avec la carte, nous devons stocker quel joueur possède la tuile, quel type de structure est construit par-dessus, quel est son prix actuel, etc. Au début, au moins pour le prototype, nous voulions utiliser MySQL, mais après quelques tests, ce n'est pas exactement aussi rapide que je le souhaiterais. Peut-être qu'un magasin d'objets comme MongoDB serait mieux adapté pour stocker des données de tuiles au lieu d'une table SQL. Ou peut-être autre chose?

Affichage de la carte

Un autre problème que je vois se déplace sur la carte. Actuellement, je crée des entités Crafty pour chaque tuile même si elle n'est pas dans la fenêtre. Ceci est lent, car même si Crafty ne rend que ceux de la fenêtre, il stocke et peut-être itère toutes les tuiles de chaque événement de rendu. Ce que j'ai actuellement est une carte générée dessinée qui est très lente à charger et bégaie lorsque vous vous déplacez, maintenant j'aimerais la rendre jouable.

Ma première idée a été de charger le sous-ensemble de tuiles affiché dans la fenêtre. Mais lorsqu'un joueur déplace la fenêtre dans une zone vide, je dois interroger le serveur et attendre la réponse, ce n'est qu'alors que la carte peut être rendue. Ce serait bien dans une application native, mais c'est lent dans un jeu Web.

Le moyen d'obtenir des performances fluides à partir de la carte pourrait être de précharger un sous-ensemble plus important de tuiles dans un tableau javascript et de l'utiliser comme cache. Le joueur aurait quelques écrans "mis en cache" et quand il déplacerait la fenêtre, je chargerais plus de tuiles dans le "cache" JS.

Suis-je dirigé dans la bonne direction? J'aimerais obtenir plus d'informations de la part de quelqu'un qui a fait quelque chose de similaire. Je suis nouveau dans le développement de jeux, mais j'ai parcouru de nombreuses sources au cours des dernières semaines.

élément
la source
1
Je suis surpris que vous ayez identifié MySQL comme un goulot d'étranglement. Qu'avez-vous testé pour arriver à la conclusion que cela ralentit les choses?
bummzack
@bummzack S'il a une rangée par tuile, je peux à peine voir comment les choses ne peuvent pas être lentes.
aaaaaaaaaaaa
1
@eBusiness L'interrogation de quelques milliers de lignes à partir d'une base de données ne devrait pas vraiment poser problème. Cela devrait toujours être de l'ordre de quelques millisecondes. Ce ne serait pas non plus 90'000 lignes, mais plutôt 30'000 lignes pour 3 joueurs (100x100 par joueur).
bummzack
Désolé pour les maths déroutants, il y a aussi deux fois l'espace entre les joueurs en plus de la zone des joueurs afin qu'ils soient à égale distance les uns des autres, ce qui fait 90k. L'interrogation n'est pas un problème. La sélection de 90k tuiles et la construction d'une carte est. Mais ce n'est pas un bon moyen de le faire. Je sérialiserai les données de la carte et utiliserai la recherche des tuiles dans la base de données lorsque des informations détaillées seront demandées.
élément

Réponses:

2

Gameplay
Tout d'abord, je voudrais vous demander, avez-vous réellement besoin de 10000 tuiles par joueur? Bien que je ne sache pas quel type de jeu vous créez, il est généralement vrai que les grandes cartes font de longs jeux. La plus grande carte de Civilization 5 est 10240 tuiles, et cela ne fonctionne que parce que vous n'avez pas besoin de jouer sur plus d'une fraction de celle-ci.

Base de données
Vous ne devez pas essayer d'exécuter un jeu comme celui-ci à partir d'une base de données, vous devez conserver les données dans la mémoire de l'application. Vous pouvez utiliser une base de données pour sauvegarder le jeu. Pour une sauvegarde complète, enregistrez une sérialisation des données du jeu, puis vous pouvez l'incrémenter en enregistrant les commandes données, puis réexécutez-les si la sauvegarde doit être utilisée.

Stockage JavaScript
En ce qui concerne le client, je dirais que vous feriez mieux de garder la carte entière chargée, au moins si vous vous en tenez aux gazillions, tout avoir dans une belle arborescence d'objets pourrait être un peu trop, donc vous devriez probablement garder les données dans un format codé "semi-binaire". Les chaînes fonctionnent parfaitement pour ce genre de choses, alternativement, vous pouvez stocker en toute sécurité des entiers non signés jusqu'à 53 bits dans un flottant de 64 bits, beaucoup de ceux dans un tableau et je pense que vous verrez une empreinte mémoire assez modeste.

Visualisation JavaScript
Bien que je ne dise pas que vous ne devez pas nécessairement utiliser le canevas, vous n'en avez en fait pas besoin pour des choses comme celle-ci. Définissez le tout comme un groupe d'éléments img et modifiez la propriété src pour afficher différentes parties de la carte.


Conseil de pro Au fait, il est parfois plus facile de partager la graine utilisée pour la générer que de partager la carte entière.

aaaaaaaaaaaa
la source
+1, mais malheureusement, une application Web écrite en PHP n'a généralement aucun moyen de conserver l'état du jeu en mémoire.
bummzack
@bummzack, Ahh, à droite, je pense que j'ai en quelque sorte ignoré le mot PHP et simplement lu Python. Un changement de framework backend pourrait alors être nécessaire. Node.js pourrait être une option.
aaaaaaaaaaaa
Je construis un magnat du transport compétitif, pensez à OpenTTD, une carte de la taille de 512x512 (262k) n'est pas si grande pour deux joueurs. Je me rends compte que c'est ambitieux, mais si la carte n'est pas si grande, le jeu se terminerait trop tôt. Parce que c'est un jeu multijoueur, je dois synchroniser les modifications de la carte entre les joueurs. Mon premier réflexe a été de simplement utiliser les concepts que je connais en développement web et d'aller avec une base de données. Il n'a pas besoin d'être super en temps réel. Je vais avec la visualisation JS, car j'aimerais avoir des éléments dynamiques sur la carte.
élément
Considérez ma réponse comme quelques conseils, à la fin, vous devrez déterminer vous-même les performances, c'est un problème grave et vous devrez peut-être faire des compromis.
aaaaaaaaaaaa
Je suis d'accord, votre réponse m'a donné matière à réflexion. Je vais essayer de trouver un moyen de conserver les données cartographiques sérialisées en mémoire et de conserver la base de données en tant que sauvegarde. Mais ensuite, je dois comprendre comment partager les changements entre les joueurs. Je reviendrai avec ce que je trouverai après avoir fait d'autres tests.
élément
1

MySQL n'est pas lent. Vous effectuez probablement des requêtes naïves ou avez des index sous-optimaux. Les approches NoSQL comme MongoDB peuvent être plus rapides, peut-être pas. Votre modèle d'accès et votre choix de requête sont ce qui compte vraiment ici. Il est possible de donner des conseils sur la façon d'améliorer les performances, mais pas sans voir ce que vous faites déjà.

Le moyen d'obtenir des performances fluides à partir de la carte pourrait être de précharger un plus grand sous-ensemble de tuiles dans un tableau javascript et de l'utiliser comme cache.

Oui bien sûr. Il n'y a pas grand-chose à ajouter ici - le client demande des tuiles au serveur, il vous suffit donc de vous assurer que celles que vous demandez couvrent une zone plus grande que l'écran.

Addenda:

nous exécutons Yii Framework sur PHP et tout cela se connecte à un générateur de carte aléatoire Python et à un moteur de jeu.

Si vous êtes compétent avec Python, je vous conseillerais d'abandonner l'intermédiaire PHP. Si vous exécutez votre jeu en tant que processus Python, vous pouvez conserver vos données de tuiles en mémoire beaucoup plus facilement et réduire considérablement les accès MySQL. Il est également utile que Python soit un langage beaucoup plus sain que PHP.

Kylotan
la source