Artigo
Criando um ambiente para 2 players com XNA
Dividindo a tela ao meio, no formato horizontal, obtendo 2 Viewports
Enviado por Luciano José em 27/4/2008 19:00:17

Introdução

 Este artigo vai tentar cobrir a criação de um ambiente na mesma tela do Monitor, para 2 players.

As telas que serão preparadas, estarão no formato horizontal; as 2  telas estarão no formato retangular, sendo o “pedaço da tela” de cima sendo do player 1, e o “pedaço da tela” de baixo sendo do player 2. 

O objeto Viewport 

Para um ambiente 2D puro e aquele em que os objetos são renderizados na tela através do objeto SpriteBatch – as principais propriedades de um objeto ViewPort são:
 
  • Viewport.X
  • Viewport.Y
  • Viewport.Width
  • Viewport.Height
 

Viewport.Width e Viewport.Height

 
Por padrão(inicialmente), qualquer jogo, criado no XNA, tem objetos sendo renderizados em uma janela(já provida pelo XNA FrameWork) com dimensões 800x600(800 pixels de largura(width) e 600 pixels de altura(height)).
 
O local em que os objetos são renderizados na tela, não está restrito ao tamanho da janela(Game Window), mas quem determina esse comportamento, é o objeto Viewport atribuído ao GraphicsDevice do jogo.
 
As propriedades Viewport.Width e Viewport.Height determinam o local aonde os objetos são renderizados na tela, por meio das dimensões de altura e largura da superfície em que são esperados os objetos a serem renderizados.
 

Viewport.X e Viewport.Y

 
Os objetos a serem renderizados na tela, são posicionados na tela, de acordo com a origem. Viewport.X e Viewport.Y determinam essa origem e os objetos quando renderizados na tela, são posicionados em relação a origem determinada.
 
Origem é o local em que os eixos se cruzam.
 
Por padrão, Viewport.X e Viewport.Y têm o valor 0(zero). Então temos o seguinte ambiente:

 

 

Foto 1 – Demonstração das dimensões e a origem da superfície em que objetos são, por padrão, renderizados

 

Ambiente para 2 players

 
Ao preparar um ambiente tanto para 2 players ou até mesmo, mais de 2 divisões na tela, tenha em mente que você precisará modificar os valores do Viewport atribuído ao GraphicsDevice do jogo.
 
O Viewport de um GraphicsDevice é acessado através de propriedade. Viewport é uma estrutura(struct). Tenha em mente que estruturas, quando acessadas através de propriedades, não podem ter os valores de seus campos modificados diretamente. Então, para preparar um ambiente para X players, será necessário o uso de um Viewport auxiliar. A preparação do ambiente será feita nesse Viewport auxiliar e após modificar os campos nesse Viewport auxiliar, daí então, será atribuído esse Viewport auxiliar ao Viewport do GraphicsDevice.
 
Inicialmente declara-se o viewPort auxiliar:
 
...
///
      /// objeto auxiliador, para definir as dimensões das 2 telas dos players
      ///
      Viewport viewPort;
...
 
Especificamente para esta demonstração, será necessário guardar a altura inicial do Viewport. Confira os comentários no sumário:
 
///
      /// Guarda a altura inicial da tela. Objeto iniciado antes das
      /// divisões das telas dos players; no metodo Initialize.
      /// Será util para "resetar" a altura do "ViewPort";
      /// preservando a altura inicial(antes das divisões) para a proxima
      /// passagem no metodo Draw
      ///
      int heightViewPort;
 
 
O uso desses objetos auxiliares, vai depender diretamente da quantidade de “sub-telas” que você quer obter em seu jogo. Lembre-se que o que está sendo demonstrado, é uma tela com “2 sub-telas” no formato horizontal; um ambiente para 2 players.
 
No método Initialize, temos a inicialização do Viewport auxiliar com o Viewport atual do jogo e também será guardado a altura original do Viewport:
 
