Ponto V!

Home XNA XNA Componente reutilizável para medir o Frame Rate (FPS) de jogos no XNA
Kléber de Oliveira Andrade
Componente reutilizável para medir o Frame Rate (FPS) de jogos no XNAImprimir
Escrito por Kleber Andrade

Neste artigo veremos como criar um componente reutilizável (GameComponent) para calcular os quadros por segundos (FPS) de um jogo desenvolvido em XNA. Este componente foi testado no XNA 3.1 e qualquer mudança de versão pode acarretar ou não no funcionamento do mesmo. Este artigo assume que o leitor já tenha os conhecimentos básicos de C# e XNA.

Introdução

Frame Rate (FPS – Frames Per Second) significa o número de quadros registrados, ou processados, ou exibidos por um dispositivo por uma unidade de tempo qualquer. Normalmente é expresso por quadros por segundos (FPS) e em monitores progressive-scan como hertz (Hz). Este tipo de medida é muito utilizado como instrumento de comparação para medir o desempenho das Placas de vídeos que é considerado muito importante nos vídeos games.

Nem todos os jogos precisão de altas taxas de fps, sendo considerado um mínimo entre 30 e 60 fps aceitável, mesmo que isto possa variar consideravelmente de jogo para jogo. Como assim, pode variar de jogo para jogo? Vamos pensar num jogo de cartas, este tipo de jogo não há necessidade de manter um FPS alto o tempo todo, pois você pode usar esse tempo para processar outras coisas mais importantes como Inteligência Artificial. Agora em jogos online e em outros jogos, a quantidade de FPS é muito importante como por exemplo nos jogos em primeira pessoa.

Calculando o Frame Rate de um jogo

Para medir a quantidade de FPS do seu jogo, você precisará armazenar a cada chamada a cada atualização do seu jogo o tempo passado e um contador que irá armazenar quantas vezes o jogo foi atualizado. Logo, quando o tempo passado for maior ou igual a 1 segundo, significa que a quantidade de quadros exibidos é à quantidade contada, então para continuar contando você deve zerar o contador e subtrair 1 segundo do tempo passado, pois se você zerar o tempo, provavelmente você vai ter perdido alguns milissegundos que a variável que armazena o tempo pode conter.

O primeiro passo então seria criar as variáveis necessárias para armazenamento do tempo passado, da quantidade de quadros e do total e dos fps do jogo.

private TimeSpan elapsedTime = new TimeSpan();
private byte totalFrames = 0;
private byte frameRate = 0;

Agora no método Update o código ficaria desta forma

public void Update(GameTime gameTime)
{
    elapsedTime += gameTime.ElapsedGameTime;
    totalFrames++;
    if (elapsedTime >= TimeSpan.FromSeconds(1))
    {
        frameRate = totalFrames;
        totalFrames = 0;
        elapsedTime -= TimeSpan.FromSeconds(1);
    }
}

Muito fácil não ? mas agora vamos tentar fazer um código totalmente reutilizável.

Projeto do nosso componente reutilizável

Os componentes são instrumentos muito úteis para o desenvolvimento modular no XNA, com ele é possível criar ferramentas sem ter dependência alguma da arquitetura a ser usada no jogo. Uma observação interessante é que ao utilizar componentes, a perca de desempenho é inevitável, ou seja, se o seu objetivo não é perder desempenho não vale à pena utilizar Components, sem contar que se o seu jogo tiver muitos componentes provavelmente você vai se perder em alguma parte.

Existem dois tipos de Game Components no XNA: o GameComponent, que é um componente comum que não executa operações de desenho e o DrawableGameComponent que possui um método Draw e pode ser desenhado. No nosso caso, iremos usar um DrawableGameComponent para deixar o componente o mais independente possível. Mais detalhes sobre os tipos de componentes ficaram para um outro artigo.

Na figura abaixo é exibido o projeto do nosso componente.clip_image002

Após analisar o projeto, vamos começar então a programar.

Programando o componente de FPS

