Traçando um globo pseudo 3D
Eu gostaria de traçar um pequeno globo onde o personagem principal pode andar, exatamente como o Sonic & Knukles Bonus Stage. Para quem não quer pesquisar no Google, aqui está uma foto .
Estou familiarizado com Raycasting, usado em Wolfenstein e outros jogos para "simular" uma perspectiva 3D em um mapa 2D.
Mas eu não consegui descobrir como programar o globo, e suponho que não fosse uma renderização 3D real, já que Sonic era um jogo de 16 bits.
Alguma ideia de como fazer isso sem nenhum sofisticado mecanismo 3D?
Respostas
Visão geral
- Configure uma trilha 1D infinita de planos 2D 2x. Conforme você corre para frente, o avião atrás de você avança para mantê-lo funcionando; isso continua acontecendo repetidamente, quer você corra para frente ou para trás.
- Agora faça a mesma coisa em 2D, ou seja, com planos 2D 2x2. Onde quer que você vá, o mundo continua sob seus pés.
- Transforme os planos em uma vista em perspectiva.
- Agora crie um efeito de protuberância esférica através da transformação do espaço da tela, ou seja, ajustando todos os pixels do solo para fazê-los parecer curvos, mesmo que seja realmente plana, uma superfície repetitiva.
- Mesmo quando o personagem gira 90 graus em alguns quadros, isso ainda mostra o mesmo efeito de mundo curvo.
Planos 3D em 2D
Vamos supor que você tenha planos planos 2x2 renderizando na tela como quadrados (vistos de cima para baixo) e que você possa se mover neles conforme descrito acima.
Agora precisamos transformar esses planos (coletivamente), vistos de cima para baixo, em uma perspectiva oblíqua ao solo.
Isso é feito em 2 etapas:
- comprima o plano de solo combinado de modo que sua metade superior "aperte" a largura da janela de visualização e sua metade inferior exceda a largura da janela de visualização. Isso é feito usando
yRatioo calculado na seção de código abaixo, ou seja, quanto mais perto estamos do topo, mais escalamosxpara apertar o topo do quadrado para que se pareça com um tronco ou triângulo. - Reduza-o e reposicione-o em y de modo que sua parte inferior fique alinhada com a parte inferior da janela de visualização e sua parte superior esteja (digamos) no meio da tela - este é o seu horizonte.
Ambas as etapas dependem de onde o jogador está atualmente.
Curvatura
Uma fórmula de semicírculo é necessária para a transformação dos pixels, que serão deslocados ao longo da tela y para obter o efeito de protuberância. Esta parte é deixada para sua pesquisa.
semicircleDisplace(xCurrent)
{
//formula to calculate maximal (horizon) yDisplacement from xCurrent
//...
return yDisplacement;
}
pixels[xCurrent][yCurrent].y += semicircleDisplace(xCurrent);
O problema com isso é que aumentamos todos os pixels tanto perto da parte inferior da tela quanto perto do topo, levando a uma espécie de U de cabeça para baixo para o terreno, quando o que realmente queremos perto da parte inferior do a tela é uma linha quase reta; no meio do caminho, algum deslocamento / protuberância; e no horizonte, deslocamento máximo. Conseguimos isso usando um fator interpolado (possivelmente linear):
semicircleDisplace(xCurrent, yCurrent)
{
//formula to calculate maximal (horizon) yDisplacement from xCurrent
//...
//linear interpolation based on where we are between bottom of screen and horizon
yRange = yMax - yMin
yRatio = yCurrent - yMin
yFactor = yRatio / yRange
return yDisplacement * yFactor;
}
pixels[xCurrent][yCurrent].y += semicircleDisplace(xCurrent, yCurrent);
yFactoré um valor entre 0.0e 1.0pelo qual você multiplica yDisplacement. Se a interpolação linear (que é barata) não der uma boa aparência, você pode brincar com interpolações não lineares para obter o tipo certo de curvatura do solo. Mas meu palpite é que linear ficará bem.