Poli.school
PCS3021

Funções

Criando funções próprias em p5.js: parâmetros, variáveis locais, valores de retorno, variáveis globais e efeitos colaterais

Quando estamos programando, é comum precisarmos utilizar uma mesma sequência de comandos em diferentes partes do programa. As funções são uma maneira de fazermos isso (sem ter que repetir os comandos), auxiliando na estruturação do programa. Desde as nossas primeiras atividades com o p5.js, temos utilizado funções. Por exemplo, no programa a seguir, cada linha está executando uma função que é pré-definida no p5.js:

function setup() {
  createCanvas(400, 300);
  background(220, 220, 240);
  stroke(255, 0, 0);
  fill(0, 255, 0);
  rect(width / 4, height / 4, width / 2, height / 2);
}

Além disso, já organizamos nossos programas usando as funções setup() e draw(), que indicam os comandos que devem ser executados somente no início e aqueles que devem ser executados repetidamente.

Agora, vamos aprender como criar nossas próprias funções. Na sua forma mais simples, uma função é escrita como:

function nomeDaFuncao() {
  // comandos...
}

Diferente do Processing, em JavaScript não é necessário indicar antes do nome se a função retorna algum valor (não existe a palavra void). O nome da função é qualquer nome começando com uma letra, e que pode ter letras, números e o caractere sublinhado ("_") em sua composição. Assim como nas variáveis, maiúsculas e minúsculas são diferenciadas, portanto:

function MINHAFUNCAO() {}
function minhaFuncao() {}
function MiNhAfUnCaO() {}

são consideradas três funções diferentes.

No exemplo a seguir, a função desenharSimbolo() foi criada para representar um comando que desenha uma composição geométrica a partir da posição (0, 0) do sistema de coordenadas. Dessa forma, os detalhes sobre o desenho ficam organizados dentro daquela função.

Código 7.1 - Sem definir uma função: mais difícil identificar os comandos que se referem ao símbolo desenhado
function setup() {
  createCanvas(500, 500);
  background(0);
  for (let i = 0; i < 5; i++) {
    for (let j = 0; j < 3; j++) {
      noStroke();
      fill(255, 128, 0);
      rect(0, 0, 100, 100);
      fill(0);
      circle(50, 50, 100);
      translate(200, 0);
    }
    translate(-500, 100);
  }
}
Carregando sketch…
Código 7.2 - Com a definição da função desenharSimbolo(): programa mais organizado e com leitura mais fácil
function setup() {
  createCanvas(500, 500);
  background(0);
  for (let i = 0; i < 5; i++) {
    for (let j = 0; j < 3; j++) {
      desenharSimbolo();
      translate(200, 0);
    }
    translate(-500, 100);
  }
}

function desenharSimbolo() {
  noStroke();
  fill(255, 128, 0);
  rect(0, 0, 100, 100);
  fill(0);
  circle(50, 50, 100);
}
Carregando sketch…

O fato da função desenharSimbolo() ter sido definida no programa não é suficiente para que o símbolo seja desenhado. É preciso executar essa função (nesse exemplo, dentro da função setup()). Cada vez que o p5.js encontra uma linha:

desenharSimbolo();

o programa executa sequencialmente todas as linhas dentro daquela função (como se fosse um "mini programa") e então continua a execução normal, nesse caso, o comando translate(200, 0).

Atividade 1

Modifique a função desenharSimbolo() do exemplo anterior, para criar uma outra composição de formas geométricas.

1.1. Parâmetros

No exemplo anterior, a função desenharSimbolo() sempre cria o desenho a partir do ponto (0, 0) e, por isso, foi preciso utilizar transformações de translação para desenhar o símbolo em diferentes locais da janela. É possível adicionar parâmetros a uma função: informações que a função utiliza para fazer suas operações. Por exemplo, essa nova versão da função desenharSimbolo() recebe dois parâmetros, x e y, que indicam a posição em que o símbolo deve ser desenhado:

Código 7.3 - Função desenharSimbolo() com parâmetros de posição
function setup() {
  createCanvas(500, 500);
  background(0);
  desenharSimbolo(100, 50);
  desenharSimbolo(300, 250);
}

function desenharSimbolo(x, y) {
  noStroke();
  fill(255, 128, 0);
  rect(x, y, 100, 100);
  fill(0);
  circle(x + 50, y + 50, 100);
}
Carregando sketch…

Os parâmetros da função são sempre listados dentro dos parênteses após o seu nome, separados por vírgulas. Cada parâmetro tem um nome e funciona como se fosse uma variável que só existe dentro da função — diferente do Processing, não é necessário indicar o tipo do parâmetro (como float), já que JavaScript não exige essa declaração. Note que, agora, para executar a função é preciso incluir valores para esses parâmetros. Por exemplo, a linha:

desenharSimbolo(100, 50);

fará com que a função desenharSimbolo() seja executada, com o parâmetro x recebendo o valor 100 e o parâmetro y recebendo o valor 50.

Atividade 2

Crie um programa que use essa nova versão da função desenharSimbolo() e desenhe, dentro da função setup(), dez símbolos em posições aleatórias da janela.

1.2. Usando variáveis dentro de uma função

Além dos parâmetros, também é possível definir variáveis dentro de uma função, que são conhecidas como variáveis locais. Essas variáveis só existem no bloco da função correspondente e não preservam seus valores (você já deve ter criado variáveis dentro da função draw() e observado essas propriedades). O exemplo a seguir desenha um conjunto de círculos concêntricos que acompanham o mouse:

Código 7.4 - Variáveis locais dentro de uma função
function setup() {
  createCanvas(500, 500);
  // desliga o desenho da seta do mouse
  noCursor();
}

function draw() {
  background(0);
  desenharCirculos(mouseX, mouseY);
}

function desenharCirculos(x, y) {
  let contador = 0;
  let diametro = 10;
  noFill();
  stroke(255);
  while (contador < 5) {
    circle(x, y, diametro);
    diametro = diametro + 10;
    contador = contador + 1;
  }
}
Carregando sketch…

Observe que as variáveis contador e diametro só existem dentro da função desenharCirculos(). Elas são definidas e inicializadas (com os valores 0 e 10, respectivamente) cada vez que a função é executada.

Atividade 3

Crie um programa com uma função desenharGrade(numero, distancia) que desenha uma grade de linhas horizontais e verticais em quantidade dada pelo parâmetro numero e espaçamento dado pelo parâmetro distancia, a partir da coordenada (0, 0) da janela.

Funções que retornam valores

Até agora, sempre escrevemos nossas funções na forma function nome(parâmetros) { ... }, sem devolver nenhum valor a quem as chamou. Entretanto, as funções também podem retornar valores, usando a palavra return. Diferente do Processing — que exige indicar antes do nome da função o tipo do valor retornado (int, boolean, String etc., no lugar de void) — em JavaScript isso não é necessário: qualquer função pode conter um return, independente do tipo do valor devolvido. Alguns exemplos de funções que retornam valores:

  • Executar operações matemáticas, como a distância entre dois pontos ou o número de dias entre duas datas;
  • Testar se uma condição é verdadeira: se dois segmentos de reta se cruzam, se um nome existe em uma lista;
  • Analisar informações: encontrar o maior número em uma lista, contar o número de cores em uma imagem etc.

No exemplo a seguir, a função pontoNoRetangulo() retorna verdadeiro ou falso, indicando se o ponto (px, py) se encontra dentro do retângulo (rx, ry, largura, altura). Ela é usada para testar se o mouse está dentro de um retângulo na janela.

Código 7.5 - Função que retorna um valor booleano
function setup() {
  createCanvas(500, 500);
}

function draw() {
  background(0);
  if (pontoNoRetangulo(mouseX, mouseY, 150, 70, 210, 130)) {
    fill(255, 0, 0);
  } else {
    fill(255);
  }
  rect(150, 70, 210, 130);
}

function pontoNoRetangulo(px, py, rx, ry, largura, altura) {
  if (px >= rx && px <= rx + largura) {
    if (py >= ry && py <= ry + altura) {
      return true;
    }
  }
  return false;
}
Carregando sketch…

Observe que, dentro da função pontoNoRetangulo() existe um comando novo: return. Esse comando é utilizado para encerrar a função, retornando o valor indicado (assim, return true faz com que a função retorne o valor true como resultado).

Atividade 4

Modifique o programa do exemplo anterior, adicionando mais dois retângulos que devem mudar de cor quando o mouse estiver sobre eles.

Atividade 5

Complete o programa a seguir, escrevendo o conteúdo da função maior() para que retorne o maior valor entre os parâmetros recebidos.

Atividade 5 - Código de partida
function setup() {
  createCanvas(500, 500);
}

function draw() {
  background(0);
  let lado = maior(mouseX, mouseY);
  rect(0, 0, lado, lado);
}

function maior(a, b) {
  // completar
}
Carregando sketch…

Funções e variáveis globais

Além de parâmetros e variáveis locais, as funções podem também manipular variáveis globais, ou seja, variáveis que são definidas fora de qualquer outra função. Na prática, já fizemos isso para conseguir criar animações em p5.js. Por exemplo:

Código 7.6 - Função draw() acessando uma variável global
// variável global
let px;

function setup() {
  createCanvas(500, 500);
  px = 0;
}

function draw() {
  background(0);
  // acessa a variável global px
  rect(px, 0, 10, 100);
  px = px + 1;
}
Carregando sketch…

