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

Wenn du hinter einem Webfilter bist, stelle sicher, dass die Domänen *. kastatic.org und *. kasandbox.org nicht blockiert sind.

Hauptinhalt

Vektorbewegung

Dieses ganze Vektor-Mathe-Zeug klingt nach etwas, das wir verstehen sollten, aber warum? Wie wird es uns tatsächlich helfen, Code zu schreiben? Die Wahrheit ist, dass wir etwas Geduld haben müssen. Es wird einige Zeit dauern, bis wir die Grossartigkeit der Klasse PVector voll verstehen.
Dies ist tatsächlich ein häufiges Vorkommnis, wenn Sie zum ersten Mal eine neue Datenstruktur lernen. Wenn Sie zum Beispiel zum ersten Mal etwas über ein Array lernen, scheint es viel mehr Arbeit zu sein, ein Array zu verwenden, als einfach mehrere Variablen für mehrere Dinge stehen zu lassen. Aber dieser Plan bricht schnell zusammen, wenn Sie hundert oder tausend oder zehntausend Dinge brauchen.
Das Gleiche kann für PVector gelten. Was jetzt vielleicht nach mehr Arbeit aussieht, wird sich später auszahlen, und zwar ganz schön auszahlen. Und Sie müssen nicht zu lange warten, denn Ihre Belohnung kommt im nächsten Kapitel.

Geschwindigkeit

Vorläufig, wollen wir uns aber auf einfachere Dinge konzentrieren. Wie programmiert man aber Bewegung mit Vektoren? Nun, wir haben den Anfang davon im Beispiel mit dem springenden Ball gesehen. Ein Objekt auf dem Bildschirm hat immer eine Position (wo es sich gerade befindet) und eine Geschwindigkeit (wie es sich von einem Moment zum nächsten Bewegt). Die Geschwindigkeit wird zur Position addiert:
position.add(velocity);
Und dann können wir das Objektes an der neuen Position darstellen:
ellipse(position.x, position.y, 16, 16);
Dies ist das 1x1 der Bewegung:
  • Addiere die Geschwindigkeit zur Positiont
  • Zeichne das Objekt an seiner neuen Position
Im Beispiel des springenden Balls steht all dieser Code in der Funktion draw von ProcessingJS. Nun wollen wir aber all diesen Code für die Bewegung in einem Objekt implementieren. So können wir die Grundlagen für die Programmierung von bewegten Objekten für all unsere Programme mit ProcessingJS entwickeln.
In diesem Fall werden wir ein generisches Objekt Mover erstellen, welches ein Ding, das sich auf dem Bildschirm bewegt, beschreibt. Daher müssen wir die folgenden Fragen berücksichtigen:
  • Welche Daten braucht ein Mover?
  • Welche Funktionen braucht ein Mover?
Nun, unser Algorithmus zum 1x1 der Bewegung beantwortet uns diese Fragen schon. Ein Objekt Mover braucht zwei Datenelemente: Position (position) und Geschwindigkeit (velocity), und beides sind Objekte vom Typ PVector. Wir beginnen mit dem Konstruktor welcher diese Eigenschaften mit zufälligen Werten initialisiert:
var Mover = function() {
  this.position = new PVector(random(width), random(height));
  this.velocity = new PVector(random(-2, 2), random(-2, 2));
};
Die Funktionalität ist genauso einfach. Der Mover muss sich bewegen und sich darstellen können. Wir implementieren dies in den Methoden update() und display(). Wir verschieben den ganzen Code für die Bewegung in die Methode update() und für die Darstellung des Objektes in die Methode display().
Mover.prototype.update = function() {
  this.position.add(this.velocity);
};

