Flere Objekter

Fra Holstebro HTX Wiki
Skift til: navigering, søgning

Eksemplet her tager udgangspunkt i Arrays[1].

Der er ikke noget spil-element i eksemplet her, det går i alt sin enkelthed ud på at få en række cirkler til at "falde" ned over skærmen.

Et fast antal cirkler, løst med flere arrays

Der oprettes en konstant objects med antallet af arrays, så man simpelt kan rette hvor mange cirkler der skal være på skærmen.

For at holde styr på elementerne oprettes to arrays posX og posY hvor hvert index indeholder positionen på skærmen.

Da elementerne skal falde med forskellig hastighed, så oprettes et array hastY der indeholder afstanden der skal rykkes nedad for hver frame.

Elementerne skal også have forskellig størrelse, så der laves et array diam med elementernes diametre.

Programmets udseende efter kørsel i et stykke tid
int objects = 20;
float [] posX = new float[objects];
float [] posY = new float[objects];
float [] hastY = new float[objects];
float [] diam = new float[objects];

I setup() angives skærmstørrelsen og hvor hurtigt skærmen skal opdateres.

I et loop sættes alle værdierne for elementerne. Først sættes en tilfældig diameter mellem 15 og 25 pixel. Dernæst placeres objektet tilfældigt ud fra hele bredden af skærmen og i en afstand af diameteren over skærmen. Til sidst sættes en tilfældig afstand den skal rykke for hver frame på mellem 3 og 4.

void setup() {
  size(400, 400);
  frameRate(60);
  for (int n = 0; n < objects; n++) {
    diam[n] = 15 + random(10);
    posX[n] = random(width);
    posY[n] = 0 - diam[n];
    hastY[n] = 3 + random(1);
  }
}

I draw() sættes slettes baggrunden først og der angives en farve egenskab.

I et loop tegnes alle cirklerne ud fra deres position og størrelse. Herefter rykkes alle elementerne den angivne afstand ned ad skærmen, og hvis de er kommet under ud af skærmen, så placeres de lige over skærmen igen.

void draw() {
  background(255);
  fill(128);
  for (int n = 0; n < objects; n++) {
    ellipse(posX[n], posY[n], diam[n], diam[n]);
    posY[n] += hastY[n];
    if (posY[n] > height + diam[n]) {
      posY[n] = 0 - diam[n];
    }
  }
}

Et fast array med objekter

Programmet her løser fuldstændig den samme problemstilling, bare struktureret på en anden måde.

Der anvendes en Class kaldet Element der er et tilfældigt valgt navn.

Først oprettes et array dots på 20 af typen Element, så der kan være 20 elementer.

int objects = 20;
Element [] dots = new Element[objects];

I setup() indledes med det samme som før, hvorefter de 20 instanser af Element oprettes og gemmes i arrayet dots.

void setup() {
  size(400, 400);
  frameRate(60);
  for (int n = 0; n < objects; n++) {
    dots[n] = new Element();
  }
}

I draw() opdateres elementerne i dots, hvor metoden update() tegner elementet ud fra objektets egenskaber, og move() flytter elementet ved at modificere elementets egenskaber.

void draw() {
  background(255);
  fill(128);
  for (int n = 0; n < objects; n++) {
    dots[n].update();
    dots[n].move();
  }
}

Det er normalt at man i processing opretter en Class-definition i sin egen fil (en Tab i kodevinduet).

For at kunne bruge objekterne, så skal der laves en Class-definition af Element som ser ud som den følgende kode. Koden indeholder 4 forskellige dele, som altsammen skal være inde i class-definitionen. Den første del består af de 4 egenskaber posX, posY, hastY og diam. disse 4 egenskaber er variabler der kun eksisterer inde i objektet når det bliver oprettet.

Den næste del er Constructoren, der skal have class-navnet (her Element), og det ligner en funktion, bare uden typen (som tit er void). Constructoren kaldes når man opretter et nyt objekt af typen Element, så derfor tildeles egenskaberne værdier på dette tidspunkt (som det skete i setup() før).

De to sidste dele af class-definitionen er de to metoder update() og move(). Det metoderne laver er at update() tegner elementet og move() flytter elementet.

class Element {
  float posX;
  float posY;
  float hastY;
  float diam;
  
  Element() {  // Constructor - kaldes med new Element
    diam = 15 + random(10);
    posX = random(width);
    posY = 0 - diam;
    hastY = 3 + random(1);
  }
  
  void update() {
    ellipse(posX, posY, diam, diam);
  }
  
  void move() {
    posY += hastY;
    if (posY > height + diam) {
      posY = 0 - diam;
    }
  }
}

Hele ideen med at lægge ting over i en class for sig er, at man kan styre at det der sker med objektet det kodes i classen, så forskellige objekter ikke har indflydelse på hinanden.

En dynamisk ArrayList med variabelt antal objekter

I dette eksempel starter programmet med en tom liste af elementer, og opretter så elementerne løbende i programflowet, og for at programmet ikke skal ende med at fylde hele PC'ens hukommelse, så fjernes elementerne igen. Til dette formål anvendes en ArrayList[2]

Sammen med ArrayList'en defineres en variabel, der siger hvor mange frames der er til det næste objekt skal oprettes:

ArrayList<Element> dots = new ArrayList<Element>();
int toNext = 1;

i setup() bliver der ikke oprettet nogen variabler, der sættes lige en textSize(20) for at kunne lave en visning af hvor mange aktive elementer der er i ArrayList'en.

void setup() {
  size(400, 400);
  frameRate(60);
  textSize(20);
}

Det er i draw() at der håndteres oprettelsen af elementer til visningen. For hver frame trækkes en fra toNext, og når den rammer 0, så sættes der en ny værdi på toNext som er tilfældig fra 1 til og med 4, og der oprettes så et nyt element. Ud fra en test af programmet, så ligger antallet af elementer på ca. 50 når skærmen er fyldt op. Dette antal afhænger af det tilfældige tal i toNext, men også af hvilken hastighed elementerne har ned over skærmen.

void draw() {
  background(255);
  fill(128);
  toNext--;
  if (toNext == 0) {
    toNext = 1 + int(random(4));
    dots.add(new Element());
  }

Efter administrationen med at oprette nye elementer, så tegnes alle elementer i en for-løkke, som løber alle elementer igennem i dots.

  for (Element dot : dots) {
    dot.update();
  }

I en anden for-løkke, som skal løbe baglæns igennem arrayet foretages flytningen af elementerne, og hvis flytningen resulterer i at elementet er kommet ud over skærmen, så fjernes det fra ArrayList'en.

Nederst på skærmen vises hvor mange elementer der er i ArrayList'en.

  for (int n = dots.size() - 1; n >= 0; n--) {
    if (! dots.get(n).move()) {
      dots.remove(n);
    }
  }
  text(dots.size(), 20, 390);
}

I class-definitionen anvendes de samme egenskaber og metoder som før, men da move-metoden skal kunne angive om den er kommet neden ud af skærmen, så skal den returnere en indikation på dette. Det gøres ved at lade den returnere en boolean, som er true hvis flytningen bliver inden for skærmen, og bliver false hvis elementet er kommet uden for skærmen.

Det kan virke lidt kryptisk at gøre det på denne måde, det ville umiddelbart virke mere logisk, hvis det skete inde i class-koden. Problemet er bare at classen ikke kan fjerne det objekt den afvikler - så får den ikke ryddet op efter sig selv i den struktur den ligger i, derfor skal det ske ude fra med en metode til at fjerne et element fra ArrayList'en.

  boolean move() {
    posY += hastY;
    if (posY > height + diam) {
      return false;
    }
    return true;
  }

Referencer

  1. Arrays Tutorial på Processing.org
  2. ArrayList på processing.org