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:
- 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?)
- 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.
- 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.
- 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 rotation
está o ângulo da tela e adjustedRotation
agora 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".