Curso de Especialização em Desenvolvimento de Jogos Digitais

Programação 2D



AULA PRÁTICA -  TRANSFORMAÇÕES GEOMÉTRICAS HIERÁRQUICAS





O objetivo deste exercício é exercitar a criação de grafos de cena.

Descompacte os fontes deste link e inclua-os em um projeto com OpenGL.
Para obter instruções sobre como criar um projeto OpenGL usando o Visual Studio acesse a página da última aula prática.

Compile o programa e controle os objetos na tela com as seguintes teclas:
- 0,1, 2: definem qual é objeto ativo;
- teclas de seta LEFT, RIGHT: movem o objeto ativo para frente/trás.
- teclas de seta UP, DOWN: giram o objeto ativo para esquerda/direita.
- barra de espaço: imprime no console as coordenadas do objeto ativo.


DESCRIÇÃO DOS FONTES

Tools.cpp e Tools.h

Contém funções auxiliares de cálculos matemáticos. Analise o Tools.cpp para ver a descrição das funções.

void InverteMatriz( float a[4][4], float b[4][4]);
void MultiplicaMatriz(float m1[4][4], float m2[4][4], float m[4][4]);
float calculaDistancia(float P1[3], float P2[3]);

Desenhos.cpp e Desenhos.h

Contém as funções de desenhos dos objetos em coordenadas do sistema de referência do objeto, ou seja, SEM as transformacoes geométricas que definem a posição, a rotação e a escala de
uma instância
Via de regra, é neste fonte que devem ser colocadas os comandos OpenGL que fazem os desenhos.

void DesenhaContornoCirculo(GLfloat raio, GLfloat centrox, GLfloat centroy);
void DesenhaCirculo(GLfloat raio, GLfloat centrox, GLfloat centroy);
void DesenhaTexto(char *string, GLfloat posX, GLfloat posY);
void DesenhaCarro();
void DesenhaHelicoptero();


Objeto.cpp e Objeto.h

Contém a estrutura capaz de armazenar uma instância de um objeto. Os métodos que aplicam as transformações geométricas estão nestes fontes.

A struct que define esta instância é a seguinte:

typedef struct Objeto {
    int tipo;
    int nroDeFilhos;
    bool eh_filho;
    GLfloat M[4][4];
    Objeto *Filho;
    Objeto *Pai;


    void setTipo(int t);
   
    void Init();
    void Rotate(float ang, float x, float y, float z);
    void Translate(float x, float y, float z);
    void Scale(float x, float y, float z);
    void Draw();
    void ImprimeMatriz(const char *msg);
    void InstanciaPonto(float PontoIN[3], float PontoOUT[3]);
    void AdicionaFilho(Objeto *filho);
    void RemoveFilho();
    
} Objeto;

Os atributos têm o seguinte significado:

    int tipo; // define se o objeto é um helicoptero(0) ou um carro(1)

    int nroDeFilhos; //define quantos filhos tem o objeto no momento

    bool eh_filho; // informa se o objeto é filho de algum outro objeto do cenário

    Objeto *Filhos; // vetor com apontadores para os filhos do objeto

    GLfloat M[4][4]; // matriz de transformação do objeto

    Objeto *Pai; // Ponteiro para o pai do objeto


Analise o fonte
Objeto.cpp  e veja a descrição de cada função.

TransfHierarq.cpp

Módulo principal que controla a exibição do cenário.
O programa trabalha com o conceito de objeto ativo, que define sobre qual objeto as transformações comandadas pelo teclado serão aplicadas. Para ativar um objeto pressione 0, 1 ou 2.
As instancias dos objeto estão armazenadas no vetor

Objeto Cenario[10];

As principais funções do módulo são:

Função Init():

Faz as iniciaizações de OpenGL e cria as instâncias que compõem o cenário.
O trecho de código abaixo é que inicializa as instâncias. No caso, há 3 instâncias. A ZERO é um helicóptero e as demais são carros.

        QTD_OBJETOS = 3;
    ObjetoAtivo = 0;

    for(int i=1; i<QTD_OBJETOS;i++)
    {
        Cenario[i].Init();
        Cenario[i].Translate(i*600,i*300,0);
        Cenario[i].setTipo(2); // carro
    }
    Cenario[0].Init();
    Cenario[0].setTipo(1); // Helicoptero


Função Desenha():

Realiza o desenho do cenário. O principal trecho é o que desenha cada objeto armazenado no vetor "Cenario".

    // Desenha o cenario todo
    for(int i=0; i<3;i++)
    {
      Cenario[i].Draw();
    }

Também se pode, nesta função imprimir as posições de cada objeto do cenário com o trecho apresentado a seguir. A variáriavel
imprimeCoordenadas é alterada pela tecla barra-de-espaco.

    if (imprimeCoordenadas)
    {
        GLfloat P1[] = {0,0,0};
        GLfloat P2[3];

        imprimeCoordenadas = false;
        printf("Posicoes do objetos:\n");
        for(int i=0; i<QTD_OBJETOS; i++)
        {
            printf("Objeto %d: ",i);
            Cenario[i].InstanciaPonto(P1,P2);
            for (int j=0; j<3;j++)
                printf("%7.2f ", P2[j]);
            printf("\n");
        }

       


EXERCÍCIO

O objetivo deste exercício é permitir que o helicoptero possa pegar um carro e transportá-lo pelo cenário até um ponto desejado, onde será 'largado'. O comando de 'pegar' só deve funcionar quando o helicóptero for o objeto ativo.
Para resolver o exercício proposto, utilize o material apresentado na aula teórica.

O carro a ser pego deve ser o mais próximo do helicoptero.

ATENÇÃO: Note que comando de pegar deve estar na função que trata as teclas void Teclado (unsigned char key, int x, int y),


       case 'p': // faz o helicoptero pegar um dos objetos do cenario
       case 'P':  if(ObjetoAtivo != 0)
                   {
                       tentaPegar = true;
                   }

Porém esta função deve apenas alterar uma variável que será testada na rotina de desenho void Desenha(void), com algo como :

    if (tentaPegar)
    {
        // acha o carro mais próximo do helicoptero
        proximo = MaisProximo(Cenario[0]);
       
        // adiciona o carro mais próximo como filho do helicoptero
        Cenario[0].AdicionaFilho(&Cenario[
proximo]);
    }

 
O mesmo processo deve ser implementado para largar o carro.

FIM.