Motif commun pour mettre à l'échelle les «unités réelles» en pixels?

10

Il s'agit d'une question complémentaire à celle-ci .

Je voudrais savoir s'il existe un motif commun / typique / meilleur pour mettre à l'échelle ma représentation du monde (actuellement 160Kmx160Km) pour l'adapter à la zone de dessin (actuellement 800x600 pixels).

Je peux penser à au moins quatre approches différentes:

Un naïf (comme je l'ai fait jusqu'à présent). J'ai implémenté une fonction globale sc(vector)qui retournera simplement une copie réduite du vecteur transmis. Cela fonctionne bien sûr, mais m'oblige à écrire du code comme:

drawCircle(sc(radius), sc(position))

Fonctions d'emballage . Je pourrais définir plusieurs fonctions, chacune d'elles enveloppant celle du middleware d'origine. Par exemple, je pourrais définir myDrawCirclequi mettrait d'abord à l'échelle les arguments qui ont besoin d'être mis à l'échelle, puis appeler drawCircleavec ce dernier. Cela rendrait mon code peut-être plus lisible et plus facile à maintenir, mais je devrais écrire beaucoup de fonctions de wrapping, qui semblent idiotes.

Décorateur de fonction . Je pourrais simplement décorer les fonctions middleware existantes, fournissant une mise à l'échelle automatique pour tous les paramètres qui sont une instanciation de la classe Vector3D, mais le problème est que ces fonctions fonctionnent également avec les mêmes paramètres étant listou Vector2Daussi, et le décorateur n'aurait aucun moyen de savoir quelles listes doivent être mises à l'échelle (le rayon par exemple) et lesquelles non (les valeurs RVB).

Initialisation de surface . Lors de la définition de la surface sur laquelle je vais dessiner, je pourrais définir le facteur d'échelle (de sorte que j'utiliserais alors des mètres et non des pixels comme paramètres). Cela fonctionnerait de manière transparente pour moi et serait ma solution de choix, mais bien sûr, elle devrait être implémentée dans le middleware, donc ce n'est pas une vraie option.

... de toute façon: comme il s'agit d'un problème très courant, je me demande s'il existe un modèle établi qui résout avec élégance ce problème que je n'ai pas trouvé.

PS: Pour ce projet, j'utilise python (avec pygame ), mais - bien qu'une réponse spécifique à python / pygame soit très appréciée, je suis plus intéressé par la description générale / de haut niveau du modèle plutôt que par sa mise en œuvre concrète.

Merci d'avance pour votre temps et votre expertise.

Mac
la source

Réponses:

6

La manière standard de procéder consiste à configurer une matrice de transformation pour effectuer la conversion pendant le rendu. Pour le rendu 3D, c'est la matrice de transformation de la vue pour la caméra qui le fait.

La plupart des API 2D ont également un moyen de spécifier une transformation de vue, en tant que matrice 2x3 ou en tant qu'échelle, translation et rotation distinctes.

Un rapide coup d'œil à la documentation de Pygame suggère que vous devrez implémenter vous-même une matrice de transformation de vue. Cela vous permet-il de dériver votre propre classe de sa classe de surface pour vous permettre d'ajouter cette fonctionnalité?

Adam
la source
Votre réponse est très utile (+1). Je peux sous-classer ma classe de surface, mais j'ai besoin de plus de temps pour explorer si je peux réaliser ce qui est indiqué dans votre message. Je suis très nouveau dans la programmation de jeux et les graphiques en général, avez-vous un lien à recommander pour expliquer cette approche matricielle (ou même seulement les mathématiques impliquées en utilisant une matrice pour mettre à l'échelle une surface?). Je vous remercie!
mac
1
Comme c'est 2D et qu'il n'y a pas de rotation impliquée, @mac dit essentiellement d'envelopper les fonctions et vous pouvez utiliser votre simple division d'échelle dans ces enveloppes. La raison pour laquelle une matrice complète est normalement utilisée est que la plupart des API ont une matrice contrôlant la fenêtre, mais il semble que Pygame ne le fasse pas, vous devez donc le faire vous-même une couche plus haut.
Patrick Hughes,
2

comme il s'agit d'un problème très courant, je me demande s'il existe un modèle établi qui résout avec élégance ce problème que je n'ai pas trouvé.

Habituellement, les gens n'essaient pas d'effectuer une mise à l'échelle au moment de l'exécution dans les jeux 2D. Je ne suis pas d'accord pour dire que c'est un problème courant. Si les gens veulent une mini-carte ou un autre redimensionnement fixe, il y a souvent un nouvel ensemble de graphiques fait à cet effet. Il est rare que vous ayez besoin d'une seule routine pour exécuter à 2 niveaux de zoom différents dans un jeu 2D.

Si vous utilisez une API 3D, vous pouvez obtenir cette fonctionnalité gratuitement - il suffit de modifier les paramètres de la caméra / fenêtre.

PyGame est une très ancienne API et, malheureusement, n'est vraiment adaptée à la 2D. Même si vous pouviez mettre au point des systèmes de mise à l'échelle adéquats pour les différents niveaux de zoom, les performances ne seront pas assez bonnes et l'apparence sera probablement inacceptable.

Je conseillerais que si vous voulez beaucoup zoomer et dézoomer, vous passez à une API 3D moderne dès que possible. Je recommanderais pyglet mais il y en aura probablement d'autres aussi.

Kylotan
la source
Merci pour votre réponse (+1). Je l'ai déjà utilisé pygletsdans le passé pour une simulation 3D. Il est certainement plus performant que cela pygame, mais le support de la 2D est de niveau assez inférieur à celui de pygame. La documentation / les exemples disponibles sont également moins détaillés, ce qui est un problème pour moi car je suis un débutant en développement de jeux, et j'ai vraiment besoin de comprendre la base des opérations les plus couramment effectuées. :) Quant à «l'âge» du pygame: vous avez raison. Une modernisation est cependant en cours! :)
mac
Quant à: "Il est rare que vous ayez besoin d'une seule routine pour fonctionner à 2 niveaux de zoom différents" ... Je pensais que c'était ce qui serait utilisé lors du changement de la taille d'une fenêtre / de la résolution d'un jeu en plein écran. D'après votre commentaire, j'ai compris que ce n'est pas le cas: un pointeur vers ce qui est "commun" à la place?
mac
Quelles opérations 2D effectuez-vous là où pyglet est plus bas niveau que pygame? Les deux vous permettent de dessiner un sprite avec 1 ligne de code. Lorsque vous modifiez la taille de la fenêtre d'un jeu 2D, le rapport pixel / unité mondiale reste presque toujours constant. Donc vous finissez par dessiner plus de sprites: vous ne les dessinez pas différemment.
Kylotan
Sur le côté bas des choses: je ne suis pas vraiment un expert sur l'une des deux bibliothèques, mais dans les pyglets, je ne pouvais pas reproduire hors de la boîte les comportements de rendu de groupe offerts par pygame (comme dans pygame.sprite.LayeredUpdatespar exemple). Quant au rapport immuable: j'ai compris ce que vous voulez dire. Le comportement que vous décrivez n'est pas celui que je veux reproduire, mais j'ai compris ce que vous voulez dire, merci pour la clarification! :)
mac
pyglet a des objets OrderedGroup - les documents sont là si vous ou quelqu'un d'autre est intéressé: pyglet.org/doc/programming_guide/displaying_images.html#sprites
Kylotan