Jeffrey Cross
Jeffrey Cross

Codebox: Swat eine (Arrayliste) von Zielen

Die letzte Codebox zeigte, wie Sie mit Ihrer Webcam Ihre Maus durch einen Zauberstab ersetzen. Wenn Sie in diesem Beispiel Ihren Stab in einen kreisförmigen Bereich des Bildschirms bewegen, ändern sich die austretenden Strahlen in eine zufällige Farbe. Dieser Artikel baut auf diesem Beispiel auf und zeigt, wie Sie komplexere Interaktionen erstellen. Diese Skizze zeigt nicht ein einzelnes stationäres Ziel, sondern eine Anzahl fliegender Ziele. Durch Berühren des Ziels (das Wort „Hut“) wird es in ein anderes Wort (in diesem Fall „Kaninchen“) umgewandelt, wie hier gezeigt:

Die Skizze veranschaulicht, wie Sie eine Liste interaktiver Objekte erstellen und verwalten. Egal, ob Sie Spiele, Partikelsysteme oder eine von Arduino gesteuerte Zaubershow schreiben (OK, ich habe meine Hand gekippt - dies ist das Thema eines zukünftigen Postens) - diese Tools werden Sie immer wieder als Sie verwenden weiter mit Processing.

Richten Sie die Skizze ein

Das Wichtigste zuerst - lassen Sie uns die Skizze zum Laufen bringen. Sie benötigen zwei Dateien für dieses Projekt: magic_words.pde und Target.pde. Starten Sie zunächst die Verarbeitung und fügen Sie den folgenden Code für magic_words.pde in das Hauptfenster ein.

Sie können entweder die erste Zeile markieren, ganz nach unten scrollen und dann mit Strg-c den Code kopieren (hart), oder Sie können auf diesen Link klicken (magic_words.pde), drücken Sie Strg + a, um den gesamten Text auszuwählen. und dann mit Strg + c kopieren (einfacher). Wenn Sie den Code kopiert haben, gehen Sie zurück zu Bearbeitung und fügen Sie ihn in das Hauptfenster ein. Verwenden Sie dann "Datei -> Speichern" aus der Menüleiste (oder einfach Strg + s) und speichern Sie die Datei unter dem Namen "magic_words" (bei der Verarbeitung wird automatisch ".pde" hinzugefügt).

Hier ist Target.pde, die zweite Datei, die Sie benötigen:

Kopieren Sie den Code mit einer beliebigen Methode in den Einfügepuffer (d. H. Alle markieren oder direkt mit der Datei verknüpfen). Diesmal müssen Sie ein neues erstellen TabAuf diese Weise können Sie bei der Verarbeitung von Skizzen mit mehreren Dateien verwalten. (Dies ist gewissermaßen das Erstellen einer neuen Registerkarte in einem Browserfenster).

Um eine Registerkarte zu erstellen, klicken Sie auf den nach rechts zeigenden Pfeil oben rechts im Verarbeitungsfenster.Bei der Verarbeitung werden Sie nach einem neuen Dateinamen gefragt - geben Sie "Ziel" ein. Wenn Sie den Dateinamen eingegeben haben, wird eine neue Registerkarte angezeigt, auf der Sie den Code einfügen können. Das folgende Diagramm zeigt Ihnen die Schritte, die Sie benötigen:

Das letzte, was wir tun müssen, ist eine nette Schriftart für das Ziel zu erstellen. (Die Schriftarten werden in Kapitel 6 der ersten Schritte mit der Verarbeitung beschrieben.) Warum fragst du? Im Auslieferungszustand hat Processing nur einen einfachen Befehl Text() Daraufhin wird Text angezeigt, aber Sie können nicht sagen, wie viel Platz sie auf dem Bildschirm einnehmen (was wichtig ist, wie wir gleich sehen werden). Außerdem handelt es sich lediglich um eine einfache alte Arial-Schriftart, daher sind sie nicht sehr interessant.