Mover.prototype.display = function() {
  stroke(0);
  strokeWeight(2);
  fill(127);
  ellipse(this.position.x, this.position.y, 48, 48);
};
Wenn die Objekt-orientierte Programmierung für dich etwas Neues ist, ist ein Punkt hier vielleicht etwas verwirrend. Zu Beginn dieses Kapitels haben wir PVector besprochen. Das Objekt PVector ist eine Vorlage für die Objekte position und velocity. Was machen diese denn innerhalb eines weiteren Objektes Mover? Aber eigentlich ist dies so ziemlich das Normalste überhaupt. Ein Objekt ist einfach eine Hülle, welche Daten und Funktionen enthält. Diese Daten können Zahlen, Strings, Arrays oder andere Objekte sein! Dies werden wir während dieses Kurs immer wieder sehen. Im Tutorial zu Partikeln werden wir zum Beispiel ein Objekt welches ein System von Partikeln darstellt programmieren. Das Objekt ParticleSystem wird seine Daten in einem Array von Particle-Objekten speichern und jedes Particle-Objekt wird seine eigenen PVector-Objekte enthalten!
Komplettieren wir nun das Objekt Mover, indem wir eine Funktion implementieren, welche entscheidet, was zu tun ist, wenn das Objekt den Rand des Canvas berührt. Vorläufig machen wir etwas ganz Simples, mit dem das Objekt einfach auf der anderen Seite wieder ins Bild kommt.
Mover.prototype.checkEdges = function() {

  if (this.position.x > width) {
    this.position.x = 0;
  } 
  else if (this.position.x < 0) {
    this.position.x = width;
  }

  if (this.position.y > height) {
    this.position.y = 0;
  } 
  else if (this.position.y < 0) {
    this.position.y = height;
  }
};
Nun da wir das Objekt Mover komplett haben, können wir uns anschauen, was im Hauptprogramm angepasst werden muss. Zuerst deklarieren und initialisieren wir eine neue Instanz von Mover:
var mover = new Mover();
Dann rufen wir die entsprechenden Funktionen in draw auf:
draw = function() {
  background(255, 255, 255);

  mover.update();
  mover.checkEdges();
  mover.display(); 
};
Und hier siehst du nun das vollständige Beispiel. Versuche, etwas mit den Zahlen herumzuspielen, Code auszukommentieren und herauszufinden, was passiert:

Beschleunigung

OK. An dieser Stelle solltest du nun zwei Dinge gut verstehen: (1) was ein PVector ist und (2) wie man einen PVector in einem Objekt verwendet, um damit seine Position und Bewegung festzuhalten. Dies ist ein wichtiger erster Schritt und du verdienst schon eine gute Runde Applaus dafür! Bevor aber die Standing Ovations und kreischenden Fans kommen, musst du noch einen etwas größeren Schritt vorwärts machen. Unser Beispiel, 1x1 der Bewegung, ist nach einer Weile ziemlich langweilig. Der Punkt beschleunigt nie, verlangsamt auch nicht und ändert ebenfalls niemals seine Richtung. Für interessentantere Bewegungen, Bewegungen welche realitätsnah wirken, müssen wir unserem Mover-Objekt einen weiteren PVector für die Beschleunigung hinzufügen.
Wir definieren hier Beschleunigung als Änderungsrate der Geschwindigkeit. Schauen wir uns diese Definition einmal genauer an. Ist dies ein neues Konzept? Nicht wirklich. Geschwindigkeit ist definiert als die Änderungsrate der Position. Im Prinzip ist dies eine Kettenreaktion. Die Beschleunigung beeinflusst die Geschwindigkeit, welche wiederum die Position beeinflusst. Im nächsten Kapitel wirst du sehen, dass dieser Effekt sogar noch wichtiger wird, wenn Kräfte die Beschleunigung beeinflussen, welche die Position verändern. Im Code sieht das Ganze so aus:
velocity.add(acceleration);
position.add(velocity);
Als Übung legen wir von nun an eine Regel für uns selbst fest. Wir werden jedes Beispiel für den Rest dieses Tutorials schreiben, ohne je den Wert von velocity (Geschwindigkeit) oder position (Position) zu verändern (außer bei der Initialisierung). Mit anderen Worten, unser Ziel für die Programmierung von Bewegung ist nun: einen Algorithmus zu finden, wie wir die Beschleunigung berechnen können und so die Kettenreaktion von Beschleunigung, Geschwindigkeit und Ort ihren Zauber entfalten zu lassen. Ehrlich gesagt wirst du Gründe finden, weshalb du diese Regel missachten möchtest, aber sie ist wichtig, um die Prinzipien hinter unserem Algorithmus für die Bewegung zu verstehen. Daher müssen wir nun einen Weg finden, die Beschleunigung zu berechnen:
  1. Eine stetige Beschleunigung
  2. Eine komplett zufällige Beschleunigung
  3. Beschleunigung in Richtung der Maus
