quinta-feira, 24 de janeiro de 2013

Peça um artigo

Caso queira um artigo, basta que o peça aqui nesse post.

Até mais!

Estruturando um jogo: Propriedades de Objetos


Ryan Lindeman criou um simples e eficiente sistema que gerencia propriedades de objetos de forma fácil.
Para começar, salve o código daqui como header (.h).
Salve o código daqui como source (.cpp).
Salve o código daqui como header.
Salve o código daqui como source.
Salve o código daqui como header.
E um exemplo básico:
#include "PropertyManager.hpp"

int main(int argc, char* argv[])
{
  PropertyManager properties;

  // Adicionar uma propriedade
  properties.Add<sf::Clock>("AnimationClock", sf::Clock());

  // Adicionar uma propriedade
  properties.Add<sf::Sprite>("Sprite", sf::Sprite());

  // Adicionar uma propriedade
  properties.Add<bool>("Visible", true);

  // Testar uma propriedade
  if(properties.Get<bool>("Visible") == true)
  {
    // Desenhar uma sprite
    renderWindow.draw(properties.Get<sf::Sprite>("Sprite"));

    // Obter uma propriedade
    sf::Clock anClock = properties.Get<sf::Clock>("AnimationClock");

    // Reiniciar o relógio de animação
    anClock.reset();

    // Atribuindo valores
    properties.Set<sf::Clock>("AnimationClock", anClock);
  }

  // Se uma propriedade existe
  if(properties.HasID("NotExist"))
  {
    printf("It exists!\n");
  }
  else
  {
    printf("It doesn't exist\n");
  }

  return 0;
}
O que podemos notar é que há bastante código por trás de tudo isso, mas, no final das contas, usaremos bem menos códigos para usar o sistema.


Estruturando um jogo: Namespaces

1- Namespaces

Namespaces são muito importantes na organização de um projeto. Através deles, podemos categorizar os códigos. Por exemplo, códigos de sons ficam separados dos de imagens. Também podemos separar conforme o nome do programador, facilitando a identificação dos autores de cada trecho.

No header, fazemos algo do tipo:

namespace Pedro
{
  class MinhaClasse {
    public:
      MinhaClasse();
      virtual ~MinhaClasse();
  };
}
No source, fazemos algo do tipo:
namespace Pedro
{
  MinhaClasse::MinhaClasse()
  {
  }
 
  MinhaClasse::~MinhaClasse()
  {
  }
}
Além disso, podemos usar classes com nomes iguais em namespaces diferentes:
class MyClass {
  public:
    MyClass();
    virtual ~MyClass();
 
    sf::Clock mClock1;
    MyStuff::Clock mClock2;
};
Para que você não precise ficar digitando o nome de seu namespace a todo momento, você pode definir quais classes de quais namespaces você usará, de forma que precisa apenas digitar o nome da classe.
using Pedro::MyClass;
using sf::Clock;

Trabalhando com Textos


Fontes definem como será o visual do texto apresentado na tela. Existem muitas fontes, e você também pode criar a sua. Vamos ver um exemplo de como definir a fonte, estilo, tamanho e cor de um texto.

// Declara uma nova fonte
 sf::Font font;
 
 // Carrega a fonte de um arquivo
 font.loadFromFile("arial.ttf");
 
 // Cria um elemento de texto.
 sf::Text text1("Eu sou um texto.");

 // Define a fonte do texto
 text1.setFont(font);

 //Define o tamanho do texto
 text1.setCharacterSize(30);

 //Define o estilo do texto
 text1.setStyle(sf::Text::Italic);

 //Define a cor do texto
 text.setColor(sf::Color::Red);
Para desenhar o texto na tela, usamos:
window.draw(text1);



quarta-feira, 23 de janeiro de 2013

Trabalhando com Cores


A classe sf::Color manipula cores do sistema RGBA. É bem fácil trabalhar com ela:


sf::Color color(255, 0, 0); // vermelho
 color.red = 0;              // fica preto
 color.blue = 128;           // fira azul escuro