Um dies zu umgehen, können Sie im Menü Extras eine neue Schriftartdatei für Ihre Skizze erstellen. Nachdem Sie die Datei mit dem importiert haben loadFont () können Sie mit Typografie herumspielen. (W00t!). Der Vorgang zum Erstellen einer Schrift ist jedoch unkompliziert. Klicken Sie zunächst in der Menüleiste auf "Tools -> Create Font ...". Daraufhin erscheint der folgende Bildschirm:

Dann müssen Sie nur noch die gewünschte Schriftart auswählen (ich habe „Baskerville-Bold“ gewählt. Wenn Sie eine andere Schriftart verwenden möchten, müssen Sie den Namen der Schriftartdatei ändern magic_words.pde). Beachten Sie, dass sich der Dateiname am unteren Rand der Box ändert, wenn Sie verschiedene Optionen auswählen. Dies ist der Dateiname, den Sie in der Skizze verwenden müssen. Die Verarbeitung fügt automatisch ".vlw" am Ende hinzu.

Nachdem Sie die beiden Dateien geladen und die Schriftart installiert haben, führen Sie die Skizze aus. (Wie bei den meisten Projekten dieser Serie benötigen Sie auch eine Webcam.) Wenn Sie den Stab (oder einen anderen geeigneten Zeiger) der letzten Codebox verwenden, sollten Sie in der Lage sein, die verschiedenen Ziele zu überfliegen.

In den nächsten beiden Abschnitten wird beschrieben, wie die Skizze funktioniert. Der erste Teil beschreibt den Code in der Datei Target.pde, mit der das Target-Objekt, der Hauptbaustein des Skripts, erstellt wird. Der zweite Abschnitt beschreibt, wie die Datei magic_words.pde und ArrayList zum Verwalten mehrerer Zielobjekte verwendet wird.

Das Zielobjekt

Kapitel 9 von Erste Schritte mit der Verarbeitung führt Objekte und objektorientierte Programmierung (OOP) ein. Kurz gesagt, ein Objekt ist ein Baustein, der zur Erstellung komplexerer Programme verwendet wird. Objekte enthalten zwei grundlegende Elemente: Feldersind Variablen, die den aktuellen Status des Objekts bestimmen, und MethodenDies sind nur Funktionen, die das Objekt dazu bringen, etwas zu tun. Ein wesentlicher Teil der Leistungsfähigkeit von OOP besteht darin, dass es Ihnen dabei hilft, physisch über Ihren Code nachzudenken, indem Sie Sie dazu anregen, in einfacheren Komponenten zu denken.

Um Objekte zu verwenden, erstellen Sie zuerst eine Klasse (oder mehrere Klassen - Sie können viele verschiedene Objekte verwenden). Dies ist wie eine Vorlage, die alles beschreibt, was das Objekt tun kann. Nachdem Sie die Klasse definiert haben, verwenden Sie die Neu Befehl, um tatsächlich Objekte zu erstellen, die Sie in Ihren Skizzen verwenden können. Diese Unterscheidung kann etwas verwirrend sein, also denken Sie so darüber nach. Wenn Sie einen Kuchen backen, beginnen Sie mit einem Rezept. Das ist wie eine Klasse - Sie haben eine Beschreibung, aber selbst einen Kuchen. Um den Kuchen oder das Objekt zu erhalten, müssen Sie dem Rezept folgen, bevor Sie etwas zu essen haben. Das Erstellen neuer Objekte ist Aufgabe von Processing Neu Befehl - Er erstellt eine neue Objektvariable, indem eine spezielle Methode namens aufgerufen wird Konstrukteur. Der Konstruktor initialisiert die Objektvariablen und macht sie im Allgemeinen für die Aktion bereit. Der einzige Unterschied zwischen ihr und jeder anderen Methode besteht darin, dass sie denselben Namen wie die Klasse selbst hat.

OK, genug Bewertung. Reden wir über den Code. Wie bereits erwähnt, ist die Target-Klasse ein Baustein. Seine Felder umfassen:

  • Aktuelle Position, wie durch die Variablen dargestellt x und y
  • Geschwindigkeit und Richtung, wie durch die Variablen dargestellt dx und dy. Dies sind nur zufällig ausgewählte Werte.
  • Breite und Höhe, wie durch die Variablen dargestellt w und h
  • Schriftgröße (mehr dazu in Kürze)
  • Eine Flagge zeigt an, ob der Stab das Ziel berührt (Flagge ist der Programmierbegriff für jede Variable, die verwendet wird, um einen bestimmten Status darzustellen, z auf oder aus)
  • Der aktuelle Text des Ziels (d. H. "Hut" oder "Kaninchen")

