Fingindo gráficos isométricos em um jogo espacial 2D

15

Primeiro, eu sei exatamente qual é o meu problema de desenho e tenho várias idéias sobre como abordá-lo. Estou aqui para descobrir como ajustar qual quadro é desenhado para que a "ilusão" isométrica seja mantida.

Estou escrevendo um jogo 2D e panorâmico que ocorre no espaço. Eu estou tentando usar gráficos isométricos em um mundo onde Up is North, não há rotação do mundo dos jogos como nos jogos isométricos tradicionais (lembre-se, o jogo ocorre no espaço, sem terreno). Aqui está um exemplo de sprite que estou tentando usar: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64.png Girado 64 vezes sobre seu próprio eixo vertical com um ângulo de visão de 35 graus (também conhecido como iso). A imagem foi gerada, portanto, isso pode ser alterado.

Por uma questão de clareza, afirmei que Norte (Para cima) é 0 graus e Leste (Direito) é 90.

Meu problema é que meu sprite nem sempre parece estar voltado para onde o jogo pensa que é devido a uma diferença nos aviões 3D usados. Não tenho certeza se estou usando a terminologia corretamente, mas minha nave espacial foi girada em um plano e o plano de visualização espera que as coisas sejam giradas em seu próprio plano. Aqui está uma representação do problema:

http://cell.stat-life.com/images/stories/AsteroidOutpost/ProjectionIssue.png À esquerda, tenho vistas laterais, à direita, vistas de cima para baixo. No topo, tenho a vista da nave espacial / folha de sprite do mundo. Na parte inferior, tenho a aparência do sprite quando é atraído para a tela.

No canto superior direito, há uma versão simplificada de como minha nave espacial foi girada (mesmo separações de graus entre cada quadro). No canto inferior direito, está o ângulo que o sprite parece estar enfrentando quando um determinado ângulo é desenhado na tela. O problema é mais evidente em cerca de 45 graus. Aqui está uma imagem sobreposta com uma linha de "plano de tela" que é apontada na direção que o navio deveria estar enfrentando: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLine.png A linha vermelha deve sempre ser apontada exatamente na mesma direção que o navio, mas como você pode ver, o problema de projeção está causando um problema. Espero estar descrevendo o problema suficientemente bem.

EDIT: A linha vermelha é girada no plano da tela, enquanto a nave espacial é girada no "plano da nave", daí a grande diferença entre o ângulo da nave e o ângulo da tela quando ela é desenhada. EDIT FIM

Parece um pouco estranho quando este navio está disparando um raio laser em um alvo que está fora de um lado, quando deveria estar disparando para frente.

Então ... as soluções que eu criei são:

  1. Pare de tentar fingir uma vista isométrica, exagere ou vá para casa. Gire meu mundo já. (PS: isso vai resolver o meu problema, certo?)
  2. Altere minha planilha de sprite (de alguma forma) para ter quadros que representam o "ângulo da tela" em que o modelo será exibido. Então, quando eu pedir uma imagem de 45 graus, ela realmente parecerá estar voltada para 45 graus na tela.
  3. Altere meu sistema de renderização de sprite para pegar um quadro diferente da folha de sprite (de alguma forma), sabendo que pegar o quadro "normal" parecerá engraçado. Então, em vez de pegar o quadro de 45 graus, ele pegará o ... quadro de 33 graus (apenas supondo) para que pareça correto para o usuário.
  4. Basta usar 3D! É muito mais fácil cara

Por um lado: Qual solução você recomendaria? Estou inclinado para 2, mesmo sabendo que está errado. Lembre-se de que tenho acesso total à ferramenta de geração de sprites. O método 3 seria minha segunda opção. Ambos os métodos simplesmente exigem que eu aplique um pouco de matemática ao (s) ângulo (s) para obter o resultado desejado. Btw, eu adicionei o # 4 lá como uma piada, eu não quero passar para 3D.