1º Passo: Crie uma classe para o componente, no meu caso chamarei de “FrameRateCounter. Definiremos uma namespace adequada para nossa classe como pode ser visto no código abaixo junto com a classe derivada de DrawableGameComponet.

namespace Utils.Componentes.FrameRateCounter
{
    /// 
    /// Componente de contador de FPS (Frames por Segundo)
    /// 
    public class FrameRateCounter : DrawableGameComponent    
    {

    }        
} 

2º Passo: Logo após, devemos então criar as variáveis necessárias para este componente.

#region [ Fields ]
/// 
/// SpriteBatch utilizado para escrever e/ou desenhar na tela
/// 
private SpriteBatch spriteBatch = null;

/// 
/// SpriteFont para escrever
/// 
private SpriteFont font = null;

/// 
/// Nome da SpriteFont à ser carregada
/// 
private string fontName;

/// 
/// Cor do texto a ser desenhado na tela
/// 
public Color Color
{
    get { return color; }
    set { color = value; }
}
private Color color = Color.White;

/// 
/// Armazena o total de tempo (segundos) passados desde o último update
/// 
private TimeSpan elapsedTime = new TimeSpan();

/// 
/// Armazena o número total de frames
/// 
private byte totalFrames = 0;

/// 
/// Armazena o total de FPS (Frames Por Segundo)
/// 
private byte frameRate = 0;

/// 
/// Vetor para armazenar a posição do texto na tela
/// 
public Vector2 Position
{
    set { position = value; }
    get { return position; }
}
private Vector2 position = new Vector2(10.0f, 10.0f);
#endregion 

3º Passo: Vamos criar agora o construtor dessa classe e também algumas sobrecargas para o mesmo, mantendo um componente maleável.

#region [ Constructor ]

/// 
/// Construtor do componente contador de FPS (Frames por Segundo)
/// 
/// Referência do jogo que o chamou
/// Nome da SpriteFont ou caminho a ser carregado
public FrameRateCounter(Game game, string fontName)
    : base(game)
{
    this.fontName = fontName;
}

/// 
/// Construtor do componente contador de FPS (Frames por Segundo)
/// 
/// Referência do jogo que o chamou
/// Nome da SpriteFont ou caminho a ser carregado
/// Cor do Texto que sera escrito na tela
public FrameRateCounter(Game game, string fontName, Color color)
    : base(game)
{
    this.fontName = fontName;
    Color = color;
}

/// 
/// Construtor do componente contador de FPS (Frames por Segundo)
/// 
/// Referência do jogo que o chamou
/// Nome da SpriteFont ou caminho a ser carregado
/// Cor do Texto que sera escrito na tela
/// Posição do Texto à ser desenhado
public FrameRateCounter(Game game, string fontName, Color color, Vector2 position)
    : base(game)
{
    this.fontName = fontName;
    Color = color;
    Position = position;
}
#endregion

4º Passo: Com os construtores implementados, precisamos então criar o nosso SpriteBatch para escrever o texto na tela e também carregar a SpriteFont. Note que este método utiliza a palavra override, o que significa que estamos utilizando o mecanismo de polimorfismo.

#region [ Load Content ]
/// 
/// Carrega o conteúdo necessário para que o componente funcione
/// 
protected override void LoadContent()
{
    // Tenta receber um serviço do tipo SpriteBatch do jogo
    spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
    if (spriteBatch == null)
    {
        // Cria uma nova SpriteBatch, que pode ser usada
        spriteBatch = new SpriteBatch(Game.GraphicsDevice);
    }
    // Carrega a font para escrever o texto
    if (!string.IsNullOrEmpty(fontName))
        font = Game.Content.Load(fontName);
}
#endregion

5º Passo: Lembram do nosso método Update? aqui iremos copiar ele, porém utilizaremos também a palavra override para o método.

