If you're seeing this message, it means we're having trouble loading external resources on our website.

Ha webszűrőt használsz, győződj meg róla, hogy a *.kastatic.org és a *.kasandbox.org nincsenek blokkolva.

Fő tartalom

Részecsketípusok

Most az objektumorientált programozás egy haladó technikáját fogjuk felhasználni, az öröklődést, úgyhogy érdemes újra átnézned az „Objektumöröklődés” részt a Bevezetés a JS-be fejezetben és azután gyere vissza! Ne aggódj, megvárunk!
Úgy érzed, jól megértetted, hogyan működik az öröklődés? Akkor jó, mert az öröklődést fogjuk felhasználni ahhoz, hogy a Particle objektumnak különböző altípusait készítsük el, ezeknek számos közös funkcionalitása lesz, de több alapvető eltérést is tartalmaznak.
Nézzük át az egyszerűsített Particle implementációnkat:
var Particle = function(position) {
  this.acceleration = new PVector(0, 0.05);
  this.velocity = new PVector(random(-1, 1), random(-1, 0));
  this.position = position.get();
};

Particle.prototype.run = function() {
  this.update();
  this.display();
};

Particle.prototype.update = function(){
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
};

Particle.prototype.display = function() {
  fill(127, 127, 127);
  ellipse(this.position.x, this.position.y, 12, 12);
};
Ezután készítsünk egy új objektumtípust a Particle alapján, amit Confetti-nek fogunk hívni. Egy egyszerű konstruktor függvénnyel fogjuk kezdeni, ami ugyanannyi argumentumot fogad, egyszerűen meghívja a Particle konstruktorát, és onnan küldi tovább az argumentumokat:
var Confetti = function(position) {
  Particle.call(this, position);
};
Annak érdekében, hogy a Confetti használhassa a Particle objektum metódusait, meg kell adni, hogy a prototípusa a Particle prototípuson alapuljon.
Confetti.prototype = Object.create(Particle.prototype);
Confetti.prototype.constructor = Confetti;
A jelenlegi Confetti objektum pontosan ugyanúgy viselkedik, mint a Particle. Az öröklődés lényege nem az, hogy duplikátumokat gyártsunk, hanem az a cél, hogy olyan új objektumokat készítsünk, amelyekben sok funkcionalitás közös, de bizonyos dolgokban különböznek. Miben különbözzön a Confetti objektum? Hát, ha a névből indulunk ki, akkor másképp kellene, hogy kinézzen. A Particle objektumaink ellipszisek, a konfetti sokszor kis papírnégyzet, tehát legalább a display metódust meg kellene változtatnunk úgy, hogy négyzeteket rajzoljunk.
Confetti.prototype.display = function(){
  rectMode(CENTER);
  fill(0, 0, 255, this.timeToLive);
  stroke(0, 0, 0, this.timeToLive);
  strokeWeight(2);
  rect(0, 0, 12, 12);
};
Az alábbi programban van egy Particle objektum és egy Confetti objektumpéldány. Figyeld meg, hogy hasonlóan viselkednek, de másképpen néznek ki! (A programban található megjegyzések: 1. sor: Dan Shiffman, natureofcode.com példája alapján; 3-8. sor: Ez a program 2 objektumot tartalmaz: - Részecske -- Konfetti (Particle al-típusa) A program végén készít egy Particlet és egy Confettit, és animálja azokat.)

Adjunk hozzá forgatást