Algumas cores comuns já foram definidas pela SFML:

sf::Color black       = sf::Color::Black;
sf::Color white       = sf::Color::White;
sf::Color red         = sf::Color::Red;
sf::Color green       = sf::Color::Green;
sf::Color blue        = sf::Color::Blue;
sf::Color yellow      = sf::Color::Yellow;
sf::Color magenta     = sf::Color::Magenta;
sf::Color cyan        = sf::Color::Cyan;
sf::Color transparent = sf::Color::Transparent;


Esse é um artigo pequeno e fácil de entender. Faça bom proveito.

terça-feira, 22 de janeiro de 2013

Gravando áudio

Gravando para um buffer de som. O áudio capturado deve ser gravado em um buffer (sf::SoundBuffer), para que então possa ser tocado ou gravado em um arquivo.

// primeiro checar se um dispositivo de áudio está disponível
if (!SoundBufferRecorder::isAvailable())
{
}

// criar o gravador
SoundBufferRecorder recorder;

// começar a capturar
recorder.start();

// parar de capturar
recorder.stop();

// recuperar o buffer
const sf::SoundBuffer& buffer = recorder.getBuffer();

A captura ocorre em sua própria thread, o que significa que você pode fazer o que quiser entre o inicio e o fim dela, sem que seja interrompida.
  • Salvar em um arquivo
    buffer.saveToFile("my_record.ogg");
    
  • Tocar
    sf::Sound sound(buffer);
    sound.play();
    
  • Outros
    const sf::Int16* samples = buffer.getSamples();
    std::size_t count = buffer.getSampleCount();
    doSomething(samples, count);
Há também 2 funções adicionaisonStart e onStop. Estas são chamadas quando a captura começa/termina.
Você também pode criar o seu próprio gravador:
class MyRecorder : public sf::SoundRecorder
{
    virtual bool onStart()
    {
        return true;
    }

    virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount)
    {
        return true;
    }

    virtual void onStop()
    {
    }
}
if (!MyRecorder::isAvailable())
{
}

MyRecorder recorder;
recorder.start();
recorder.stop();

Reproduzindo áudio



A SFML provê 2 classes para reproduzir áudio: sf::Sound e sf::Music.
sf::Sound é um objeto leve que reproduz áudio carregado de um sf::SoundBuffer. Deve ser usado para sons pequenos.
sf::Music não carrega todo o áudio na memória, em vez disso, o reproduz direto do arquivo.
As classes sf::Sound e sf::SoundBuffer trabalham da mesma maneira que sf::Sprite/sf::Texture.
Você pode carregar um buffer de som de um arquivo com a sua função loadFromFile.
#include <SFML/Audio.hpp>

int main()
{
    sf::SoundBuffer buffer;
    if (!buffer.loadFromFile("sound.wav"))
        return -1;

    return 0;
}

Como de costume, você também pode carregar um arquivo de áudio da memória (loadFromMemory) ou de um stream de entrada personalizado (loadFromStream).
Os formatos de áudio suportados podem ser encontrados aqui.
Para reproduzir o som, devemos instanciar antes a sf::Sound.
sf::SoundBuffer buffer;

sf::Sound sound;
sound.setBuffer(buffer);
sound.play();

A melhor coisa é que você pode atribuir o mesmo buffer de som para vários sons, se assim quiser. Até mesmo pode reproduzi-los juntamente.
Sons e músicas são reproduzidos em uma thread separada. Ou seja, você pode fazer o que quiser depois de começar a tocar o som que ele não vai parar de tocar até que termine ou seja interrompido explicitamente.
Tocando uma música:
sf::Music music;
if (!music.openFromFile("music.ogg"))
    return -1; // erro
music.play();

Exemplos:
// tocar playback
sound.play();

// ir para o 2º segundo
sound.setPlayingOffset(sf::seconds(2));

// pausar playback
sound.pause();

// retomar playback
sound.play();

// parar playback e rebobinar
sound.stop();