protected override void Initialize()
        {
            ...
          this.viewPort = this.GraphicsDevice.Viewport;
 
          this.heightViewPort = this.viewPort.Height;
      }
 
A preparação das telas dos players, acontece de fato, no método Draw:
 
 
protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
          //configurando as dimensões da tela(o ViewPort) para o player 1
          //Neste momento, a tela do player 1, fica com um formato retangular
          this.viewPort.Height = viewPort.Height / 2;
          this.GraphicsDevice.Viewport = viewPort;          
 
Neste momento, a superfície que recebe os objetos a serem renderizados na tela, está com o seu Viewport com origem (0, 0) em relação a janela(Game Window), e com uma área retangular de 800x300. A foto abaixo demonstra isso:
 
 
 
 
 
          //Desenhando na tela o player 1 e tudo relativo a tela dele
          this.spriteBatch.Begin();          
          this.spriteBatch.Draw(this.player1, position1, Color.Red);
          this.spriteBatch.End();
 
          //configurando as dimensões da tela(o ViewPort) para o player 2
          this.viewPort.Y = viewPort.Height;          
          this.GraphicsDevice.Viewport = viewPort;
 
Agora, neste momento, a superfície que recebe os objetos a serem renderizado na tela, está ocupando uma área retangular, com origem (0, 300) em relação a janela(Game Window), e com uma área retangular de 800x300. A foto abaixo demonstra isso:
 
 
          //Desenhando na tela o player 2 e tudo relativo a tela dele
          this.spriteBatch.Begin();          
          this.spriteBatch.Draw(this.player2, position2, Color.CornflowerBlue);
          this.spriteBatch.End();
 
Agora, será necessário preparar o ambiente para a próxima passagem no método Draw. O melhor a fazer é reinicializar as dimensões da superfície. O código abaixo faz isso:
 
          //Reinicializando as dimensões da tela, para a configuração inicial(normal)
 
          this.viewPort.Y = 0;
          this.viewPort.Height = this.heightViewPort;
          this.GraphicsDevice.Viewport = viewPort;
            
          base.Draw(gameTime);
      }
 

O código completo:

///
  /// Neste "Game", a região superior da tela, pertence ao player 1. Já a parte
  /// inferior(a parte de baixo), pertence ao player 2.
  ///
  /// Para movimentar o player 1 utilize as teclas: W, A, S e D
  /// Para movimentar o player 2 utilize as SETAS
  ///  public class Game1 : Microsoft.Xna.Framework.Game
    {
      GraphicsDeviceManager graphics;
 
      SpriteBatch spriteBatch;
        
      ///
      /// textura que vai ficar na parte de cima da tela
      ///
      Texture2D player1;
 
      ///
      /// textura que vai ficar na parte de baixo da tela
      ///
      Texture2D player2;
 
      ///
      /// objeto auxiliador, para definir as dimensões das 2 telas dos players
      ///
      Viewport viewPort;
      
      ///
      /// Guarda a altura inicial da tela. Objeto iniciado antes das
      /// divisões das telas dos players; no metodo Initialize.
      /// Será util para "resetar" a altura do "ViewPort";
      /// preservando a altura inicial(antes das divisões) para a proxima
      /// passagem no metodo Draw
        ///
      int heightViewPort;
      
 
         ///
      /// posição do player 1
      ///
      Vector2 position1;
 
      ///
      /// posicao do player 2
      ///
      Vector2 position2;
 
      public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";            
        }
 
      protected override void Initialize()
        {
          this.position1 = new Vector2(0, 0);
          this.position2 = new Vector2(0, 0);          
 
          base.Initialize();
 
          this.viewPort = this.GraphicsDevice.Viewport; 
       
          this.heightViewPort = this.viewPort.Height;
        }
 
      protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
 
          this.player1 = this.Content.Load<Texture2D>("player1");
          this.player2 = this.Content.Load<Texture2D>("player2");
        }
 
      protected override void Update(GameTime gameTime)
        {
 
          KeyboardState keyboard = Keyboard.GetState();
 
            #region Controle do Player 1
 
          if (keyboard.IsKeyDown(Keys.W))
            {
                position1.Y -= 5;
            }
 
          if (keyboard.IsKeyDown(Keys.S))
            {
                position1.Y += 5;
            }
 
          if (keyboard.IsKeyDown(Keys.A))
            {
                position1.X -= 5;
            }
 
          if (keyboard.IsKeyDown(Keys.D))
            {
                position1.X += 5;
            }
            #endregion
 
            #region Controle do Player 2
 
            if (keyboard.IsKeyDown(Keys.Up))
            {
                position2.Y -= 5;
            }
 
          if (keyboard.IsKeyDown(Keys.Down))
            {
                position2.Y += 5;
            }
 
          if (keyboard.IsKeyDown(Keys.Left))
            {
                position2.X -= 5;
            }
 
          if (keyboard.IsKeyDown(Keys.Right))
          {
                position2.X += 5;
            }
            #endregion
 
          //Posições do player 1 e 2, sendo expostas na barra de titulo da janela
          this.Window.Title = "Player 1: " +
              this.position1 + " - Player 2: " + this.position2;
 
          base.Update(gameTime);
        }
 
      protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
          //configurando as dimensões da tela(o ViewPort) para o player 1
          //Neste momento, a tela do player 1, fica com um formato retangular
          this.viewPort.Height = viewPort.Height / 2;
          this.GraphicsDevice.Viewport = viewPort;          
 
          //Desenhando na tela o player 1 e tudo relativo a tela dele
          this.spriteBatch.Begin();          
          this.spriteBatch.Draw(this.player1, position1, Color.Red);
          this.spriteBatch.End();
 
          //configurando as dimensões da tela(o ViewPort) para o player 2
          this.viewPort.Y = viewPort.Height;
          
          this.GraphicsDevice.Viewport = viewPort;
 
          //Desenhando na tela o player 2 e tudo relativo a tela dele
          this.spriteBatch.Begin();          
          this.spriteBatch.Draw(this.player2, position2, Color.CornflowerBlue);
          this.spriteBatch.End();
 
          //Reinicializando as dimensões da tela, para a configuração inicial(normal)
          this.viewPort.Y = 0;
          this.viewPort.Height = this.heightViewPort;
          this.GraphicsDevice.Viewport = viewPort;
          
          base.Draw(gameTime);
      }
    }

Projeto para Download:  ambientepara2players.zip 468758 bytes

Atenção!!!

Observe que foram necessários 2 blocos(Begin/End do SpriteBatch) foram utilizados para renderização das texturas.
Caso o ambiente para o player 1 e 2, fosse preparado em torno de um único bloco (Begin/End), o resultado obtido seria algo totalmente diferente que a proposta em foco.
 
 
Algumas imagens do código acima:

 

Na foto abaixo, observe o que acontece quando o player 1 tenta descer, e o player 2 tenta subir. O objetivo era esse!!!

 
O resultado obtido ao final, me fez lembrar do modo para 2 players no jogo Sonic 2. E para você? Fez recordar algum jogo que proporcionou-lhe momentos bons e únicos?!?!

Todas as imagens acima, foram criadas e/ou editadas com a ferramenta Microsoft Expression Design 2 Beta. 

Dúvidas, Críticas e Sugestões são bem vindas.

Obrigado! 

 


Sobre o Autor

lucianoJose
Luciano José
MCP, MCTS. Administrador do SharpGames. Sou de Pernambuco! Meu Blog: lucianojosefj.spaces.live.com

Clique para avaliar:

Comentários

Adicione seu Comentário  Voltar
Translator
AdSense

Amazon

Logos do XBox 360, XNA e Games For Windows
Copyright 2008 por SharpgamesPolítica de Privacidade  |  Termos de Uso