Para dois: Usando os métodos 2 ou 3, como eu ajustaria os ângulos de entrada ou saída? Eu não sou tão bom com projeções 3D e matrizes 3D (quanto mais matrizes 2D), e qualquer outra matemática que possa ser usada para alcançar o resultado desejado.

Pensando em voz alta aqui: se eu pegar um vetor unitário voltado para a direção em que eu quero que o navio olhe (no plano da tela), em seguida, projete-o no avião, em seguida, descubra qual é o ângulo entre essa linha projetada e a do avião norte é, eu deveria ter o ângulo do gráfico do navio que eu quero exibir. Certo? (solução para o número 3?) Cara ... não consigo resolver isso.

EDITAR:

Eu sei que o problema é difícil de visualizar com imagens estáticas, então eu ter cumprido o meu Tester Visual Sprite Biblioteca para exibir a questão: http://cell.stat-life.com/downloads/SpriteLibVisualTest.zip Exige XNA 4.0 Esta aplicação é basta girar o sprite e desenhar uma linha do ponto central para o ângulo que o jogo acha que o navio deve estar enfrentando.

EDIT 8 de setembro

Continuando no meu parágrafo "pensando em voz alta": em vez de usar uma projeção (porque parece difícil), estou pensando em usar um vetor de unidade voltado para o norte (0x, 1y, 0z), use uma matriz para girá-la no ângulo o sprite está realmente voltado para a frente e, em seguida, gire-o novamente do "plano de visualização" para fora para o "plano de sprite" em torno do eixo X; o vetor (essencialmente o projeta) de volta ao plano de visualização usando apenas o X e Y (ignorando Z). Então, usando esse novo vetor achatado, eu pude determinar seu ângulo e usá-lo para ... algo, alguma coisa. Eu vou pensar mais tarde.

EDIT 8 de setembro (2)

Eu tentei seguir minha idéia de cima com algum sucesso, yay! Então ... para que uma linha vermelha pareça estar saindo diretamente da minha nave espacial (apenas para fins de teste), fiz o seguinte:

Vector3 vect = new Vector3(0, 1, 0);
vect = Vector3.Transform(vect, Matrix.CreateRotationZ(rotation));
vect = Vector3.Transform(vect, Matrix.CreateRotationY((float)((Math.PI / 2) - MathHelper.ToRadians(AngleFromHorizon))));
Vector2 flattenedVect = new Vector2(vect.X, vect.Y);

float adjustedRotation = (float)(getAngle(flattenedVect.X, flattenedVect.Y));

Onde rotationestá o ângulo da tela e adjustedRotationagora o ângulo da tela parece no plano do sprite. Não sei por que eu precisava girar Y em vez de X, mas provavelmente é algo a ver com 3D que eu não conheço.

Portanto, agora tenho uma informação adicional, mas como usá-la para escolher um quadro mais apropriado? Talvez, em vez de girar do plano de visão para o plano de sprite, e depois projetar de volta, eu devesse tentar fazer o contrário. Aqui está o meu sprite com uma linha vermelha ajustada, mas o que realmente quero fazer é ajustar o modelo, não a linha: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLineCorrected.png

EDIT 9 de setembro

HORAY! Está consertado! Vou descrever o que fiz para corrigi-lo:

Eu segui o conselho do eBusiness e "esmaguei" pelo sistema de coordenadas do mundo (ou esticado ...?). Esta é essencialmente a solução nº 1, embora eu tivesse a impressão de que teria que girar meu sistema de coordenadas do mundo em relação ao sistema de coordenadas da tela. Não é verdade! Up ainda é + y, e Right ainda é + x. Modifiquei meus métodos WorldToScreen e ScreenToWorld para converter adequadamente entre as coordenadas do mundo e da tela. Esses métodos podem não ser ótimos, mas aqui estão os únicos dois métodos na minha base de código que tiveram que mudar.

public Vector2 ScreenToWorld(float x, float y)
{
    float deltaX = x - (size.Width / 2f);
    float deltaY = y - (size.Height / 2f);

    deltaX = deltaX * scaleFactor / (float)Math.Sqrt(3);
    deltaY = deltaY * scaleFactor;

    return new Vector2(focusWorldPoint.X + deltaX, focusWorldPoint.Y + deltaY);
}

public Vector2 WorldToScreen(float x, float y)
{
    float deltaX = x - focusWorldPoint.X;
    float deltaY = y - focusWorldPoint.Y;

    deltaX = deltaX / scaleFactor * (float)Math.Sqrt(3);
    deltaY = deltaY / scaleFactor;

    return new Vector2(size.Width / 2f + deltaX, size.Height / 2f + deltaY);
}

Foi isso! Alterar esses dois métodos afetou todo o resto: o que eu estava vendo, onde os objetos foram desenhados, onde eu estava clicando, tudo. Minha nave espacial agora olha diretamente para o alvo que está atirando e tudo está se encaixando. Vou experimentar a projeção ortográfica, ver se faz tudo parecer mais "real".

John McDonald
fonte
Parabéns. Não se esqueça de me cutucar quando tiver algo jogável, eu gostaria de ver para onde isso vai.
aaaaaaaaaaaa 10/09
@eBusiness Conforme prometido: cell.stat-life.com/images/stories/AsteroidOutpost/… e cell.stat-life.com/images/stories/AsteroidOutpost/AOOhNoes.png Observe como o navio parece estar olhando para a torre? : D Obrigado!
John McDonald
@eBusiness, Um vídeo youtube.com/watch?v=Q8pR9KDBsCo Há também um link para download, desde que você pediu.
John McDonald

Respostas:

4

Quando você escolhe a perspectiva isométrica, precisa corrigir a escala entre o eixo X e o eixo Y. Se uma determinada distância projetar para 1 na tela do eixo Y, a mesma distância será projetada para sqrt (3) na tela do eixo X. Então, se você desenhar coisas na tela, faria algo como:

draw(object.image, object.x*sqrt(3), object.y)

Notas sem resposta:

  • Por que você mexeria com folhas de sprite e outras coisas? Você pode obter um renderizador 3D para fazer isométrica, se quiser.
  • Como você está usando folhas de sprite, por que elas não são anti-alias?
  • Isométrico no espaço, acho que nunca vi um jogo usar isso, não tenho certeza de como ele funcionará, dada a falta de um terreno claramente isométrico para referência visual.
aaaaaaaaaaaa
fonte
11
Eu acho ... Isso pode consertar tudo. É uma solução fácil, e posso deixar o lençol sozinho. Vou tentar isso o mais rápido possível e informá-lo como vai. Para responder suas anotações: 1) Estou usando 2D porque é com isso que estou familiarizado e estou gerando minhas folhas a partir de modelos 3D. 2) As arestas devem ser nítidas, mas dentro das arestas duras eu poderia usar o canal alfa para anti-alias, que virá. 3) Não pretendo simular a terceira dimensão (muito), quero principalmente gráficos 2D que não sejam de cima para baixo e permitam que você veja os lados das coisas.
John McDonald
5

Como o sprite girado é gerado? São capturas de tela de um modelo 3D rotativo? O ângulo de frente pode estar desativado devido à perspectiva da câmera da ferramenta de modelagem 3D. A perspectiva isométrica não é uma representação precisa do espaço 3D. Coisas longe da 'câmera' não ficam menores.

Se você quer apenas uma solução rápida. A solução 2 pode ser difícil de acertar. A solução 3 parece fácil, basta trocar os quadros que não correspondem ao ângulo por um que se adapte melhor ao ângulo.

Os lasers ainda estarão desligados algumas vezes. Como você não está fazendo uma rotação suave, mas mostrando quadros diferentes para determinados intervalos de graus.

EDITAR:

Seu problema é que as capturas de tela geradas não são uma perspectiva isométrica, mas uma visualização normal da câmera 3D.

insira a descrição da imagem aqui