O valor do volume vai de 0 (mudo) a 100 (máximo e padrão).
sound.setVolume(50);
O atributo loop define se o som/música repete ou não.
sound.setLoop(true);

Trabalhando com Teclado e Mouse - Parte II

Na primeira parte deste artigo, abordamos os eventos relacionados ao teclado e ao mouse. Neste segunda parte, veremos como verificar o estado das teclas/botões em tempo-real. Por exemplo, veremos se uma tecla escolhida está sendo pressionada, ao invés de sermos notificados que alguma tecla foi pressionada.

Teclado

A classe que dá acesso ao estado das teclas é a sf::Keyboard. Esta contém apenas uma funçãoisKeyPressed. Essa função checa o estado atual de uma tecla. Mesmo que a janela esteja sem foco, a função funciona.

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
    character.move(1, 0);
}

Códigos de teclas são definidos na enum sf::Keyboard::Key.
Mouse

A classe que dá acesso ao estado do mouse é a sf::Mouse.
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
    gun.fire();
}

Códigos de botões do mouse são definidos na enum sf::Mouse::Button. São 5 os botões: esquerdo, direito, roda e mais outros dois.
Você também obter/definir a posição atual do mouse, relativa ao desktop ou à janela.
// relativa ao desktop
sf::Vector2i globalPosition = sf::Mouse::getPosition();

// relativa à janela
sf::Vector2i localPosition = sf::Mouse::getPosition(window);
// relativa ao desktop
sf::Mouse::setPosition(sf::Vector2i(10, 50));

// relativa à janela
sf::Mouse::setPosition(sf::Vector2i(10, 50), window);

Concluindo o artigo, podemos notar que não é muito complicado trabalhar com teclado e mouse. É por isso que a SFML significa Simple and Fast Multimedia Library.

Trabalhando com Teclado e Mouse - Parte I


Os eventos sf::Event::KeyPressed e sf::Event::KeyReleased são desencadeados quando uma tecla é pressionada ou liberada. Se uma tecla está sendo pressionada, vários eventos KeyPressed serão gerados. Para desabilitar eventos KeyPressed repetidos, você pode usar a função window.setKeyRepeatEnabled(false).
Há um tutorial que mostra como manipular teclas pressionadas em tempo real (ao contrário desse evento, que tem um intervalo entre cada chamada). Você pode ler tanto este como o artigo presente aqui no site.
O membro associado a este evento é o event.key, que contém o código da tecla digitada/liberada.
if (event.type == sf::Event::KeyPressed)
{
    if (event.key.code == sf::Keyboard::Escape)
    {
        std::cout << "the escape key was pressed" << std::endl;
    }
}

O evento sf::Event::MouseWheelMoved é desencadeado quando a roda do mouse é movida. O membro associado a este evento é o event.mouseWheel, que contém a quantidade de movimento da roda e a posição atual do cursor.
if (event.type == sf::Event::MouseWheelMoved)
{
    std::cout << "wheel movement: " << event.mouseWheel.delta << std::endl;
    std::cout << "mouse x: " << event.mouseWheel.x << std::endl;
    std::cout << "mouse y: " << event.mouseWheel.y << std::endl;
}

Os eventos sf::Event::MouseButtonPressed e sf::Event::MouseButtonReleased são desencadeados quando o botão do mouse é pressionado/liberado. O membro associado é o event.mouseButton, que contém o código do botão pressionado/liberado e a posição atual do cursor.
if (event.type == sf::Event::MouseButtonPressed)
{
    if (event.mouseButton.button == sf::Mouse::Right)
    {
        std::cout << "the right button was pressed" << std::endl;
        std::cout << "mouse x: " << event.mouseButton.x << std::endl;
        std::cout << "mouse y: " << event.mouseButton.y << std::endl;
    }
}

O evento sf::Event::MouseMoved é desencadeado quando o mouse é movido dentro da janela (tendo esta foco ou não). O membro associado a este evento é o event.mouseMove, que contém a posição atual do cursor relativa à janela.
if (event.type == sf::Event::MouseMoved)
{
    std::cout << "new mouse x: " << event.mouseMove.x << std::endl;
    std::cout << "new mouse y: " << event.mouseMove.y << std::endl;
}