#region [ Update ]
/// 
/// Método que atualiza o componente
/// 
/// Referência para o tempo de jogo
public override void Update(GameTime gameTime)
{
    // Recebe o tempo passado deste a última chamada
    elapsedTime += gameTime.ElapsedGameTime;
    // Incrementa o total de frames por segundos, uma vez
    // que este método está sendo chamado novamente
    totalFrames++;
    // Verifica se o tempo passado (elapsedTime) é maior que
    // 1 segundo
    if (elapsedTime >= TimeSpan.FromSeconds(1))
    {
        // Se o tempo passado for maior ou igual a 1 segundo,
        // definimos então a variavel frameRate com a quantidade
        // total de frames exibido na tela da variavel totalFrames
        frameRate = totalFrames;
        // Logo após zeramos a variável que guardava o total de frames,
        // para começar a recontagem e verificar se houve mudanças
        totalFrames = 0;
        // Retiramos 1 segundo da variável que armazena o tempo passado,
        // pois pode ser que este tempo tenha passado de 1 segundo.
        elapsedTime -= TimeSpan.FromSeconds(1);
    }
}
#endregion

6º Passo: Por último, iremos desenhar então a informação da quantidade de FPS na tela do jogo. Note novamente que o método é escrito usando override.

#region [ Draw ]
/// 
/// Método para desenhar a quantidade de Frames por Segundos
/// 
/// Referência para o tempo de jogo
public override void Draw(GameTime gameTime)
{
    // Armazena uma string indicando a quantidade de FPS
    string fps = string.Format("FPS: {0}", frameRate);
    // Inicializa o SpriteBatch para desenhar
    spriteBatch.Begin();
    // Escreve o FPS na tela
    spriteBatch.DrawString(font, fps, position, color);
    // Finaliza o SpriteBatch
    spriteBatch.End();
}
#endregion 

Pronto, nosso componente esta concluído, agora precisamos testar ele em nosso jogo.

Usando o componente de FPS no meu jogo

1º Passo: Adicione a classe FrameRanteCounter.cs no seu projeto.

2º Passo: Crie um SpriteFont para que o componente possa escrever na tela a taxa de FPS. Chamarei minha font de “fpsFont”, veja um exemplo de arquivo spritefont abaixo usando font arial e tamanho 14.



  
    Arial
    14
    0
    true
    
    
      
         
        ~
      
    
  

3º Passo: Adicione a namespace do componente na sua classe que irá declarar o objeto.

using Utils.Componentes.FrameRateCounter;

4º passo: Inicialize o objeto e adicione a lista de GameComponents do jogo, veja o exemplo abaixo, no qual o componente é adicionado na classe principal do jogo (Game1.cs).

Observação: Faça isso no método Initialize.

protected override void Initialize()
{
    // TODO: Add your initialization logic here
    FrameRateCounter FPSCounter = new FrameRateCounter(this, "fpsFont");
    Components.Add(FPSCounter);
    base.Initialize();
}

5º passo: Pronto agora é só compilar (F5) seu projeto e ver o componente de FPS em ação.

clip_image004

Download do Componente de FPS

Para fazer download deste componente e utilizar em seus jogos clique na imagem abaixo.

download

Conclusão

Espero que este componente seja muito útil para seus jogos, uma vez que ele o ajudará a medir a taxa de fps do seu jogo e também é de fácil utilização. Qualquer melhoria no componente poderá ser sugerida por vocês, para mantermos o componente atualizado para todos.


Comentários (4)
  • Felipe A. Pires  - Parabéns
    avatar

    Kleber, parabéns por essa nova fase virtual.
    O tutorial ficou excelente, muito fácil de se entender.
    Que venham mais tutoriais assim...

  • Kleber Andrade
    avatar

    Obrigado Felipe, logo virá novos tutoriais com certeza.

  • Jonathan Araujo
    avatar

    Ótimo artigo.

    Legal mexi muito pouco com XNA, tem bastante coisa legal, e sempre gosto de ler sobre.

    Assim que eu sobra um tempo voltarei a programar com XNA :)

  • Kleber Andrade
    avatar

    Obrigado Jonathan, volte sim, logo teremos mais tutoriais de XNA.

    Abraços,

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter