Interakcija mišem i tastaturom u Processing-u

Lekcija 3 od 14 · Processing

Do sada su naši skečevi samo crtali i pomerali oblike. Program postaje zanimljiv kada reaguje na korisnika: na pomeranje i klik miša i na pritisak tastera. U ovoj lekciji upoznaćeš promenljive i funkcije za miš i tastaturu i napraviti malu igru.

Pre nego što počneš: potrebno predznanje – Osnove Processinga (funkcije setup() i draw(), crtanje oblika).
Kako da učiš: svaki primer prekucaj u Processing (režim Java) i pokreni ga dugmetom ▶. Zadatke na kraju prvo reši sam/a.

Položaj miša: mouseX i mouseY

Processing u svakom trenutku zna gde je kursor. Promenljive mouseX i mouseY sadrže koordinate miša unutar prozora, a pmouseX i pmouseY položaj iz prethodnog kadra. Pošto se draw() izvršava oko 60 puta u sekundi, dovoljno je da oblik nacrtamo na položaju miša i on će ga pratiti.

void setup() {
  size(400, 400);
}

void draw() {
  background(230);
  fill(0, 120, 255);
  noStroke();
  ellipse(mouseX, mouseY, 40, 40);   // krug prati kursor
}
Zašto background() na početku draw()? Bez njega bi ostajali svi prethodni krugovi, pa bi se dobio trag. Probaj da ga premestiš u setup() i pogledaj razliku.

Klik mišem: mousePressed i mouseButton

Postoje dva načina da se reaguje na taster miša:

  • promenljiva mousePressed je true sve dok je taster pritisnut – pogodno za crtanje dok se drži taster;
  • funkcija void mousePressed() se pozove jednom pri svakom pritisku – pogodno za brojanje klikova.

Promenljiva mouseButton kaže koji je taster pritisnut: LEFT, RIGHT ili CENTER. U primeru ispod je jednostavan program za crtanje: levi taster crta, desni briše, a taster c čisti ceo crtež.

void setup() {
  size(500, 400);
  background(255);
}

void draw() {
  if (mousePressed) {                 // taster miša je pritisnut
    if (mouseButton == LEFT) {
      stroke(0);                      // levi taster – crna olovka
      strokeWeight(4);
    } else {
      stroke(255);                    // desni taster – gumica
      strokeWeight(20);
    }
    line(pmouseX, pmouseY, mouseX, mouseY);   // linija od prethodnog do trenutnog položaja
  }
}

void keyPressed() {
  if (key == 'c') {
    background(255);                  // taster c briše crtež
  }
}

Linija od (pmouseX, pmouseY) do (mouseX, mouseY) spaja dva uzastopna položaja, pa crtež nema rupa ni kada se miš brzo pomera.

Tastatura: key, keyCode i keyPressed

Za tastaturu važi isto pravilo: promenljiva keyPressed je true dok se taster drži, a funkcija void keyPressed() se poziva jednom pri pritisku. Pritisnuti znak je u promenljivoj key (npr. 'a', ' ').

Strelice i drugi posebni tasteri nemaju znak. Tada je key == CODED, a taster se prepoznaje po keyCode: LEFT, RIGHT, UP, DOWN.

float x = 200;
float y = 200;
float korak = 5;

void setup() {
  size(400, 400);
}

void draw() {
  background(30);
  fill(255, 200, 0);
  rect(x - 20, y - 20, 40, 40);

  if (keyPressed && key == CODED) {   // posebni tasteri (strelice) imaju key == CODED
    if (keyCode == LEFT)  x -= korak;
    if (keyCode == RIGHT) x += korak;
    if (keyCode == UP)    y -= korak;
    if (keyCode == DOWN)  y += korak;
  }
  x = constrain(x, 20, width - 20);   // kvadrat ne izlazi iz prozora
  y = constrain(y, 20, height - 20);
}

Funkcija constrain(vrednost, min, max) vraća vrednost ograničenu na zadati opseg, pa kvadrat ostaje u prozoru. Pošto se provera radi u draw(), kvadrat se kreće ravnomerno dok god držiš strelicu.

Primer: igra „Pogodi metu“

Spojimo sve u malu igru. Na slučajnom mestu se pojavi crveni krug. Klik unutar kruga donosi poen i krug postaje manji, a klik pored kruga je promašaj. Da li je klik unutar kruga proveravamo rastojanjem: ako je rastojanje od miša do centra manje od poluprečnika, pogodak je.

float cx, cy;          // centar mete
float r = 30;          // poluprečnik mete
int poeni = 0;
int promasaji = 0;

void setup() {
  size(500, 400);
  novaMeta();
}

void draw() {
  background(240);
  fill(220, 40, 60);
  noStroke();
  ellipse(cx, cy, 2 * r, 2 * r);

  fill(0);
  textSize(18);
  text("Poeni: " + poeni + "   Promašaji: " + promasaji, 10, 25);
}

void mousePressed() {
  // klik je unutar kruga ako je rastojanje od centra manje od poluprečnika
  if (dist(mouseX, mouseY, cx, cy) < r) {
    poeni++;
    r = max(10, r - 2);   // meta je sve manja
  } else {
    promasaji++;
  }
  novaMeta();
}

void novaMeta() {
  cx = random(r, width - r);
  cy = random(40 + r, height - r);
}

Funkcija dist(x1, y1, x2, y2) računa rastojanje dve tačke po Pitagorinoj teoremi. random(a, b) daje slučajan broj iz intervala, pa nova meta uvek staje ceo u prozor i ne preklapa natpis sa poenima.

Ideja za nadogradnju: dodaj tajmer od 30 sekundi (millis() vraća broj milisekundi od pokretanja) i na kraju ispiši konačan rezultat.

Zadaci za vežbu

Za svaki zadatak postoji uputstvo i rešenje. Rešenja su proverena prevođenjem.

ZADATAK 01Težina: lako

Boja pozadine sa tastature

Napiši skeč u kome taster r povećava crvenu komponentu boje pozadine za 20, g zelenu, a b plavu. Kada komponenta pređe 255, vraća se na početak. Razmak vraća belu pozadinu. Trenutne vrednosti ispiši u uglu prozora.

ZADATAK 02Težina: lako

Brojač klikova

Na sredini prozora prikaži broj. Levi klik ga povećava za 1, a desni smanjuje za 1, ali broj nikada nije manji od nule.

Česte greške i saveti
  • Promenljiva mousePressed i funkcija mousePressed() nisu isto: promenljiva važi dok se taster drži, funkcija se poziva jednom po kliku.
  • Za strelice prvo proveri key == CODED, pa tek onda keyCode.
  • key razlikuje mala i velika slova: 'a' nije isto što i 'A'.
  • Bez background() na početku draw() na ekranu ostaju tragovi prethodnih kadrova.

Proveri znanje

Otvori kviz

Kviz: interakcija

1. Šta sadrže promenljive mouseX i mouseY?




2. Kada se poziva funkcija void mousePressed()?




3. Kako se prepoznaje pritisak strelice nagore?




4. Kako proveriti da je klik unutar kruga sa centrom (cx, cy) i poluprečnikom r?