Question
Lorsque vous avez un jeu 2D qui utilise de très grandes images (plus grandes que ce que votre matériel peut supporter), que faites-vous? Peut-être y a-t-il une solution intéressante à ce problème qui ne m'est jamais venue à l'esprit auparavant.
Je travaille essentiellement sur une sorte de créateur de jeux d'aventure graphique. Mon public cible est constitué de personnes ayant peu ou pas d'expérience en développement (et programmation) de jeux. Si vous travailliez avec une telle application, ne préféreriez-vous pas qu'elle gère le problème en interne plutôt que de vous dire de "partager vos images"?
Le contexte
Il est bien connu que les cartes graphiques imposent un ensemble de restrictions sur la taille des textures qu'elles peuvent utiliser. Par exemple, lorsque vous travaillez avec XNA, vous êtes limité à une taille de texture maximale de 2048 ou 4096 pixels selon le profil que vous choisissez.
Habituellement, cela ne pose pas beaucoup de problèmes dans les jeux 2D car la plupart d'entre eux ont des niveaux qui peuvent être construits à partir de petites pièces individuelles (par exemple des tuiles ou des sprites transformés).
Mais pensez à quelques jeux classiques d'aventure graphique point'n'click (par exemple Monkey Island). Les pièces des jeux d'aventure graphique sont généralement conçues dans leur ensemble, avec peu ou pas de sections reproductibles, tout comme un peintre travaillant sur un paysage. Ou peut-être un jeu comme Final Fantasy 7 qui utilise de grands arrière-plans pré-rendus.
Certaines de ces pièces peuvent devenir assez grandes, s'étendant souvent sur trois écrans de largeur ou plus. Maintenant, si nous considérons ces arrière-plans dans le contexte d'un jeu haute définition moderne, ils dépasseront facilement la taille de texture maximale prise en charge.
Maintenant, la solution évidente à cela est de diviser l'arrière-plan en sections plus petites qui correspondent aux exigences et de les dessiner côte à côte. Mais est-ce que vous (ou votre artiste) devez être celui qui divise toutes vos textures?
Si vous travaillez avec une API de haut niveau, ne devrait-elle pas être prête à faire face à cette situation et à effectuer le fractionnement et l'assemblage des textures en interne (soit en tant que prétraitement tel que Content Pipeline de XNA ou au moment de l'exécution)?
Éditer
Voici ce que je pensais, du point de vue de la mise en œuvre de XNA.
Mon moteur 2D ne nécessite qu'un très petit sous-ensemble des fonctionnalités de Texture2D. Je peux en fait le réduire à cette interface:
public interface ITexture
{
int Height { get; }
int Width { get; }
void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}
La seule méthode externe que j'utilise qui repose sur Texture2D est SpriteBatch.Draw () afin que je puisse créer un pont entre eux en ajoutant une méthode d'extension:
public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
{
texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
}
Cela me permettrait d'utiliser une ITexture de manière interchangeable chaque fois que j'utilisais un Texture2D auparavant.
Ensuite, je pourrais créer deux implémentations différentes d'ITexture, par exemple RegularTexture et LargeTexture, où RegularTexture emballerait simplement un Texture2D normal.
D'un autre côté, LargeTexture conserverait une liste de Texture2D correspondant chacun à l'un des morceaux fractionnés de l'image complète. La partie la plus importante est que l'appel de Draw () sur la LargeTexture devrait être capable d'appliquer toutes les transformations et de dessiner toutes les pièces comme si elles n'étaient qu'une seule image contiguë.
Enfin, pour rendre l'ensemble du processus transparent, je créerais une classe de chargeur de texture unifiée qui agirait comme une méthode d'usine. Il prendrait le chemin de la texture comme paramètre et retournerait une ITexture qui serait soit une RegularTexture soit une LargeTexture selon la taille de l'image dépassant la limite ou non. Mais l'utilisateur n'avait pas besoin de savoir lequel c'était.
Un peu exagéré ou ça sonne bien?
Réponses:
Je crois que tu es sur le bon chemin. Vous devez diviser les images en petits morceaux. Puisque vous créez un créateur de jeux, vous ne pouvez pas utiliser le pipeline de contenu de XNA. À moins que votre créateur ne ressemble davantage à un moteur qui nécessitera toujours que les développeurs utilisent Visual Studio. Vous devez donc créer vos propres routines qui feront le fractionnement. Vous devriez même envisager de diffuser les morceaux un peu avant qu'ils ne deviennent visibles afin de ne pas limiter la quantité de mémoire vidéo que les joueurs devraient avoir.
Il y a quelques astuces que vous pouvez faire spécifiquement pour les jeux d'aventure. J'imagine que comme tous les jeux d'aventure classiques, vous aurez quelques couches de ces textures pour que ... votre personnage puisse marcher derrière l'arbre ou le bâtiment ...
Si vous voulez que ces couches aient un effet de paralaxe, alors lorsque vous divisez vos tuiles, sautez simplement toutes les translucides une fois. Ici, vous devez penser à la taille des carreaux. Les tuiles plus petites ajouteront la gestion des frais généraux et des appels, mais seront moins de données là où les tuiles plus grandes seront plus conviviales pour le GPU mais auront beaucoup de translucidité.
Si vous n'avez pas d'effet paralaxé, au lieu de couvrir toute la scène avec 2-4 images géantes qui ont une profondeur de 32 bits, vous pouvez créer une seule profondeur de 32 bits. Et vous pouvez avoir une couche de pochoir ou de profondeur qui ne sera que de 8 bits par pixel.
Je sais que cela semble difficile à gérer des actifs par des développeurs autres que des jeux, mais ce n'est pas nécessairement le cas. Par exemple, si vous avez une rue avec 3 arbres et que le joueur passe derrière 2 d'entre eux et devant le troisième arbre et le reste de l'arrière-plan ... Faites simplement la disposition de la scène comme vous le souhaitez dans votre éditeur puis dans un Étape de construction de votre créateur de jeu, vous pouvez faire cuire ces images géantes (enfin de petites tuiles d'une grande image).
À propos de la façon dont les jeux classiques le faisaient. Je ne suis pas sûr qu'ils aient probablement fait des tours simmilaires mais vous devez vous rappeler qu'au moment où l'écran était en 320x240, les jeux étaient en 16 couleurs qui, lorsque vous utilisez des textures palattelisées, vous permet d'encoder 2 pixels en un seul octet. Mais ce n'est pas ainsi que fonctionnent les architectures actuelles: D
Bonne chance
la source
Coupez-les pour qu'elles ne soient plus arbitrairement grandes, comme vous dites. Il n'y a pas de magie. Ces vieux jeux 2D l'ont fait ou ont été rendus dans le logiciel, auquel cas il n'y avait aucune restriction matérielle au-delà de la taille de la RAM. Il est à noter que beaucoup de ces jeux 2D n'avaient vraiment pas d'énormes arrière-plans, ils faisaient juste défiler lentement pour se sentir énormes.
Ce que vous cherchez à faire dans votre créateur de jeux d'aventure graphique, c'est de prétraiter ces grandes images pendant une sorte d'étape de "construction" ou "d'intégration" avant que le jeu ne soit préparé pour fonctionner.
Si vous souhaitez utiliser une API et une bibliothèque existantes au lieu d'écrire les vôtres, je vous suggère de convertir ces grandes images en mosaïques lors de cette "construction" et d'utiliser un moteur de mosaïques 2D, qui sont nombreux.
Si vous souhaitez utiliser vos propres techniques 3D, vous souhaiterez peut-être toujours vous scinder en mosaïques et utiliser une API 2D bien connue et bien conçue pour écrire votre propre bibliothèque 3D à cet effet, de cette façon, vous êtes assuré de commencer au moins par une bonne conception de l'API et moins de conception requise de votre part.
la source
Si vous savez à quoi ressemble un quadtree dans la pratique visuelle, j'ai utilisé une méthode qui coupe des images détaillées de grande taille en images plus petites relativement similaires à ce à quoi ressemble une preuve / visualisation d'un quadtree. Cependant, les miens ont été créés de cette façon pour découper des zones spécifiques qui pourraient être encodées ou compressées différemment en fonction de la couleur. Vous pouvez utiliser cette méthode et faire ce que j'ai décrit, car cela est également utile.
Au moment de leur exécution, les couper nécessiterait temporairement plus de mémoire et ralentirait le temps de chargement. Je dirais que cela dépend si vous vous souciez plus du stockage physique ou du temps de chargement d'un jeu d'utilisateurs créé avec votre éditeur.
Temps de chargement / exécution: La façon dont je procéderais pour le chargement consiste simplement à le découper en morceaux de taille proportionnelle. Tenez compte d'un pixel sur la partie la plus à droite si c'est un nombre impair de pixels, mais personne n'aime que leurs images soient coupées, en particulier les utilisateurs inexpérimentés qui pourraient ne pas savoir que ce n'est pas entièrement à eux. Faites-leur la moitié de la largeur OU la moitié de la hauteur (ou 3rds, 4ths quelle que soit) la raison pour laquelle ils ne sont pas en carrés ou en 4 sections (2 rangées 2 colonnes) est parce que cela rendrait la mémoire de mosaïque plus petite car vous ne vous soucieriez pas de x et y en même temps (et selon le nombre d'images aussi volumineuses, cela pourrait être assez important)
Avant la main / automatiquement: dans ce cas, j'aime l'idée de donner à l'utilisateur le choix de le stocker dans une image ou de le stocker comme des pièces distinctes (une image doit être par défaut). Le stockage de l'image au format .gif fonctionnerait très bien. L'image serait dans un fichier, et plutôt que chaque image soit une animation, ce serait plus comme une archive compressée de la même image (ce qui est essentiellement ce qu'est un .gif de toute façon). Cela permettrait une facilité de transport des fichiers physiques, une facilité de chargement:
Oh et si vous utilisez la méthode .gif, vous devez changer l'extension du fichier en quelque chose d'autre (.gif -> .kittens) pour éviter toute confusion lorsque votre .gif s'anime comme s'il s'agissait d'un fichier cassé. (ne vous inquiétez pas de la légalité de cela, .gif est un format ouvert)
la source
Cela va sembler évident, mais pourquoi ne pas simplement diviser votre pièce en petits morceaux? Choisissez une taille arbitraire qui ne heurtera pas les cartes graphiques (comme 1024x1024, ou peut-être plus grandes) et divisez simplement vos pièces en plusieurs morceaux.
Je sais que cela évite le problème, et honnêtement, c'est un problème très intéressant à résoudre. Quoi qu'il en soit, c'est une sorte de solution triviale, qui peut parfois fonctionner pour vous.
la source