Atualização: O algoritmo de renderização de mapa foi corrigido, adicionou mais ilustrações, mudou a formatação.
Talvez a vantagem da técnica "zig-zag" para mapear os ladrilhos para a tela possa ser dita de que os ladrilhos x
e as y
coordenadas estão nos eixos vertical e horizontal.
Abordagem "Desenho em diamante":
Ao desenhar um mapa isométrico usando "desenho em um diamante", acredito que se refere apenas à renderização do mapa usando um for
loop aninhado sobre a matriz bidimensional, como este exemplo:
tile_map[][] = [[...],...]
for (cellY = 0; cellY < tile_map.size; cellY++):
for (cellX = 0; cellX < tile_map[cellY].size cellX++):
draw(
tile_map[cellX][cellY],
screenX = (cellX * tile_width / 2) + (cellY * tile_width / 2)
screenY = (cellY * tile_height / 2) - (cellX * tile_height / 2)
)
Vantagem:
A vantagem da abordagem é que é um simples aninhado for
loop com lógica bastante direta que funciona de forma consistente em todos os blocos.
Desvantagem:
Uma desvantagem dessa abordagem é que as coordenadas x
e y
dos blocos no mapa aumentarão em linhas diagonais, o que pode dificultar o mapeamento visual da localização na tela para o mapa representado como uma matriz:
No entanto, haverá uma armadilha na implementação do código de exemplo acima - a ordem de renderização fará com que os blocos que deveriam estar atrás de certos blocos sejam desenhados no topo dos blocos na frente:
Para corrigir esse problema, a for
ordem do loop interno deve ser revertida - iniciando no valor mais alto e renderizando no valor mais baixo:
tile_map[][] = [[...],...]
for (i = 0; i < tile_map.size; i++):
for (j = tile_map[i].size; j >= 0; j--): // Changed loop condition here.
draw(
tile_map[i][j],
x = (j * tile_width / 2) + (i * tile_width / 2)
y = (i * tile_height / 2) - (j * tile_height / 2)
)
Com a correção acima, a renderização do mapa deve ser corrigida:
Abordagem "zig-zag":
Vantagem:
Talvez a vantagem da abordagem "zig-zag" seja que o mapa renderizado possa parecer um pouco mais verticalmente compacto do que a abordagem "diamante":
Desvantagem:
Ao tentar implementar a técnica de zig-zag, a desvantagem pode ser que é um pouco mais difícil escrever o código de renderização, porque não pode ser escrito tão simples quanto um for
loop aninhado sobre cada elemento em uma matriz:
tile_map[][] = [[...],...]
for (i = 0; i < tile_map.size; i++):
if i is odd:
offset_x = tile_width / 2
else:
offset_x = 0
for (j = 0; j < tile_map[i].size; j++):
draw(
tile_map[i][j],
x = (j * tile_width) + offset_x,
y = i * tile_height / 2
)
Além disso, pode ser um pouco difícil tentar descobrir a coordenada de um bloco devido à natureza escalonada da ordem de renderização:
Nota: As ilustrações incluídas nesta resposta foram criadas com uma implementação Java do código de renderização de bloco apresentado, com a seguinte int
matriz como o mapa:
tileMap = new int[][] {
{0, 1, 2, 3},
{3, 2, 1, 0},
{0, 0, 1, 1},
{2, 2, 3, 3}
};
As imagens de bloco são:
tileImage[0] ->
Uma caixa com uma caixa dentro.
tileImage[1] ->
Uma caixa preta.
tileImage[2] ->
Uma caixa branca
tileImage[3] ->
Uma caixa com um alto objeto cinza.
Uma observação sobre larguras e alturas de lado a lado
As variáveis tile_width
e tile_height
que são usadas nos exemplos de código acima se referem à largura e altura do bloco do solo na imagem que representa o bloco:
O uso das dimensões da imagem funcionará, desde que as dimensões da imagem e as dimensões do bloco correspondam. Caso contrário, o mapa de blocos poderá ser renderizado com intervalos entre os blocos.
j = (2 * x - 4 * y) / tilewidth * 0.5; i = (p.x * 2 / tilewidth) - j;
.De qualquer maneira, o trabalho é feito. Suponho que em zigue-zague você queira dizer algo assim: (os números estão na ordem de renderização)
E por diamante você quer dizer:
O primeiro método precisa de mais blocos renderizados para que a tela inteira seja desenhada, mas você pode facilmente fazer uma verificação de limite e pular todos os blocos totalmente fora da tela. Ambos os métodos exigirão uma trituração de número para descobrir qual é a localização do bloco 01. No final, ambos os métodos são aproximadamente iguais em termos de matemática necessária para um certo nível de eficiência.
fonte
Se você tiver alguns ladrilhos que excedem os limites do seu diamante, recomendo desenhar em ordem de profundidade:
fonte
A resposta de Coobird é a correta e completa. No entanto, combinei suas dicas com as de outro site para criar um código que funcione no meu aplicativo (iOS / Objective-C), que eu gostaria de compartilhar com qualquer pessoa que vier aqui procurar algo assim. Por favor, se você gostar / faça o voto positivo desta resposta, faça o mesmo com os originais; tudo o que fiz foi "ficar nos ombros dos gigantes".
Quanto à ordem de classificação, minha técnica é o algoritmo de um pintor modificado: cada objeto tem (a) uma altitude da base (eu chamo de "nível") e (b) um X / Y para a "base" ou o "pé" de a imagem (exemplos: a base do avatar está a seus pés; a base da árvore está em suas raízes; a base do avião é a imagem central etc.) Depois, apenas classifico o nível mais baixo ao mais alto, depois o mais baixo (mais alto na tela) Y, então mais baixo (mais à esquerda) até mais alto base-X. Isso renderiza as peças da maneira que se esperaria.
Código para converter a tela (ponto) em bloco (célula) e vice-versa:
fonte
Você pode usar a distância euclidiana do ponto mais alto e mais próximo do visualizador, exceto que isso não está certo. Isso resulta em uma ordem de classificação esférica. Você pode esclarecer isso olhando para mais longe. Mais longe, a curvatura fica achatada. Então, basta adicionar 1000 para cada um dos componentes x, ye z para fornecer x ', y' e z '. A classificação em x '* x' + y '* y' + z '* z'.
fonte
O verdadeiro problema é quando você precisa desenhar alguns ladrilhos / sprites que cruzam / abrangem dois ou mais ladrilhos.
Após 2 meses (difíceis) de análise pessoal do problema, finalmente encontrei e implementei um "desenho de renderização correto" para o meu novo jogo cocos2d-js. A solução consiste em mapear, para cada peça (suscetível), quais sprites estão "na frente, atrás, acima e atrás". Depois de fazer isso, você pode desenhá-los seguindo uma "lógica recursiva".
fonte