Nesse caso, a variável px é usada para determinar a posição horizontal do retângulo a ser desenhado na tela. Essa variável precisa ser global porque seu valor precisa ser preservado entre execuções da função draw().

Uma questão importante é: já que as funções podem acessar variáveis globais, por que não usar somente esse tipo de variável no programa? Por que criar variáveis dentro das funções? O problema das variáveis globais é que elas podem ser acessadas de qualquer ponto do programa e, portanto qualquer função pode modificá-las. Por outro lado, uma variável local é inicializada cada vez que a função é executada e só é acessível dentro daquela função.

Consequentemente, devemos procurar usar variáveis globais somente para representar informações que precisam ser compartilhadas dentro do programa, ou que precisam ser preservadas entre chamadas de função (como é o caso das variáveis usadas em animações com a função draw()).

É importante observar que, em muitos casos, podemos passar informações para uma função como parâmetros, em vez de acessar diretamente variáveis globais. Isso faz com que a função se torne mais flexível, pois não depende mais da existência daquelas variáveis globais para funcionar. No exemplo a seguir, temos duas versões de uma função que desenha pontos aleatórios na janela. Em um caso, as variáveis globais width e height do p5.js são usadas diretamente. No outro, o tamanho da área de desenho é definido através de parâmetros da função.

Código 7.7 - Acessando variáveis globais diretamente
function setup() {
  createCanvas(500, 500);
  background(0);
  desenharPontos();
}

function desenharPontos() {
  for (let contador = 0; contador < 10; contador++) {
    let px = random(width);
    let py = random(height);
    circle(px, py, 10);
  }
}
Carregando sketch…
Código 7.8 - Recebendo as mesmas informações como parâmetros
function setup() {
  createCanvas(500, 500);
  background(0);
  desenharPontos(width, height);
}

function desenharPontos(largura, altura) {
  for (let contador = 0; contador < 10; contador++) {
    let px = random(largura);
    let py = random(altura);
    circle(px, py, 10);
  }
}
Carregando sketch…

Ao organizarmos nossos programas com funções, é recomendável analisar se cada informação que precisamos representar deve ser implementada como uma variável global ou se pode ser uma variável local ou parâmetro.

Atividade 6

Procurando evitar acessar diretamente variáveis globais, modifiquei o exemplo da animação com a função draw() para o seguinte. Por que isso não funciona?

Atividade 6 - Código para análise
// variável global
let px;

function setup() {
  createCanvas(500, 500);
  px = 0;
}

function draw() {
  background(0);
  moverBloco(px);
}

function moverBloco(posX) {
  rect(posX, 0, 10, 100);
  posX = posX + 1;
}
Carregando sketch…

Efeitos colaterais

A discussão anterior sobre variáveis globais mostra uma situação em que, intencionalmente, modificamos uma informação externa à função. Idealmente, uma função cumpre os seus objetivos sem causar outras alterações (embora isso nem sempre seja viável), que são conhecidas como efeitos colaterais. Por exemplo, vejamos a função desenharSimbolo() apresentada no início deste capítulo:

function desenharSimbolo() {
  noStroke();
  fill(255, 128, 0);
  rect(0, 0, 100, 100);
  fill(0);
  circle(50, 50, 100);
}

O objetivo dessa função é desenhar uma composição geométrica. Entretanto, depois que essa função é executada, as configurações de contorno e preenchimento das formas são alteradas (por causa das chamadas das funções noStroke() e fill()) e vão afetar o restante do programa. Nesse caso, podemos evitar esses efeitos colaterais com as funções push() e pop() do p5.js, que armazenam e restauram as configurações de desenho e de transformação (translação, rotação e escala), respectivamente. Diferente do Processing — que separa pushStyle()/popStyle() (só estilo) de pushMatrix()/popMatrix() (só transformações) — em p5.js push() e pop() cuidam das duas coisas de uma só vez.

Código 7.9 - Evitando efeitos colaterais com push() e pop()
function desenharSimbolo() {
  // salva as configurações de desenho e transformação
  push();
  noStroke();
  fill(255, 128, 0);
  rect(0, 0, 100, 100);
  fill(0);
  circle(50, 50, 100);
  // restaura as configurações antes de terminar a função
  pop();
}

Quando possível, recomenda-se programar as funções de maneira a evitar efeitos colaterais. Quando não for viável, é importante documentar (em comentários) os efeitos colaterais existentes, para ajudar na compreensão e correção de erros do programa.

Assim encerramos o capítulo sobre funções, buscando entender em mais detalhes algumas práticas que já utilizávamos em nossos programas. Com isso, expandimos nosso repertório com a capacidade de criar nossas próprias funções, para organizar e tornar mais compreensíveis nossos programas.

Copyright © 2026