Legyen még okosabb a programunk! Mondjuk pörögjenek a Confetti részecskék, miközben átrepülnek a rajzvásznon! Persze a szögsebességet és a szöggyorsulást modellezhetnénk ugyanúgy, mint a Rezgések fejezetben. Ehelyett egy gyors és felületes megoldást választunk.
Tudjuk, hogy a részecske x helyzete valahol 0 és az ablakszélesség között található. Mi lenne, ha azt mondanánk: amikor a részecske x helyzete 0, a forgási sebesség legyen 0; amikor az x helyzete eléri az ablakszélességet, akkor a forgási sebesség legyen TWO_PI? Ismerősen hangzik? Ha van egy adott intervallumba eső értékünk, amit át akarunk konvertálni egy másik intervallumba, azt bármikor megtehetjük a ProcessingJS map() függvénye segítségével.
var theta = map(this.position.x, 0, width, 0, TWO_PI);
Hogy még gyorsabban pörögjön, a szög intervallumát 0-tól TWO_PI·2-ig állítjuk be. Lássuk, hogyan tudjuk ezt a kódrészletet beilleszteni a display() metódusba!
Confetti.prototype.display = function(){
  rectMode(CENTER);
  fill(0, 0, 255);
  stroke(0, 0, 0);
  strokeWeight(2);
  pushMatrix();
  translate(this.position.x, this.position.y);
  var theta = map(this.position.x, 0, width, 0, TWO_PI * 2);
  rotate(theta);
  rect(0, 0, 12, 12);
  popMatrix();
};
Ez lett az eredmény – indítsd újra néhányszor, hogy lásd a forgatás eredményét! (A programban található megjegyzések: 1. sor: Dan Shiffman, natureofcode.com példája alapján; 3-8. sor: Ez a program 2 objektumot tartalmaz: - Részecske -- Konfetti (Particle al-típusa) A program végén készít egy Particlet és egy Confettit, és animálja azokat.)
A theta számítását alapozhatnánk az y pozícióra is, aminek egy kicsit más lesz a hatása. Mi az oka ennek? Nos, a részecskének az y irányban nullától eltérő konstans gyorsulása van, ami azt jelenti, hogy az y sebesség az idő lineáris függvénye, az y pozíció pedig az idő négyzetes függvénye. Az alábbi ábrán láthatod a fenti program adatai alapján generált grafikonokat:
A pozíció (egy lefelé görbülő vonal), a sebesség (egy lefelé haladó egyenes) és a gyorsulás (egy vízszintes vonal) függvénye.
Ez azt jelenti, hogyha a konfetti gyorsulását az y helyzet alapján változtatjuk, akkor a forgatás is négyzetes lesz. Ez fizikai szempontból nem lesz túl pontos, mivel a valóságban a levegőben aláhulló konfetti pörgése meglehetősen bonyolult, de próbáld ki, így is eléggé valószerűen néz ki. Tudnál javasolni más olyan függvényt, ami még realisztikusabb?

Egy másmilyen részecskerendszer

Most pedig azt szeretnénk, hogy sok Particle és Confetti objektumot tudjunk készíteni, hiszen ezért hoztuk létre a ParticleSystem objektumot. Ki tudjuk-e vajon bővíteni úgy, hogy a Confetti objektumokat is nyomon tudja követni? Alább látható egy olyan módszer, amivel ezt megtehetjük, átmásolva azt, amit a Particle objektumra írtunk meg:
var ParticleSystem = function(position) {
  this.origin = position;
  this.particles = [];
  this.confettis = [];
};

ParticleSystem.prototype.addParticle = function() {
    this.particles.push(new Particle(this.origin));
    this.confettis.push(new Confetti(this.origin));
};

ParticleSystem.prototype.run = function(){
  for (var i = this.particles.length-1; i >= 0; i--) {
    var p = this.particles[i];
    p.run();
  }
for (var i = this.confettis.length-1; i >= 0; i--) {
    var p = this.confettis[i]; p.run();
  }
};
Figyeld meg, hogy két különálló tömbünk van, egy a részecskéknek és egy másik a konfettik számára. Bármit csinálunk a részecskékkel, ugyanazt meg kell tenni a konfettikkel is! Ez bosszantó, mert azt jelenti, hogy kétszer annyi programsort kell írni, és ha változtatni kell, azt két helyen kell átvezetni. Meg tudjuk spórolni ezt az ismétlődést, mivel a JavaScriptben lehetőség van különböző típusú objektumok egy tömbben való tárolására, és mivel az objektumoknak közös az interfészük – a run() metódust hívjuk meg és mindkét objektumtípusban definiáljuk ezt az interfészt. Úgyhogy továbbra is egy tömböt fogunk tárolni, véletlenszerűen döntjük el, hogy melyik objektumtípust adjuk hozzá, és egy tömbön fogunk végighaladni. Ez így sokkal egyszerűbb programmódosítást jelent – mindössze az addParticle() metódust kell változtatni.
var ParticleSystem = function(position) {
  this.origin = position;
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function() {
  var r = random(1);
  if (r < 0.5) {
    this.particles.push(new Particle(this.origin));
  } else {
    this.particles.push(new Confetti(this.origin));
  }
};

ParticleSystem.prototype.run = function(){
  for (var i = this.particles.length-1; i >= 0; i--) {
    var p = this.particles[i];
    p.run();
    if (p.isDead()) {
      this.particles.splice(i, 1);
    }
  }
};
Miután mindent összeraktunk:

Szeretnél részt venni a beszélgetésben?

Még nincs hozzászólás.
Tudsz angolul? Kattints ide, ha meg szeretnéd nézni, milyen beszélgetések folynak a Khan Academy angol nyelvű oldalán.