Uai ! em ateh map scroll hehehe, bem parte das minhas reflexões sobre a forma de implementar o jogo estão se materalizando, criei o conceito de cena, contendo o gerenciador de eventos e deslocamento da tela para permitir o scroll da tela de fundo.

o primeiro detalhe eh a classe Scene em si

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace ChickenMaze
{
public abstract class Scene
{
public Game game;
public EventManager eventManager;
public int X;
public int Y;

public Scene(Game game, EventManager eventManager)
{
this.game= game;
this.eventManager= eventManager;
this.X = 0;
this.Y = 0;
}

public abstract void Initialize();
public abstract void LoadContent();
public abstract void Draw(GameTime gameTime, SpriteBatch spriteBatch);

}
}

que em alguns aspectos tentei manter o design semelhante a classe Game, com excessão do método Draw que adicionei o objeto spriteBatch sendo passado como parâmetro para evitar esta complexidade na cena atual, assim na classe Game principal do jogo um objeto scene é criado, e ao executar initialize, loadcontent e draw os respectivos metodos da Scene corrente serão chamados.

Esta abaixo eh a SceneMainMaze que determina os detalhes especificos do jogo, como sprite que vai ser usado como personagem, mapa e tratadores de eventos, note que a implementação dos eventos fica separada deste código.

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace ChickenMaze
{
class SceneMainMaze : Scene
{
Sprite chicken;
Map map;

public SceneMainMaze(Game game, EventManager eventManager)
: base(game, eventManager)
{

}

public override void Initialize(){

map = new Map(this);
chicken = new Sprite(“chicken”, this);
chicken.Position = map.GetFirstFreeSpot();
chicken.SetMap(map);

eventManager.addHandler(new EventCantMoveHere(this));
eventManager.addHandler(new EventKeyboardLeft(this, chicken, map));
eventManager.addHandler(new EventKeyboardRight(this, chicken, map));
eventManager.addHandler(new EventKeyboardUp(this, chicken, map));
eventManager.addHandler(new EventKeyboardDown(this, chicken, map));
eventManager.addHandler(new EventNeedScrollMap(this, chicken, map ));
}

public override void LoadContent()
{
chicken.LoadContent(game.Content);
map.LoadContent(game.Content);
}

public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
Color color = new Color(0, 136, 0);
game.GraphicsDevice.Clear(color);

map.Draw(spriteBatch);
chicken.Draw(spriteBatch);
}
}
}

Então o trecho abaixo mostra como os eventos são registrados para que ao serem disparados, o tipo de evento é testado e em seguida o métido run() dos eventos é executado

eventManager.addHandler(new EventKeyboardDown(this, chicken, map));
eventManager.addHandler(new EventNeedScrollMap(this, chicken, map ));

O código abaixo é o tratador de eventos para quando o scroll de mapa eh necessário

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace ChickenMaze
{
class EventNeedScrollMap: EventHandler
{
protected Sprite sprite;
protected Map map;

protected int HorizontalBorderLimit;
protected int VerticalBorderLimit;

const byte BORDER_DIVISION_INDEX = 4;

public EventNeedScrollMap(Scene scene, Sprite sprite, Map map)
: base(EventHandler.EventType.SPRITE_MOVED, scene)
{
this.sprite = sprite;
this.map = map;

HorizontalBorderLimit = scene.game.GraphicsDevice.Viewport.Width / BORDER_DIVISION_INDEX;
VerticalBorderLimit = scene.game.GraphicsDevice.Viewport.Height / BORDER_DIVISION_INDEX;
}

///

/// if the sprite is close to the border of the viewport,
/// for each direction of the movement change the viewport
/// of the GraphicsDevice
///

/// public override void run(Object source) {

int SceneShift = sprite.speed;
int x = (int)sprite.Position.X – scene.X;
int y = (int)sprite.Position.Y – scene.Y;

// into left limit
if (x < scene.game.GraphicsDevice.Viewport.X + HorizontalBorderLimit)
{
if (scene.X - SceneShift > 0)
{
scene.X -= SceneShift;
}
}

// into right limit
if (x > scene.game.GraphicsDevice.Viewport.X
+ scene.game.GraphicsDevice.Viewport.Width – HorizontalBorderLimit)
{
scene.X += SceneShift;
}

// into top limit
if (y < scene.game.GraphicsDevice.Viewport.Y + VerticalBorderLimit)
{
if (scene.Y - SceneShift > 0)
{
scene.Y -= SceneShift;
}
}

// into bottom limit
if (y > scene.game.GraphicsDevice.Viewport.Y
+ scene.game.GraphicsDevice.Viewport.Height – VerticalBorderLimit)
{
scene.Y += SceneShift;
}

}

}
}

Desta maneira tratadores de evento podem ser facilmente reaproveitados entre jogos, e inclusive escrever código para realizar testes destes tratadores.

os próximos passos são :

  • carregar o mapa de uma arquivo
  • determinar que a galinha chegou no fim do mapa e criar evento para isto
  • adicionar sons
  • adicionar timer na tela
  • adicionar os marcadores de labirinto com ovos (1 ovo a cada 10 segundos com duração de 60 segundos cada)
  • adciionar cena de tela inicial
  • adicionar cena de pontuação