Padrão comum para dimensionar "unidades reais" para pixels?

10

Esta é uma pergunta de acompanhamento para esta outra .

Gostaria de saber se existe um padrão comum / típico / melhor para dimensionar minha representação do mundo (atualmente 160Kmx160Km) para ajustá-lo à área de desenho (atualmente 800x600 pixels).

Posso pensar em pelo menos quatro abordagens diferentes:

Um ingênuo (do jeito que eu fiz até agora). Eu implementei uma função global sc(vector)que simplesmente retornará uma cópia reduzida do vetor passado. Isso obviamente funciona, mas me obriga a escrever código como:

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

Funções de quebra automática . Eu poderia definir várias funções, cada uma envolvendo o middleware original. Por exemplo, eu poderia definir myDrawCircleque primeiro escalaria os argumentos que precisam de escala e depois chamasse drawCirclecom o último. Isso tornaria meu código talvez mais legível e mais fácil de manter, mas eu deveria escrever muitas funções de agrupamento, que parecem bobas.

Decorador de funções . Eu poderia simplesmente decorar as funções de middleware existentes, fornecendo escala automática para todos os parâmetros que são uma instanciação da classe Vector3D, mas o problema é que essas funções também funcionam com os mesmos parâmetros, listou Vector2Dseja, e o decorador não teria como saber quais listas precisam ser redimensionadas (o raio, por exemplo) e quais não (os valores RGB).

Inicialização de superfície . Ao definir a superfície em que vou desenhar, eu poderia definir o fator de escala (para então usar metros e não pixels como parâmetros). Isso funcionaria de forma transparente para mim e seria minha solução preferida, mas é claro que deveria ser implementado no middleware, portanto não é uma opção real.

... de qualquer maneira: como esse é um problema muito comum, pergunto-me se existe um padrão estabelecido que resolva elegantemente esse problema que não consegui encontrar.

PS: Para este projeto, estou usando python (com pygame ), mas - embora uma resposta específica para python / pygame seja muito apreciada, estou mais interessado na descrição geral / de alto nível do padrão do que em sua implementação concreta.

Agradecemos antecipadamente pelo seu tempo e experiência.

Mac
fonte

Respostas:

6

A maneira padrão de fazer isso é configurar uma matriz de transformação para fazer a conversão durante a renderização. Para renderização em 3D, é a matriz de transformação de exibição da câmera que faz isso.

A maioria das APIs 2D também tem uma maneira de especificar uma transformação de exibição, como uma matriz 2x3 ou como uma escala, translação e rotação separadas.

Uma rápida olhada na documentação do pygame sugere que você precisará implementar uma matriz de transformação de exibição. Permite derivar sua própria classe da classe de superfície para permitir que você adicione essa funcionalidade?

Adão
fonte
Sua resposta é muito útil (+1). Posso subclassificar minha classe de superfície, mas preciso de mais tempo para explorar se posso alcançar o que é indicado na sua postagem. Eu sou muito novo em programação de jogos e gráficos em geral, você tem algum link para recomendar essa explicação da abordagem matricial (ou mesmo apenas a matemática envolvida no uso de uma matriz para dimensionar uma superfície?). Obrigado!
mac
1
Como é 2D e não há rotação envolvida, o @mac está basicamente dizendo para agrupar funções e você pode usar sua divisão de escala simples nesses invólucros. O motivo pelo qual uma matriz completa é normalmente usada é que a maioria das APIs tem uma matriz que controla a janela de exibição, mas parece que o pygame não possui, então você precisa fazer isso sozinho uma camada acima.
Patrick Hughes
2

Como esse é um problema muito comum, pergunto-me se existe um padrão estabelecido que resolva elegantemente esse problema que não consegui encontrar.

Geralmente, as pessoas não tentam executar a escala de tempo de execução em jogos 2D. Não concordo que seja um problema comum. Se as pessoas desejam um mini-mapa ou algum outro redimensionamento fixo, geralmente há um novo conjunto de gráficos para esse fim. É raro que você precise de uma única rotina para executar em 2 níveis de zoom diferentes em um jogo 2D.

Se você usa uma API 3D, pode obter essa funcionalidade gratuitamente - basta alterar os parâmetros da câmera / porta de visualização.

PyGame é uma API muito antiga e, infelizmente, só é realmente adequada para 2D. Mesmo que você possa trabalhar com sistemas de dimensionamento adequados para os diferentes níveis de zoom, o desempenho não será bom o suficiente e a aparência provavelmente será inaceitavelmente ruim.

Eu recomendaria que, se você quiser aumentar e diminuir o zoom, mude para uma API 3D moderna o mais rápido possível. Eu recomendaria o pyglet, mas provavelmente também haverá outros.

Kylotan
fonte
Obrigado pela sua resposta (+1). Eu já usei pygletsno passado para uma simulação 3D. É certamente mais capaz do que pygame, mas o suporte ao 2D é de nível bastante inferior ao do Windows pygame. A documentação / exemplos disponíveis também são menos detalhados, o que é uma chatice para mim, pois sou iniciante no desenvolvimento de jogos e preciso realmente entender a base das operações mais executadas. :) Quanto à "idade" do pygame: você está certo. Uma modernização está em andamento, no entanto! :)
mac
Quanto a: "É raro você precisar de uma rotina única para rodar em dois níveis de zoom diferentes" ... Pensei que fosse isso que seria usado ao alterar o tamanho de uma janela / a resolução de um jogo em tela cheia. Pelo seu comentário, entendi que não é: qualquer ponteiro para o que é "comum"?
mac
Quais operações 2D você está executando onde o pyglet é mais baixo que o pygame? Ambos permitem desenhar um sprite com 1 linha de código. Quando você altera o tamanho da janela de um jogo 2D, a proporção de pixel para unidade mundial quase sempre permanece constante. Então você acaba desenhando mais sprites: você não os desenha de maneira diferente.
Kylotan
No lado mais baixo das coisas: eu não sou verdadeiramente um especialista em nenhuma das duas bibliotecas, mas em pyglets não pude replicar imediatamente os comportamentos de renderização de grupo oferecidos pelo pygame (como pygame.sprite.LayeredUpdatespor exemplo). Quanto à relação imutável: entendi o que você quer dizer. O comportamento que você descreve não é o que quero replicar, mas entendi o que você quer dizer, obrigado pelo esclarecimento! :)
mac
pyglet tem OrderedGroup objetos - docs aqui se você ou qualquer outra pessoa é interessadas: pyglet.org/doc/programming_guide/displaying_images.html#sprites
Kylotan