Kanter, kanter, mange mangekanter

Introduksjon:

Her skal vi se på litt mer avansert opptegning og bevegelse. Vi skal ta utgangspunkt i oppgaven om den sprettende ballen, men bytte ut ballen med trekanter, firkanter og mangekanter. Det anbefales derfor at du har gjort den oppgaven før, eller at du har en forståelse av if-setninger og koordinatsystemet fra før. Altså skal du lære å tegne former med kanter, mange kanter.

Steg 1: Enkle firkanter

Vi begynner med rektangler: de firkantene som det er enklest å tegne på datamaskinen.

Sjekkliste

  • float x;
    float y;
    float xFart = 1.5;
    float yFart = 2;
    
    void setup() {
      size(640, 480);
      x = width / 2;
      y = height / 2;
    }
    
    void draw() {
      x += xFart;
      y += yFart;
    
      if (x < 0) {
        xFart = -xFart;
      }
    
      if (x > width - 100) {
        xFart = -xFart;
      }
    
      if (y < 0) {
        yFart = -yFart;
      }
    
      if (y > height - 100) {
        yFart = -yFart;
      }
    
      background(0);
      rect(x, y, 100, 100);
    }
    

    Dette programmet er ganske likt det som ble lagd i siste oppgave om den sprettende ballen, men det er noen små forskjeller:

    • Vi har endret tallene brukt i if-setningene. Hvorfor tror du dette er gjort? Hva skjer om du også tegner opp en sirkel med samme posisjon og størrelse som firkanten?

Utfordringer

Enkle trekanter

Å tegne rektangler var omtrent helt likt som å tegne sirkler, men nå skal du lære å tegne trekanter. Om en trekant ble tegnet opp med en posisjon og en bredde og høyde, hadde man ikke hatt så veldig god kontroll over hvordan trekanten så ut. Derfor må vi si for hvert hjørne befinner seg.

Sjekkliste

  • void draw() {
      x += xFart;
      y += yFart;
    
      if (x < 0) {
        xFart = -xFart;
      }
    
      if (x > width - 100) {
        xFart = -xFart;
      }
    
      if (y < 0) {
        yFart = -yFart;
      }
    
      if (y > height - 100) {
        yFart = -yFart;
      }
    
      background(0);
      triangle(x, y, x + 100, y, x + 50, y + 100);
    }
    

    Her har vi tatt i bruk triangle istedenfor rect. Denne tar imot seks argumenter, to for hvert hjørne i trekanten. x, y er posisjonen til det første hjørnet øverst til venstre, x + 100, y er posisjonen til det øverste høyre hjørnet og x + 50, y + 100 er det siste hjørnet nederst i midten.

Forbedre leseligheten

Noen ganger kan det være vanskelig å lese kode med kall på funksjoner som tar mange argumenter. I Processing tar de fleste funksjoner bare imot noen få argumenter, men triangle tar seks. Da kan det være nyttig å dele opp kallet over flere linjer. For eksempel kunne setningen ovenfor vært skrevet slik at hvert hjørne var på hver sin linje:

triangle(x, y,
  x + 100, y,
  x + 50, y + 100);

Hvis man fortsatt synes det er vanskelig å lese eller rotete, kan man legge til noen ekstra mellomrom for å få ting på linje. Merk at om man bruker automatisk formatering av koden i Processing, vil den fjerne mellomrom den mener er overflødig.

Utfordringer

Trekanter

Nå skal vi se hvordan vi kan lage trekanter hvor hvert hjørne beveger seg for seg selv. Da trenger vi variabler for posisjon og fart for hvert hjørne. Til sammen blir dette fire variabler for hvert hjørne i trekanten. En for x-posisjon, en for y-posisjon, en for x-fart og en for y-fart. Ettersom trekanten har tre hjørner, blir dette totalt 3 hjørner * 4 variabler = 12 variabler.

Vi kunne kalt dem f.eks. x1, x2, x3 og tilsvarende lagt tall til y, xFart og yFart. Isteden skal vi bruke noe som kalles en array. Det er vanlig å bruke det engelske ordet også på norsk, men det oversettes noen ganger til liste, vektor, rekke, tabell eller matrise.

Sjekkliste

  • float[] x = new float[3];
    float[] y = new float[3];
    float[] xFart = new float[3];
    float[] yFart = new float[3];
    

    Nå har vi endret typen av variablene fra float til float[]. Når vi putter firkantklammer etter en type, er det en array som inneholder verdier av typen foran klammene. Bak likhetstegnet ser vi også noe nytt new float[3] betyr at vi skal lage en ny float-array med tre tall i.

  • void setup() {
      size(800, 600);
    
      x[0] = width / 2;
      x[1] = width / 2;
      x[2] = width / 2;
    
      y[0] = height / 2;
      y[1] = height / 2;
      y[2] = height / 2;
    
      xFart[0] = 1.5;
      xFart[1] = 2.5;
      xFart[2] = 3.5;
    
      yFart[0] = -5;
      yFart[1] = 2.5;
      yFart[2] = -1.5;
    }
    

    Her ser vi hvordan vi jobber med verdiene i en array. Vi bruker firkantklammer med et tall i for å si hvilken verdi vi skal jobbe med. Den første verdien finnes på plass 0, og den siste verdien er på plass 2 som er én lavere enn størrelsen. Tallet for plasseringen kalles indeks. Indeksen er alltid én lavere enn om vi skulle telle vanlig fordi vi begynner på 0. Derfor er den siste indeksen én lavere enn størrelsen.

  • void draw() {
      for (int i = 0; i < x.length; i++) {
        x[i] += xFart[i];
        y[i] += yFart[i];
    
        if (x[i] < 0) {
          xFart[i] = -xFart[i];
        }
    
        if (x[i] > width) {
          xFart[i] = -xFart[i];
        }
    
        if (y[i] < 0) {
          yFart[i] = -yFart[i];
        }
    
        if (y[i] > height) {
          yFart[i] = -yFart[i];
        }
      }
    
      background(0);
      triangle(x[0], y[0], x[1], y[1], x[2], y[2]);
    }
    

    Her ser du en helt ny konstruksjon som vi skal se nærmere på i forklaringen nedenfor, men først kan du lagre og kjøre programmet.