Os eventos sf::Event::MouseEntered e sf::Event::MouseLeft são desencadeados quando o cursor do mouse entra/sai da janela.
if (event.type == sf::Event::MouseEntered)
    std::cout << "the mouse cursor has entered the window" << std::endl;

if (event.type == sf::Event::MouseLeft)
    std::cout << "the mouse cursor has left the window" << std::endl;

Trabalhando com eventos


Para começar, é necessário que  conheçamos o tipo sf::Event. Basicamente, é uma união. Isto significa que apenas um dos seus membros é válido em certo instante. O membro válido é o que corresponde ao tipo de evento. Em palavras mais simples, se o evento for o KeyPressed, então você terá que usar um membro correspondente, no caso o event.key.
sf::Event possui a função pollEvent (da classe sf::Window). Esta deve ser chamada antes de gerenciar os eventos. Exemplo:
sf::Event event;

// enquanto houver novos eventos
while (window.pollEvent(event))
{
    // ver o tipo
    switch (event.type)
    {
        // evento fechar janela
        case sf::Event::Closed:
            window.close();
            break;

        // evento tecla pressionada
        case sf::Event::KeyPressed:
            break;

        // eventos que não tratamos
        default:
            break;
    }
}


O evento sf::Event::Closed é desencadeado quando o usuário tenta fechar a janela (seja pelo teclado ou clicando no botão fechar). Tipicamente é usada a função window.close(). Mas você pode fazer outras coisas antes, como salvar o estado atual ou confirmar o fechamento. Se você não fizer nada, a janela fica aberta.
O evento sf::Event::Resized é desencadeado quando o programador ou o usuário redimensiona a janela. O membro associado a esse evento é o event.size, que contém o novo tamanho da janela. Exemplo:
if (event.type == sf::Event::Resized)
{
    std::cout << "new width: " << event.size.width << std::endl;
    std::cout << "new height: " << event.size.height << std::endl;
}

Os eventos sf::Event::LostFocus e sf::Event::GainedFocus são desencadeados quando a janela ganha ou perde o foco (neste caso ela não reconhece as teclas pressionadas). Não há membros associados a esse evento. Exemplo:
if (event.type == sf::Event::LostFocus)
    myGame.pause();

if (event.type == sf::Event::GainedFocus)
    myGame.resume();

O evento sf::Event::TextEntered é desencadeado quando um caractere é digitado. Há uma diferença entre este evento e o evento KeyPressed: o primeiro interpreta o caractere como um todo, então se for pressionar a tecla de um acento, não vai acontecer nada até que você digite a letra a ser acentuada; já o segundo reconhece o pressionamento do acento como um evento e o da letra como outro.
O membro associado a este evento é o event.text, que contém o valor Unicode do caractere digitado. Você pode tanto colocá-lo em uma sf::String ou em um char.
if (event.type == sf::Event::TextEntered)
{
    if (event.text.unicode < 128)
        std::cout << "ASCII character typed: " << static_cast<char>(event.text.unicode) << std::endl;
}

Existem muitos eventos, que podem ser conferidos no guia oficial (sf::Event). No entanto, vamos tratar de mais alguns nos próximos artigos.

segunda-feira, 21 de janeiro de 2013

Trabalhando com janelas

A partir de agora, começamos a complicar um pouco as coisas. Mas não se assuste, pois veremos as coisas  com mais detalhes. Vamos ver como abrir e manejar uma janela.

 Abrir uma janela

Usaremos a classe sf::Window. Veja como é simples:
#include <SFML/Window.hpp>

int main()
{
    sf::Window window(sf::VideoMode(800, 600), "Titulo");

    return 0;
}

Bem, definimos o tamanho da janela (sem contar a barra de titulo e as bordas) e o seu título.
Você pode passar um terceiro argumento, que é uma combinação de estilos.
  • sf::Style::None: sem decoração, não combina com outros estilos
  • sf::Style::Titlebar: barra de titulos
  • sf::Style::Resize: redimensionável e botão maximizar
  • sf::Style::Close: botão fechar
  • sf::Style::Fullscreen: tela cheia, não combina com outros estilos
  • sf::Style::Default: estilo padrão, que é um atalho para Titlebar | Resize | Close
Há também um quarto argumento (opcional), que define opções específicas do OpenGL (tutorial).
Se você quiser criar a janela depois de já tê-la instanciado, ou então recriá-la com um modo de vídeo ou título diferente, você pode usar a função create, que usa os mesmos argumentos que o construtor.
#include <SFML/Window.hpp>

int main()
{
    sf::Window window;
    window.create(sf::VideoMode(600, 600), "Janela");

    return 0;
}

Modificando a janela:

// Mudar a posição window.setPosition(sf::Vector2i(10, 50)); //Mudar o tamanho window.setSize(sf::Vector2u(640, 480)); //Mudar o título window.setTitle("SFML window");

Controlando a taxa de atualização:
window.setVerticalSyncEnabled(true); //assim sua aplicação vai desenhar na mesma frequência que o monitor (geralmente 60 vezes por segundo)

ou

window.setFramerateLimit(30); //assim você define uma taxa máxima em vez de automatizar
Pegando dados:

//Obter o tamanho sf::Vector2u size = window.getSize(); unsigned int width = size.x; unsigned int height = size.y;

O que mais você poderia saber?

- Você pode criar várias janelas e manejá-las junta ou separadamente.
- Não é suportado o uso de vários monitores.

Veja mais: OpenGL na janelaReferência da classe sf::Window.

Trabalhando com tempo

É usada uma classe (sf::Time) para trabalhar com tempo na SFML. O valor pode ser de qualquer uma das seguintes unidades: segundos, milissegundos, microssegundos. No exemplo abaixo, todos os valores  representam 1 centésimo de segundo.

sf::Time t1 = sf::microseconds(10000);
sf::Time t2 = sf::milliseconds(10);
sf::Time t3 = sf::seconds(0.01f);

É possível fazer a conversão entre as unidades:

sf::Time time = sf::microseconds(10000);sf::Int32 msec = time.asMilliseconds();
float     sec  = time.asSeconds();

sf::Time é apenas uma quantidade de tempo, podendo ser negativa e sofrer operações matemáticas:

sf::Time t1 = sf::seconds(0.01f);
sf::Time t2 = t1 * 2;
sf::Time t3 = t1 + t2;
sf::Time t4 = -t3;

bool b1 = (t1 == t2);
bool b2 = (t3 > t4);

Para medir o tempo, vamos usar uma classe específica: sf::Clock. Essa possui 2 funções: getElapsedTime() e restart(). A primeira é descartável quando usamos a segunda:

//esses códigos
sf::Clock clock;
sf::Time elapsed1 = clock.getElapsedTime(); //retorna o tempo
clock.restart(); //reseta//dão no mesmo que os abaixo (que são mais práticos)
sf::Clock clock;
sf::Time elapsed1 = clock.restart(); //reseta e retorna o tempo
}

Configurar Code::Blocks para SFML

Vou explicar como configurar, de uma forma clara e fácil:

A- Supondo que você já compilou a SFML para a sua versão do MinGW, vou mostrar como usar a SFML  com o Code::Blocks.

B- A primeira coisa que você deve fazer é escolher que tipo de projeto criar (pelo menu File). No caso, escolha EMPTY PROJECT.

C- Agora vamos especificar ao programa como achar a SFML:

Caso você queira pular a etapa D, basta copiar as pastas Include e Lib da pasta SFML para dentro da pasta do MinGW. Depois confirme tudo que aparecer.

D- Clique em Project -> Build Options. Clique em Add, na guia Search Directories -> Compiler. Adicione o endereço da pasta Include. Na guia Search Directories -> Linker, adicione o endereço da pasta Lib.


E- Em Linker Settings, vá clicando em Add e adicionando os seguintes valores:


F- Caso você use a versão Static da biblioteca, adicione um -s no final de cada um dos valores. Assim: sfml-graphics-s, sfml-window-s, sfml-system-s. Também faça o seguinte:

G- Caso você use a versão Dynamic da biblioteca, deixe como na imagem do item E. Mas você terá que copiar as DLLs respectivas (ficam na pasta Bin) para a pasta do seu projeto já compilado.
H- Agora coloque o seguinte código:
#include <SFML/Graphics.hpp> int main() { sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!"); sf::CircleShape shape(100.f); shape.setFillColor(sf::Color::Green); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(); window.draw(shape); window.display(); } return 0; }
I- Compile (F9).Você terá algo como:

Caso tenha alguma dúvida, basta deixá-la abaixo na área de comentários. Eu responderei o mais rápido que eu puder.

Compilar SFML para usar com MinGW

Vou mostrar etapa por etapa:

A- Baixar a SFML. Descompactar o gz e depois o tar (ou seja, descompacte tudo até ter todas as pastas).
B- Editar a variável PATH:

Windows 7
1- Selecione Computador no menu Iniciar
2- Escolha Propriedades do sistema no menu de contexto
3- Clique em Configurações avançadas do sistema > guia Avançado

Windows XP
1- Iniciar -> Painel de controle -> Sistema -> Avançado

Seja qual for o seu Windows, agora será o mesmo caminho:

1- Clique em Variáveis de ambiente, em Variáveis do sistema, localize PATH e clique nele.
2- Nas janelas de Edição, modifique PATH, adicionando o caminho para a pasta bin do MinGW. Por exemplo, se houver o texto 'aaaaaaaa', você coloca 'aaaaaaaa; C:\mingw\bin'. Esse é só um exemplo. Lembre-se de separar por ponto-e-vírgula.

C- Baixe o CMAKE.

D- Depois de instalar o CMAKE, entre na pasta dele, depois entre em bin e abra o cmake-gui.exe.


1- Insira o endereço de onde se localiza o source da SFML (onde você encontra o arquivo CMakeLists.txt).
2- Escolha onde deseja que o build seja feito.
3- Clique aí.

E- Na janela que aparecer, selecione a opção "MinGW makefiles". Certifique-se de que "Use default native compilers" está selecionado também.

F- Após isso, você verá algumas linhas em vermelho. Você deverá modificar algumas coisas:

CMAKE_BUILD_TYPE
Escolha entre "Debug" e "Release".
CMAKE_INSTALL_PREFIX
Selecione uma pasta onde deseja que os arquivos sejam instalados. Não é necessário modificar o valor se este for um endereço aceitável, também não será obrigatório instalar os arquivos. Eu não fiz o tutorial mostrando essa forma (instalação). Ou seja, não se preocupe com essa linha, a menos que saiba o que está fazendo.
BUILD_SHARED_LIBS
Passando o mouse por cima dessa linha, verá que vai aparecer uma informação, indicando o que você deve colocar, dependendo do que vai querer (linkagem dinâmica ou estática). A cada versão pode ser diferente, por isso você deve analisar corretamente.
SFML_BUILD_EXAMPLES
Por padrão, não é feito o build dos exemplos. Caso deseje, modifique o valor.
SFML_BUILD_DOC
Se você tiver o Doxygen e desejar fazer um build da documentação, modifique o valor. Por padrão não está ativado.
SFML_USE_STATIC_STD_LIBS (Windows only)
Deixe como TRUE, pois assim não dependerá das DLLs da STDLIB.

G- Clique no botão Configure novamente e depois em Generate.

H- Agora que configuramos tudo, está na hora de fazer o BUILD de verdade.

I- Clique em Iniciar, digite 'cmd' e tecle enter. Usando 'cd nomedapasta', vá até a pasta onde você gerou os arquivos com o CMAKE. Digite mingw32-make e tecle enter.

J- Pronto, se tudo deu certo, você compilou a SFML 2.0 para a sua versão do MinGW.