Introdução à Programação Gráfica

usando Processing

ANIMAÇÃO

O modo contínuo de execução permite que o programador tenha controle do fluxo de execução do seu programa. Duas funções são utilizadas: a função setup, utilizada de maneira opcional, é executada uma vez só durante o carregamento da página. A função draw, por sua vez, é o coração do modo contínuo e indica o que deve se repetir constantemente.

Baseada em duas funções

O que se repete: a função draw

Todo código é repetido indefinidamente

Quando o bloco draw termina, ele é executado novamente

void draw() {

// Coloque aqui o código que deve rodar indefinidamente

}

O código dentro do draw entra em um processo chamado loop e só é interrompido quando o usuário fecha o programa ou clica no botão stop. No exemplo, a mensagem “Olá, Processing” é repetida até o fechamento do programa.

void draw() {
 println("Olá, Processing");
}
void draw() {
 println("Olá, Processing");
}

Um programa só pode ter um bloco draw

void draw()
{
println("Olá, Processing");
}
void draw()
{
println("Olá, Processing");
}

Configuração do modo contínuo

Existem algumas funções que devem ser executadas apenas uma vez em um programa. Por exemplo, a configuração da largura e altura da tela através da função size deve ser executada apenas no início da execução. Outras configurações importantes que devem ser realizadas apenas uma vez são o carregamento de imagens, configuração do antialiasing (função smooth) e escolha da fonte a ser utilizada através da função textFont.

Dessa forma, tudo que se deseja executar apenas uma vez e antes da chamada da função draw deve ser colocado no bloco setup, definido assim:

void setup() {

// Coloque aqui o código que será executado apenas uma vez

}

Controle da taxa de repetição

Por padrão, o bloco draw se repete um máximo de 60 vezes em cada segundo

A taxa de repetição é chamada de frameRate

A variável frameRate indica o número de frames por segundo (fps) que o draw é executado

O código exibe o valor de frameRate no console do Processing.

void draw()
{
println(frameRate);
}

O valor do frameRate não é exato.  Muitas vezes, um programa pode ser executado mais lentamente quando a máquina for lenta devido a algum processamento poderoso sendo realizado. 

Número de repetições 

Variável frameCount

Tal variável indica a quantidade de vezes que o método draw foi chamado desde o início do programa, ou seja, cada vez que o draw é executado o valor de frameCount aumenta em uma unidade.

void draw()
{
 print("O valor de frameRate: ");
 println(frameRate);
 print("O valor de frameCount: ");
 println(frameCount);
}
void draw()
{
print("O valor de frameRate: ");
println(frameRate);
print("O valor de frameCount: ");
println(frameCount);
}

Alterar a taxa de repetição

O valor do frameRate pode ser mudado com a função frameRate. A alteração do valor de frameRate para um valor baixo deixa a execução de um programa mais lenta. Quanto maior o valor de frameRate, mais rápida a taxa de atualização.

Quanto maior o valor, mais rápida a atualização

Quanto menor o valor, mais lenta a atualização

No exemplo abaixo, o valor de frameRate é alterado para 3, ou seja, a função draw é chamada no máximo 3 vezes por segundo. Observe também que o texto desenhado se sobrepõe a cada chamada.


    
void draw()
{
 frameRate(3);
 textFont(createFont("Arial", 20));
 text("frameCount é:", 10, 50);
 text(frameCount, 10, 70);
 print("O valor de frameCount é:");
 println(frameCount);
}
void draw()
{
 frameRate(3);
 textFont(createFont("Arial", 20));
 text("frameCount é:", 10, 50);
 text(frameCount, 10, 70);
 print("O valor de frameCount é:");
 println(frameCount);
}

Para corrigir esta sobreposição, pode-se, por exemplo, chamar a  função background. Neste caso, o fundo vai ser reconstruido a cada execução com a cor indicada como parâmetro.

void draw()
{
 frameRate(3);
 background(0);
 textFont(createFont("Arial", 20));
 text("frameCount é:", 10, 50);
 text(frameCount, 10, 70);
 print("O valor de frameCount é:");
 println(frameCount);
}

Implementando uma animação simples no Processing

Expressões Relacionais

Uma expressão relacional é obtida quando dois valores são comparados. Esta comparação tem como resultado um valor lógico. Tal valor pode ser o valor verdadeiro (true) ou o falso (false).

Devolve verdadeiro quando dois operandos são iguais

println(int(3==3));
println(int(3==4));
println(int(30!=40));
println(int(40!=40));
println(int(10>5));
println(int(10<5));
println(int(10>10));
println(int(10>=10));

Conversão de boolean para inteiro

Usar a função int

println(int(3==3));
println(int(3==4));
println(int(30!=40));
println(int(40!=40));
println(int(10>5));
println(int(10<5));
println(int(10>10));
println(int(10>=10));

Operadores lógicos são úteis para combinar duas ou mais expressões relacionais e para inverter valores lógicos. O operador E, representado pelo sinal &&, retorna o valor verdadeiro caso todos os operandos tenham valor verdadeiro. O operador OU, reprentado pelo sinal ||, retorna o valor verdadeiro caso qualquer um dos operandos tenha valor verdadeiro. O operador NÃO, representado pelo sinal ! é um operador unário, ou seja, só pode ser aplicado em um operando. Neste caso, a aplicação do operador inverte o verdadeiro como falso e vice-versa.

Em uma comparação com objetos do mundo real, o operador E funciona como se fosse uma combinação de duas válvulas em um mesmo cano. Apenas se as duas válvulas estiverem ligadas a água sai pelo cano e enche o pote.

Verdadeiro se todas as condições forem verdadeiras

No programa, cada uma das válvulas é controlada por um operador lógico. A válvula da esquerda é controlada pelo teclado e a da direita pelo mouse. Só no caso de ambas as válvulas estiverem ligadas o cano deixa a água sair.

  • true && true é igual a true;
  • true && false é igual a false;
  • false && true é igual a false;
  • false && false é igual a false;

Verdadeiro se qualquer uma das duas condições forem verdadeiras

No caso do operador OU, temos dois canos diferentes. Assim, tanto no caso de uma válvula ou outra estarem abertas o pote será preenchido com água. Novamente, a válvula da esquerda é controlada pelo teclado e a da direita pelo mouse.

  • true || true é igual a true;
  • true || false é igual a true;
  • false || true é igual a true;
  • false || false é igual a false;
  • !true é igual a false;
  • !false é igual a true.

Até agora o código que executamos foi linha a linha

Até agora o código que escrevemos caracterizou-se por ser executado linha a linha e do início ao fim do programa. A única alteração de fluxo trabalhada foi implementada através do bloco draw, que permite que seja feita a repetição de parte do código indefinidamente. Entretanto, em um programa de computador muitas vezes torna-se necessário um controle mais fino do fluxo de execução. Por exemplo, realizar um desenho apenas quando uma certa condição esteja satisfeita. Para este controle será necessária a definição da estrutura condicional, representada pela palavra chave if.

Estrutura de Seleção ou Condicional permite a escolha de um grupo de ações a ser executado apenas quando certas condições são satisfeitas

Pode ser verdadeira (true) ou falsa (false)

Expressões relacionais são expressões que realizam operações de comparação entre dois valores de um mesmo tipo primitivo usando os operadores relacionais (==, >=, !=, <=, etc). Os operandos são variáveis, constantes ou expressões de qualquer tipo e o resultado da expressão é um valor lógico.

Observe que o operador == não deve ser substituído por apenas um sinal de igual. Apenas um sinal de igual é usado para a operação de atribuição

Operadores lógicos são úteis para combinar duas ou mais expressões relacionais e para inverter valores lógicos. O operador E, representado pelo sinal &&, retorna o valor verdadeiro caso todos os operandos tenham valor verdadeiro. O operador OU, reprentado pelo sinal ||, retorna o valor verdadeiro caso qualquer um dos operandos tenha valor verdadeiro. O operador NÃO, representado pelo sinal ! é um operador unário, ou seja, só pode ser aplicado em um operando. Neste caso, a aplicação do operador inverte o verdadeiro como falso e vice-versa.

Em uma comparação com objetos do mundo real, o operador E funciona como se fosse uma combinação de duas válvulas em um mesmo cano. Apenas se as duas válvulas estiverem ligadas a água sai pelo cano e enche o pote.

Verdadeiro se todas as condições forem verdadeiras

No programa, cada uma das válvulas é controlada por um operador lógico. A válvula da esquerda é controlada pelo teclado e a da direita pelo mouse. Só no caso de ambas as válvulas estiverem ligadas o cano deixa a água sair.

  • true && true é igual a true;
  • true && false é igual a false;
  • false && true é igual a false;
  • false && false é igual a false;

Verdadeiro se qualquer uma das duas condições forem verdadeiras

No caso do operador OU, temos dois canos diferentes. Assim, tanto no caso de uma válvula ou outra estarem abertas o pote será preenchido com água. Novamente, a válvula da esquerda é controlada pelo teclado e a da direita pelo mouse.

  • true || true é igual a true;
  • true || false é igual a true;
  • false || true é igual a true;
  • false || false é igual a false;
  • !true é igual a false;
  • !false é igual a true.

Estrutura de seleção simples

O primeiro tipo de estrutura condicional é a seleção simples. Nesta estrutura, construída através da instrução if, se uma certa condição for verdadeira, a primeira instrução imediatamente abaixo da condição é executada. Caso a condição seja false, o comando é ignorado. Em inglês, “if” significa “se”.

if (condição)

  instrução a ser executada se a condição for verdadeira

Significa: a ação só pode ser executada se a condição for verdadeira

if(px==100)

  println("Chegou na reta final!");

Caso haja mais de um comando a ser executado estes comandos devem ser agrupados entre colchetes. Este agrupamento é chamado de bloco de instruções.

if(condição) {

   primeira instrução a ser executada...

   segunda instrução a ser executada...

   ...

}

if(px==200) {

   println("Voltando para o início");

   px = 0;

}

Estrutura de seleção composta

Para executar um fluxo alternativo de código apenas no caso da condição ser falsa, utiliza-se a estrutura de seleção composta. Neste caso, a palavra else é colocada logo após o fim do bloco de código definido pelo comando if. O bloco de instruções após o else só é executado quando a condição for falsa. É importante destacar que o fluxo principal e o fluxo alternativo tem execuções excludentes, ou seja, o fluxo alternativo nunca é executado após o fluxo principal.

Permite considerar um fluxo alternativo ao fluxo principal

Palavra-chave else

Nunca o fluxo alternativo é executado após o principal

if(condição)

    comando

else

    comando alternativo

if(condição) {

   comando 1

   comando 2

}

else

   comando alternativo

if(condição)

   comando

else {

  comando alternativo 1

  comando alternativo 2

}

if(condição) {

  comando 1

  comando 2

} else {

  comando alternativo 1

  comando alternativo 2

}

Função com parâmetros e sem retorno

Relembrando como definir uma função

void nome() {

   instruções;

}

Para chamar a função, dentro do setup, coloque o nome da função

void nome() {

   instruções;

}

void setup() {

   instruções;

   nome();

}

Funções podem ter parâmetros para alterar seu comportamento

Definindo uma função com parâmetros

void nome(tipo parâmetro, tipo parâmetro) {

   instruções;

}

void desenharCabeca(float diametro) {

  noFill();

  ellipse(40,20,diametro/4,diametro/4);

  ellipse(60,20,diametro/4,diametro/4);

  ellipse(50,30,diametro,diametro);

}

void setup() {

  desenharCabeca(60);

}

void desenharCabeca(float diametro) {

  noFill();

  ellipse(40,20,diametro/4,diametro/4);

  ellipse(60,20,diametro/4,diametro/4);

  ellipse(50,30,diametro,diametro);

}

void setup() {

  desenharCabeca(60);

}

Técnica para simular comportamentos complexos

Separa comportamento em estados distintos

Permite que unifiquemos diferentes programas em um só

Mudança de estado

FSM demonstra como um objeto varia em relação ao tempo

FSM de Moore

FSM de Mealy

Passar da Representação Gráfica para código

Estados (gerundio)

Transições (eventos)

Ação realizada (a cada estado)

Implementação da FSM

Codificada via switch

Legível, se pequena

Difícil de descobrir erros, se grande

Lógica redundante em diversos estados

Não há como representar claramente que um estado foi executado pela 1a vez

switch (estado)

{

 case stVagando:

    Vagar();

    if (ViuInimigo() ) estado=stAtacando;

    if (Morreu () ) estado=stMorrendo;

 break;

 case stAtacando:

    Atacar();

    estado=stVagando;

    if (Morreu () ) estado=stMorrendo;

  break;

case stMorrendo:

    ApodrecerLentamente();

break;

}// end switch

enum state{stVagando, stAtacando, stMorrendo); ...

switch (estado)

{

case stVagando:

Vagar();

if (ViuInimigo() ) estado=stAtacando;

if (Morreu () ) estado=stMorrendo;

break;

case stAtacando:

Atacar();

estado=stVagando;

if (Morreu () ) estado=stMorrendo;

break;

case stMorrendo:

ApodrecerLentamente();

break;

}// end switch