Parallax Scrolling é um tipo de Scrolling em que várias camadas (que podem ser formadas por tiles) movem-se em velocidades diferentes, dando a impressão de profundidade. Essa técnica é utilizada para aumentar o realismo do jogo.
Jogos como Super Mario World e Megaman X utilizam essa técnica.
A idéia principal dessa técnica é que as camadas mais distantes se movimentam mais lentamente.
O cálculo da velocidade de deslocamento das camadas pode ser feito utilizando-se as dimensões da camada principal (onde ocorre a ação), da seguinte forma:
· Velocidade Scrolling X = Largura da Camada N / Largura da Camada Principal
· Velocidade Scrolling Y = Altura da Camada N / Altura da Camada Principal
No nosso exemplo, vamos utilizar quatro camadas (as imagens foram retiradas de http://en.wikipedia.org/wiki/Parallax_scrolling): Céu, Montanhas, Grama e Principal.




Vamos criar a classa ParallaxLayer, que representará cada camada:
public class ParallaxLayer
{
private Texture2D imagem;
private Vector2 posicao;
private Vector2 velocidade;
public Vector2 Posicao
{
get { return this.posicao; }
set { this.posicao = value; }
}
public ParallaxLayer(float velX, float velY)
{
this.posicao = new Vector2(0, 0);
this.velocidade = new Vector2(velX, velY);
}
public void LoadContent(ContentManager content, string filename)
{
this.imagem = content.Load<Texture2D>(filename);
}
public void Update(GameTime gameTime)
{
float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
this.posicao.X -= this.velocidade.X * deltaTime;
this.posicao.X = this.posicao.X % this.imagem.Width;
}
public void Draw(SpriteBatch batch)
{
batch.Draw(this.imagem, this.posicao, Color.White);
batch.Draw(this.imagem, new Vector2(this.posicao.X + this.imagem.Width, 0), Color.White);
}
}
O método Update atualiza a posição da camada. Observe a linha :
this.posicao.X = this.posicao.X % this.imagem.Width;
ela especifica que a nossa camada fique “presa” e repita o seu movimento sem sair da tela.
O método Draw desenha nossa camada na tela. Ele desenha a camada duas vezes. A primeira, na posição atual e a segunda no fim da camada (depois da largura da imagem), dando um efeito de continuidade. Assim, nossa camada se repete sempre que chega ao final.
Agora, na Classe Game, faça:
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//lista de camadas
List<ParallaxLayer> layers;
//velocidade de movimentação da camada principal
float velocidadePrincipal = 100f;
//velocidade da camada de montanhas
float velocidadeMontanhas = 0.3f;
//velocidade da camada de grama
float velocidadeGrama = 0.85f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
//define a largura da tela
graphics.PreferredBackBufferWidth = 640;
//define a altura da tela
graphics.PreferredBackBufferHeight = 400;
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
this.layers = new List<ParallaxLayer>();
ParallaxLayer background = new ParallaxLayer(0, 0);
//cria a camada de montanhas
ParallaxLayer montanhas = new ParallaxLayer(velocidadePrincipal * velocidadeMontanhas, 0);
//cria a camda de grama
ParallaxLayer grama = new ParallaxLayer(velocidadePrincipal * velocidadeGrama, 0);
//cria a camada principal (árvores)
ParallaxLayer basica = new ParallaxLayer(velocidadePrincipal, 0);
//adiciona as camadas
this.layers.Add(background);
this.layers.Add(montanhas);
this.layers.Add(grama);
this.layers.Add(basica);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//carrega as imagens das camadas
this.layers[0].LoadContent(Content, @"Imagens/ceu");
this.layers[1].LoadContent(Content, @"Imagens/montanhas");
this.layers[2].LoadContent(Content, @"Imagens/grama");
this.layers[3].LoadContent(Content, @"Imagens/principal");
}
protected override void Update(GameTime gameTime)
{
foreach (ParallaxLayer layer in this.layers)
{
layer.Update(gameTime);
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//desenha as camadas na tela
foreach (ParallaxLayer layer in this.layers)
{
layer.Draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Criamos uma Lista de Camadas, adicionamos as quatro camadas à lista e definimos a velocidade de cada uma delas.
Utilizamos o foreach (ParallaxLayer layer in this.layers), nos métodos Update e Draw, para percorrer a lista, atualizando e desenhando cada camada. Note que criamos uma ordem de impressão: a camada mais distante é a primeira a ser impressa e, portanto, será a mais lenta.
A montagem do cenário fica da seguinte forma:

Nosso projeto está pronto!
Download do Projeto:
cid-7e0cd7f2de37453e.skydrive.live.com/self.aspx/XNA/Parallax%20Scrolling.zip