Embora seja possível, com o que foi mostrado até então, criar cenários como labirintos, seria muito complicado criar um jogo do tipo side-scrolling
no qual o cenário acompanha a movimentação do personagem que controlamos como se usasse uma câmera para seguí-lo.
Neste tutorial abordaremos algumas funcionalidades extras da classe Scene que: permitem o uso de cenários que excedem os limites da tela e
controlam a movimentação dentro do mesmo.
1 - Tiles
Assim como foi descrito no tutorial sobre a classe, os cenários são construídos a partir de retângulos de dimensões iguais,
que são mais conhecidos como tiles. Todo o cenário será descrito basicamente em função de quais tiles usar em que posições.
Obs.: não é recomendável o uso de tiles muito pequenos, pois eles tornarão mais difícil o tratamento de colisões.
2 - Um novo arquivo do cenário
Seguindo o mesmo modelo do tutorial anterior, estaremos usando uma matriz maior.
O arquivo é organizado da seguinte forma:
linha 1 - número de imagens usadas para a construção do cenário (as imagens estáticas).
linha 2 - caminho da primeira imagem e sua extensão
linha 3 - caminho da segunda imagem e sua extensão
linha 4 - caminho da terceira imagem e sua extensão
linha n+1 - caminho da n-ésima imagem e sua extensão
linha n+2 - começo da construção da matriz
linha m - fim da construção da matriz que é representada pelo caracter '%'.
linha m+1 - caminho do backdrop e sua extensão.
É importante notar que se, por exemplo, o tile representado pelo número 1 tem 30 pixels de largura por
32 pixels de altura e o arquivo de cenário tem 44 colunas e 30 linhas de descrição, teremos um cenário de 1320 pixels de largura e 960 pixels de altura.
Exemplo de uma arquivo '.scn'.
2
tile.png
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
%
background.jpg
3 - Funções de movimentação
Para mover um cenário de acordo com um referencial e aplicar esse deslocamento a todos os objetos dinâmicos usamos as seguintes funções:
//Desenha os tiles do cenário que estiverem ao redor do GameObject
//passado e dentro dos limites das dimensões da janela.
public void moveScene(GameObject object);
//Retorna o quanto o cenário se moveu no eixo x.
public double getXOffset();
//Retorna o quanto o cenário se moveu no eixo y.
public double getYOffset();
4 - Centralizando um objeto.
Para movimentar o cenário de forma a centralizar um determinado objeto e repassar essa movimentação a todos os objetos dinâmicos, usamos as funções anteriores da seguinte forma:
//Desenha todos os tiles que estiverem ao redor do jogador,
//e em seguida atualiza sua posição com o "deslocamento" do cenário.
scene.moveScene(player);
player.x += scene.getXOffset();
player.y += scene.getYOffset();
window.update();
Através dessa sequência de funções é possível causar a impressão de que há uma câmera seguindo o jogador.
Obs.: Como já foi mencionado, é necessário aplicar a atualização do posicionamento a cada objeto dinâmico, embora neste caso isso tenha sido feito apenas para o jogador.
5 - Delimitando as áreas percorríveis.
Para fazer, por exemplo, um jogo de plataforma temos que tratar as colisões que ocorrerão entre o personagem e os tiles que correspondem às paredes:
Continuaremos seguindo os mesmos passos do tutorial de cenários, mas agora com um novo tratamento de colisões:
//Retorna as imagens que estiverem na mesma área do player (x,y), (x + largura, y + altura)
Vector tiles = scene.getTilesFromPosition(playerMin, playerMax);
player.setFloor(window.getHeight());
//para todos os tiles
for(int i = 0 ; i < tiles.size() ; i++)
{
TileInfo tile = (TileInfo)tiles.elementAt(i);
//se o tile é parede e o player colidiu com ele
if((tile.id == Constante.TILE_WALL) && player.collided(tile))
{
//A colisão com o jogador foi na vertical?
if (VerticalCollision (player, tile))
{
if(tile.y + tile.height + player.getVelocityY() - player.getMovementSpeed() - 1 < player.y)
{
//o player está abaixo da parede
player.y = tile.y + tile.height;//Reposiciona o player
player.setVelocityY(0.0);
}
else if (tile.y > player.y + player.height - player.getVelocityY() - player.getMovementSpeed() - 1)
{
//o player está acima da parede
player.setVelocityY(0.0);
player.setFloor((int)tile.y);
player.y = tile.y - player.height ;//Reposiciona o player
}
}
//O jogador está se movendo na horizontal? A colisão foi na horizontal?
if((player.moveuNaHorizontal()) && (HorizontalCollision(player, tile))){
//o player está atrás da parede?
if(player.x <= tile.x - player.getMovementSpeed()- 1)
player.x = tile.x - player.width;//Reposiciona o player
else
//o player está na frente da parede
player.x = tile.x + tile.width;//Reposiciona o player
}
}
}
boolean VerticalCollision (GameObject object, TileInfo tile)
{
if (tile.x + tile.width <= object.x)
return false;
if (object.x + object.width <= tile.x)
return false;
return true;
}
boolean HorizontalCollision (GameObject object, TileInfo tile)
{
if (tile.y + tile.height <= object.y)
return false;
if (object.y + object.height <= tile.y)
return false;
return true;
}
A função getVelocityY() retorna a velocidade vertical com a qual o jogador está se movendo, causada pela função de pulo (jump()).
A função getMovementSpeed() não consta na classe sprite e foi implementada no caso para retornar o quanto o jogador se desloca por efeito dos controles.
As funções VerticalCollision() e HorizontalCollision() por si só não retornam o fato de ter ocorrido ou não uma colisão na vertical e na horizontal.
A princípio deve ser usada a função collided(), que retornará true caso tenha ocorrido uma colisão e então usar aquelas funções para saber por onde ocorreu a colisão.