A vista isométrica simula o espaço 3D, mas não é uma representação precisa. As coisas ficam menores com o aumento da distância da câmera. Isso não é feito para a perspectiva isométrica, pois isso causaria artefatos de escala feios no sprite.

As capturas de tela da sua nave espacial são feitas com a perspectiva da câmera 3D. É por isso que o disparo a laser está desativado. Compare a linha vermelha na 'isométrica' e na 'perspectiva'.

Seu gerador de sprite deve usar Matrix.CreateOrthographic () em vez de Matrix.CreatePerspective () para a matriz de projeção.

Stephen
fonte
O sprite é gerado usando uma ferramenta 3D para 2D que estou desenvolvendo, então o problema pode estar nessa ferramenta. A ferramenta simplesmente carrega um modelo 3D e, para alcançar o Spaceship64.png (acima), ele gira o modelo em (360/64) = 5.625 graus, salva isso como um quadro e o gira novamente na mesma quantidade até ter tudo 64 quadros. O código usado para renderizar o modelo está aqui: code.google.com/p/sprite-maker/source/browse/trunk/XNAWindow/… A rotação é feita em outra classe. Eu também estava pensando que as soluções 2 e 3 eram inversas, não?
John McDonald
Editou minha resposta. Veja acima.
Stephen
Acho que preciso fazer as duas coisas: fazer meu gerador de sprite usar uma projeção ortográfica E alterar meu sistema de coordenadas do mundo, como o que o @eBusiness está dizendo. Eu tentei a projeção ortográfica ontem à noite e certamente mudou a aparência do meu navio, mas por si só não resolveu o problema de ângulo que estou enfrentando.
John McDonald
Acabei de ver sua edição. O sprite corrigido parece que o centro do navio está fora do centro da linha vermelha. Talvez seja suficiente desenhar a nave um ou dois pixels mais alto do que o ponto inicial da linha vermelha. O erro visível muda enquanto a nave se afasta da sua origem mundial? Em seguida, dimensionar o eixo X pode corrigir isso.
Stephen
1

Eu acho que o que você tem aqui é simplesmente a aparência isométrica. Você está certo nisso, visualmente falando, parece haver uma diferença maior entre 0deg e 10deg do que entre 90deg e 100deg. . . mas isso ocorre porque isométrica comprime intrinsecamente um eixo. Se você não quer esse visual, não quer isométrico.

Dito isto, acho que os problemas visuais que você está tendo são graças a não ter um ponto de referência visual. Seu cérebro está assumindo que você está olhando de cima para baixo - ei, é espaço, por que você não estaria - e também o está interpretando como uma visão padrão de cima para baixo. Para fins de teste, tente adicionar alguns pontos de referência holográficos flutuantes. Uma grade angular de 45 graus, por exemplo, ou um conjunto de círculos ao redor da espaçonave. Verifique se estão distorcidas adequadamente, como se estivessem no mesmo plano isométrico em que sua nave espacial é renderizada. Aposto que seu cérebro descobrirá a perspectiva e de repente parecerá correta.

Agora, descubra como transmitir isso aos seus usuários. . . isso é outra questão.

ZorbaTHut
fonte
Também não precisarei girar o eixo do mundo para concluir a ilusão usando este método (método nº 1 na pergunta)?
John McDonald
Tanto quanto posso dizer, a nave já está sendo renderizada corretamente - as vistas laterais mostram o ângulo que deve ser isométrico para parecer "correto". Suponho que não tenho certeza do que você quer dizer com "gire o eixo do mundo".
precisa saber é o seguinte
Por "girar o eixo mundial", quero dizer girar o mundo em relação à câmera em 45 graus para fazer com que "Norte" fique em direção à parte superior direita ou esquerda da tela em uma diagonal, em vez de "Norte" ser reto para cima em direção ao topo da tela.
9139 John McDonald
Isso pode ajudar, mas no espaço não deve fazer muita diferença de qualquer maneira. A menos que você tenha uma grade sobreposta ao mundo, isso não deve importar.
precisa saber é o seguinte