Nach dem obligatorischen Ziel() Konstruktor (die einzige Aufgabe besteht darin, die Werte des vor und nach dem Text für das Ziel festzulegen), umfassen die Methoden:

  • Schritt(), wodurch sich das Ziel auf der Bühne bewegt. Dies funktioniert durch Hinzufügen der dx und dy zum x und y Variablen.
  • Farbe(), die das Ziel auf der Bühne an der (x, y) Position
  • detectCollision (), der feststellt, ob der Stab mit dem Ziel kollidiert ist
  • setBox (), der die Breiten- und Höhenvariablen des Ziels aktualisiert, je nachdem, ob der Stab ihn berührt hat
  • Umschalten(), was das Zielwort ändert. (d. h., wenn das aktuelle Wort "Hat" ist, dann Umschalten macht es "Kaninchen" und umgekehrt)
  • auf der Bühne(), die ein Flag zurückgibt, das anzeigt, ob das Ziel den sichtbaren Bildschirmbereich verlassen hat

Die ersten beiden Methoden sind ziemlich einfach, aber die verbleibenden Methoden, mit denen Kollisionen erkannt werden, verdienen etwas mehr Aufmerksamkeit. Wenn Sie sich von der ursprünglichen Codebox zurückrufen, ist Kollisionserkennung der Name für alle Arten, auf die Sie feststellen können, dass sich zwei Dinge auf dem Bildschirm schneiden. Im ursprünglichen Beispiel für den Zauberstab hatten wir ein kreisförmiges Ziel. Daher verwendeten wir eine einfache Abstandsformel, um zu bestimmen, ob sich die Koordinaten des Stabes innerhalb des Radius des Ziels befanden. In diesem Beispiel verwenden wir ein rechteckiges Ziel. Um die Sache etwas komplizierter zu gestalten, ändert sich die Größe des Ziels, wenn der Bedarf es berührt. Daher benötigen wir einige unterstützende Methoden, um sicherzustellen, dass alle Variablen mit dem aktuellen Status des Ziels übereinstimmen. Das folgende Diagramm zeigt die verschiedenen Stücke, die im Spiel sind:

Mit diesem Diagramm ist es ziemlich einfach, den Code für zu schreiben detectCollision ():

// Bestimmt, ist eine bestimmte x, y-Koordinate innerhalb der Box boolean detectCollision (float cx, float cy) {boolean retVal = false; if ((cx> x) && (cx <(x + w)) && (cy> (y-h)) && (cy <y)) {retVal = true; } return retVal; }

Endlich, das auf der Bühne() bestimmt, ob sich das Ziel noch in der sichtbaren Bühne befindet. Sobald es ausgeflogen ist, wird es recycelt, indem es an einer neuen Stelle mit einer neuen Geschwindigkeit und Richtung aufgestellt wird. Es ist tröstlich zu beachten, dass trotz der hinzugefügten Komplexitäten der größte Teil dieses Codes fast identisch ist mit Beispiel 5-17: Die Grenzen eines Rechtecks ​​in der Einführung.

Arrayliste der Ziele

Nun, da wir die Target-Klasse durchlaufen haben, wollen wir uns nun ansehen, wie man sie benutzt. Wie eingangs erwähnt, bestand das Hauptziel dieses Beispiels darin, zu zeigen, wie Sie mehrere Objekte dynamisch verwalten können. Standardarrays (die in Kapitel 10 von Getting Started with Processing beschrieben werden) sind zwar für viele Dinge von Vorteil, aber sie sind nicht sehr dynamisch, denn wenn Sie einmal angegeben haben, wie viele Elemente sie enthalten, bleiben Sie für immer dabei.