Forklaring

I begynnelsen av draw har vi nå lagt inn noe som kalles en løkke, loop på engelsk. En løkke er en del med kode som utføres flere ganger. Det finnes andre slags løkker, og denne kalles en for-løkke. Inne i parentesene etter for har vi tre setninger. Den første, int i = 0, blir utført før løkken. Den neste, i < x.length, bestemmer om koden i løkken skal utføres eller om løkken er ferdig. Den siste, i++, utføres etter koden mellom krøllparentesene, altså innholdet i løkken. i bruker vi inne i løkken som indeks når vi jobber med arrayene istedenfor å skrive faste tall.

Så om vi går gjennom koden steg for steg, ser vi at først lages en variabel i av typen int som starter med verdien 0. int er typen som brukes for tall uten desimaler, altså heltall eller integer på engelsk. Så sjekker vi om i er mindre enn størrelsen til arrayen x. Hvis den er det, og det er den, for størrelsen til x er 3 og i er bare 0, kjøres koden mellom krøllparentesene. Når all koden mellom krøllparentesene er kjørt, så kjøres i++ som også er nytt for oss. i++ gjør det samme som i = i + 1, altså det øker i med 1. Nå sjekker vi igjen om i er mindre enn størrelsen til x. Og sånn fortsetter det helt til i blir like stor eller større enn størrelsen til x.

Løkker som ser slik ut, med et heltall som økes med én og sjekkes mot størrelsen på en array, er veldig vanlig og brukes til å jobbe med arrayer. Du kommer til å se mange slike i fremtidige oppgaver. Løkker kan kreve litt øving før man blir god på det, men etter hvert blir man veldig glad for at man slipper å skrive den samme koden mange ganger.

Utfordringer

Mangekanter

Nå skal vi se på hvordan vi kan lage mangekanter. Mangekanter er bare et generelt navn for en form med flere kanter, som trekanter, firkanter, femkanter, osv.

Sjekkliste

  • int KANTER = 5;
    float[] x = new float[KANTER];
    float[] y = new float[KANTER];
    float[] xFart = new float[KANTER];
    float[] yFart = new float[KANTER];
    

    Nå bruker vi en variabel for å sette størrelsen isteden. Dette hjelper leseligheten og gjør det enklere å endre antall kanter fordi vi bare trenger å endre tallet ett sted istedenfor fire steder.

  • void setup() {
      size(800, 600);
    
      for (int i = 0; i < KANTER; i++) {
        x[i] = random(width);
        y[i] = random(height);
        xFart[i] = random(-5, 5);
        yFart[i] = random(-5, 5);
      }
    }
    

    Denne løkken likner en del på den vi har i draw fra før. Vi har derimot introdusert en funksjon som heter random. Denne gir oss tilfeldige tall. Hvis vi kaller den uten noen verdier, random(), får vi et tall mellom 0 og 1. Hvis vi kaller den med én verdi, random(width), får vi et tall mellom 0 og verdien. Hvis vi bruker to verdier, random(-5, 5), får vi et tall mellom de to verdiene.

  • void draw() {
      for (int i = 0; i < KANTER; i++) {
        x[i] += xFart[i];
        y[i] += yFart[i];
    
        if (x[i] < 0) {
          xFart[i] = -xFart[i];
        }
    
        if (x[i] > width) {
          xFart[i] = -xFart[i];
        }
    
        if (y[i] < 0) {
          yFart[i] = -yFart[i];
        }
    
        if (y[i] > height) {
          yFart[i] = -yFart[i];
        }
      }
    
      background(0);
    
      beginShape();
      for (int i = 0; i < KANTER; i++) {
        vertex(x[i], y[i]);
      }
      endShape(CLOSE);
    }
    

    Her ser vi tre nye funksjoner: beginShape, vertex og endShape. beginShape angir at vi skal tegne en form. vertex betyr at vi skal legge til et hjørne i formen, den tar inn to verdier for posisjonen til hjørnet. endShape sier at formen er ferdig og klar til å tegnes på skjermen. Hvis vi kaller endShape uten CLOSE, blir ikke formen lukket og fylt.

Utfordringer

  • Pass på, om farten blir lavere enn den var, kan hjørnet bli sittende fast i kanten av vinduet. Det er fordi vi egentlig lar den bevege seg litt utenfor vinduet for så å snu. Sett x eller y til å være lik posisjonen til vinduskanten inne i if-setningene for å unngå det.

Forbedre denne siden

Funnet en feil? Kunne noe vært bedre? Hvis ja, vennligst gi oss tilbakemelding ved å lage en sak på Github eller fiks feilen selv om du kan. Vi er takknemlige for enhver tilbakemelding!

Rapporter et problemVis koden og fiks selv