Der Algorithmus #1, eine stetige Beschleunigung, ist nicht besonders interessant, aber er ist der einfachste und hilft uns die Beschleunigung in unserem Code zu implementieren.
Zuerst müssen wir eine weitere Eigenschaft, welche für die Beschleunigung steht, vom Typ PVector im Konstruktor von Mover hinzufügen. Wir initialisieren sie mit (0,001,0,01) und verändern diesen Wert nie, da unser Algorithmus eine konstante Beschleunigung ist. Vieleicht denkst du, “Mein Gott, diese Werte sind fuchtbar klein!” Das ist richtig, sie sind ziemlich winzig. Es ist wichtig, dass du verstehst, dass unsere Beschleunigungswerte (in Pixel gemessen) sich mit der Zeit in der Geschwindigkeit summieren (je nach Framerate etwa 30 Mal pro Sekunde). Und damit der Betrag des Geschwindigkeitsvektors in einem vernünftigen Bereich bleibt, müssen unsere Beschleunigungswerte relativ klein bleiben.
var Mover = function() {
  this.position = new PVector(width/2,height/2);
  this.velocity = new PVector(0, 0);
  this.acceleration = new PVector(-0.001, 0.01);
};
Beachte, dass wir im Code oben die Geschwindigkeit ebenfalls mit 0 initialisiert haben, da wir wissen, dass sie dank der Beschleunigung im Laufe des Programms wächst. Dies geschieht in der Methode update():
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);  
};
Da wir die Geschwindigkeit ständig erhöhen, laufen wir Gefahr dass sie unglaublich groß wird, falls wir das Programm lange laufen lassen. Daher wollen wir die Geschwindigkeit begrenzen. Dies können wir mit der Methode limit von PVector tun, welche den Betrag eines Vektors begrenzt.
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Daraus ergibt sich Folgendes:
Wie groß ist der Betrag der Geschwindigkeit? Wenn er kleiner als 10 ist, alles ok; sie bleibt so wie sie ist. Wenn er größer als 10 ist, wird er auf 10 reduziert!
Schauen wir uns nun die Änderungen am Mover-Objekt, inklusive der Beschleunigung und limit() an:
Nun zu Algorithmus #2, eine komplett zufällige Beschleunigung. In diesem Fall wollen wir, anstatt die Beschleunigung im Objektkonstruktor zu initialisieren, in jedem Zyklus, d.h. bei jedem Aufruf von update(), einen neuen Beschleunigungswert haben.
Mover.prototype.update = function() {
  this.acceleration = PVector.random2D();
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Da der zufällige Vektor normalisiert ist, können wir ihn auf zwei Arten skalieren:
  1. Die Beschleunigung mit einem konstanten Wert skalieren:
    acceleration = PVector.random2D();
    acceleration.mult(0{,}5);
    
  1. Die Beschleunigung mit einem zufälligen Wert skalieren:
    acceleration = PVector.random2D();
    acceleration.mult(random(2));
    
Obwohl dies vielleicht offensichtlich erscheint, ist es wichtig zu verstehen, dass Beschleunigung nicht nur ein schneller werden oder verlangsamen eines bewegenden Objektes bedeutet, sonder jegliche Änderung des Betrags der Geschwindigkeit oder deren Richtung. Die Beschleunigung wird dazu verwendet um ein Objekt zu steuern. Und dies werden wir in den nächsten Kapiteln immer wieder sehen, wenn wir beginnen Objekte zu programmieren, welche Entscheidungen treffen wie sie sich über den Bildschirm bewegen.

Der Kurs "Natürliche Simulationen" ist eine Bearbeitung von "The Nature of Code" von Daniel Shiffman, und wird unter der Creative Commons Attribution-NonCommercial 3,0 Unported Lizenz verwendet.

Willst du an der Diskussion teilnehmen?

Noch keine Beiträge.
Verstehst du Englisch? Klick hier, um weitere Diskussionen auf der englischen Khan Academy Seite zu sehen.