Angenommen, Sie wollten eine Reihe von Zielen haben, aber anstatt sie so zu recyceln, wie wir es hier getan haben, wollten Sie sie einfach löschen. In einem Standardarray können Sie keine Elemente löschen. Wenn Sie mit 5 begonnen haben, haben Sie immer 5, egal was passiert. Wenn Sie also etwas "löschen" möchten, müssen Sie eine Art unbeholfener Workaround haben. Oder, auf der anderen Seite, nehmen Sie an, Sie hätten ein Programm, in dem Sie normalerweise eine Handvoll Artikel verwalten müssten, aber manchmal haben Sie vielleicht Tausende. Bei Verwendung eines Standard-Arrays müssen Sie jedes Mal Tausende Platz schaffen, wodurch Speicherplatz verschwendet wird und Ihre Skizzen langsamer werden.

Verarbeitung Anordnungsliste ist ein Weg, um diese Einschränkungen zu umgehen. ArrayList ist kein einfacher Datentyp wie Float oder Int, sondern eine Bausteinklasse für die Verwaltung anderer Objekte. Es gibt Methoden zum Hinzufügen neuer Elemente, zum Löschen vorhandener Elemente, zum Ermitteln der Anzahl der Elemente in der Liste usw. Die Arbeit mit ArrayList ist nicht nur ein wirklich nützliches Werkzeug, sondern macht Sie auch mit den Techniken vertraut, die Sie in anderen, anspruchsvolleren Klassen wie HashMaps verwenden (etwas, das wir in zukünftigen Posts untersuchen werden). Wechseln Sie also zu magic_words.pde und schauen wir uns den Code an.

Das Erstellen einer ArrayList ist ziemlich einfach und erfolgt in dieser Zeile. Beachten Sie, dass wir keine Größe angeben müssen:

ArrayList-Ziele; // Eine ArrayList ist eine dynamische Methode zum Verwalten von Arrays

Nach der Deklaration können wir der ArrayList einige neue Objekte hinzufügen, die wir mit der hinzufügen() Methode. Hier ist der Code-Ausschnitt in der Konfiguration() Methode, die die ursprünglichen Ziele hinzufügt:

Ziele = neue ArrayList (); // Erzeuge eine neue Liste für (int i = 0; i <N; i ++) {Ziele.add (neues Ziel ("Hat", "Rabbit")); }

Dieser Ausschnitt weist einige interessante Punkte auf. Zunächst wird die Syntax für das Aufrufen einer Methode veranschaulicht object_variable.Klassenmethode (Argumentliste). Zweitens wird gezeigt, wie Sie ein Objekt als Argument für ArrayList verwenden können. Beachten Sie, wie wir das verwenden Neu Befehl in der Argumentliste - erstellt eine neue Zielobjektvariable und übergibt sie an die Liste. Schließlich zeigt das Snippet, wie wir das alles in einer Schleife machen können. Wir könnten 10, 100 oder 10.000 Objekte hinzufügen - die Größe der Liste ist vollständig dynamisch.

Dieser nächste Ausschnitt, der im erscheint zeichnen() Methode, zeigt, wie wir die verwenden können erhalten() Methode, um ein Element aus der ArrayList zu ziehen:

für (int i = 0; i <Ziele.size (); i ++) {Ziel t = (Ziel) Ziele. Ziel (i); // Hole das i-te Ziel aus dem Array t.paint (); // Paint it // Auf Kollisionen prüfen if (t.detectCollision (wandX, wandY)) {if (! T.inTarget) {t.toggle (); t.inTarget = true; }} else {t.inTarget = false; } t.step (); // Fortfahren auf dem Bildschirm // Wenn das aktuelle Ziel die Bühne verlassen hat, löschen Sie es aus der Liste und erstellen Sie ein neues Ziel. If (! T.onStage ()) {Zielen.remove (i); Targets.add (neues Ziel ("Hut", "Kaninchen")); }}

Die wichtigste Zeile hier ist die Ziel t = (Ziel) Ziele. Ziel (i);. Hier passieren einige Dinge. Die erste ist, dass wir eine neue Zielvariable erstellen t. Dieses Mal verwenden wir jedoch nicht die Neu Befehl. Warum fragst du? Dies ist darauf zurückzuführen, dass das Objekt, auf das wir zugreifen möchten, bereits vorhanden ist Konfiguration() Methode. Alles, was wir hier tun, ist das Abrufen. Zweitens haben wir diese Art von seltsamer Syntax (Ziel). Auf diese Weise teilen wir der Verarbeitung mit, welche Art von Variablen von uns erwartet wird. Dies wird als "Casting" bezeichnet und bedarf weiterer Erklärungen.

Wenn Sie sich erinnern, ist ArrayList ein generisches Werkzeug - wir könnten es mit einer Target-Variablen, der Jitterbug-Klasse verwenden, die in Kapitel 10 des Handbuchs Erste Schritte mit der Verarbeitung beschrieben wird, oder einer anderen Klassenvariablen, die wir in der Zukunft erstellen könnten. Processing (und Java, die zugrunde liegende Sprache, auf der es basiert) können jedoch nicht mit generischen Objekten umgehen. Es erfordert, dass wir jeder Variablen bei der Deklaration einen genauen Typ zuweisen. Hinzufügen (Ziel) zur Vorderseite des erhalten() Befehl ist das, was dies tut - wir sagen Verarbeitung: "Hey, wir ziehen ein 'Target'-Objekt ab." Sie werden dies als bezeichnet sehen Gießen in anderen Programmiermitteln.

Endlich haben wir die Targets.get (i) Teil der Linie. Dies sagt nur "ziehen Sie die ichDas Element aus der ArrayList der Ziele.

Sobald wir die Variable tatsächlich abgerufen haben tWir können read seine Variablen aufrufen, seine Methoden aufrufen und generell dazu bringen, dass wir unser Gebot abgeben. In diesem Beispiel rufen wir zuerst die Farbe() Methode, um das Ziel auf dem Bildschirm zu zeichnen. Als Nächstes prüfen wir, ob der Stab den Stift berührt (wie Sie sich an die letzte Codebox erinnern, wird die Position des Stabes durch die Variablen dargestellt wandX und wandY). Bei einer Kollision prüfen wir zuerst, ob der Stab vorhanden war bereits im Ziel (Mit anderen Worten, der Zauberstab könnte bei einer früheren Iteration von mit dem Objekt kollidiert sein Konfiguration() und immer noch in der Zielbox.) Wenn dies nicht der Fall ist (d. h. die Zielbox zum ersten Mal trifft), schalten wir den Text um und setzen die inTarget Flagge. Wenn sich der Stab bereits im Ziel befindet, setzen wir einfach das Zielflag auf "false", wodurch verhindert wird, dass das Ziel bei jeder Wiederholung von wechselt zeichnen(). Der nächste Befehl t.step (), erhöht einfach das Ziel x und y Positionen. Zum Schluss das letzte ob block prüft, ob das Ziel auf der Bühne nicht mehr sichtbar ist. Wenn dies nicht der Fall ist (d. H., Es ist vom sichtbaren Bereich des Bildschirms abgegangen), wird das Ziel mit der Taste aus der ArrayList entfernt Löschen() Methode; Ein neues Ziel wird dann an einem beliebigen Ort hinzugefügt.

Wütend! Das ist eine Menge abstrakter Dinge, aber es lohnt sich zu verstehen, da Sie diese Techniken immer wieder anwenden werden. Unabhängig davon, ob Sie eine ArrayList, eine HashMap oder eine andere allgemeine Datenstruktur verwenden, ist das Verständnis dieser grundlegenden Schritte - Erstellen eines neuen Objekts, Speichern in einer generischen Datenstruktur und Abrufen - von grundlegender Bedeutung für anspruchsvollere Programme.

In der nächsten Codebox nehmen wir eine Pause von der Webcam und erkunden, wie Sie mit einer wirklich coolen Bibliothek namens controlP5 anspruchsvollere Informationen von Benutzern erhalten. Oh, und Fraktale. Das machen wir auch.

Mehr: Alle Codebox-Spalten anzeigen

Aktie

Leave A Comment