1. Kapitel
Basics der Programmierung
Programmieren mit processing oder p5.js
In diesem Kapitel möchte ich Dir die Basics der Programmierung meiner ausführbaren Programmbeispiele vermitteln, um Dir die Nachverfolgung oder eigenständigen Entwicklung solcher Programme zu ermöglichen.Als die Entwickler von processing sich an die Arbeit machten, hatten sie das Ziel, eine Entwicklungsumgebung für "jedermann" zu schaffen. Die Ansprüche an Programmierkenntnisse sollten möglichst gering gehalten werden. Zu Zeiten der Konzipierung der ersten Version von Processing spielten die Themen "Internet" bzw. "Mobile Endgeräte" noch keine Rolle, was zur Folge hatte, dass die von den Nutzern entwickelten Lösungen in erster Linie lokal auf dem Desktop liefen. In der zweiten Version wurde eine Interpreter zur Verfügung gestellt, der JAVA in JAVASCRIPT convertierte und damit Auftritte im Internet ermöglichte. Allerdings mit dem Mangel, dass sie auf mobilen Endgeräten nicht bedienbar sind, weil die Behandlung von touch-events nicht hinreichend möglich ist. In der dritten Version von Processing steht dieser Converter nun nicht mehr zur Verfügung. Statt dessen wurde eine neue Entwicklungsumgebung, nämlich p5.js ins Leben gerufen. Wie der Appendix '.js' deutlich macht, handelt es sich hierbei um ein javascript-basiertes Tool. Jetzt sind auch Internet-Auftritte auf mobilen Endgeräten möglich. Natürlich verlangt der Umstieg auf p5.js einiges an Umstellungen, die aber relativ schnell zu erlernen sind. In p5.js werden die Unterschiede erläutert und mit Programmbeispielen hinterlegt. Auf meiner Homepage stelle ich beide Programmversionen als download zur Verfügung, auch wenn die Processing-Lösungen nicht immer dem letzten Stand entsprechen. Alle aktuellen Programmbeispiele sind in p5.js geschrieben.
Processing
Processing hat verschiedene Vorteile, von denen die wichtigsten hier genannt sein:- Processing ist ein open source Projekt,
- Processing ist Java-basiert und kooperiert mit JavaScript,
- Dank JavaScript können web-Applikationen geschrieben werden,
- Dank der komfortablen Matrix-Befehle können voneinander unabhängige Koordinatensysteme kreiert werden
- Processing verfügt über viele features, die eine Vielzahl von Bewegungsmodi unterstützt
- Processing verfügt über multimedia-Fähigkeiten
Es ist nicht meine Absicht, eine detailierten Einführung in "processing" zu geben -
dafür gibt es gute Tutorials. Nein,
ich möchte nur auf eine Besonderheit eingehen, die manchmal zu Verwirrung führt.
zeigt den prinzipiellen Pogrammlauf eines in
"processing" geschriebenen Programmes. Zu Beginn des Programms wird, wie üblich, eine Deklaration von Variablen und Klassen ausgeführt. Daran schließt
sich eine setup()-Sequenz an, die nur einmal durchlaufen wird. Im Setup werden
Variablen mit Startwerten versehen oder Klassen instanziiert. Ist dies erfolgt, beginnt
der eigentliche Programmlauf. Und hier liegt der Unterschied zu anderen Objekt
orientierten Programmiersprachen: diese als draw() bezeichnete Sequenz wird,
wenn nicht das Programm absichtlich gestoppt wird, fortlaufend wiederholt. Und zwar
im Takt des Bildschirm-Refreshs. Damit werden bewegte Bilder einfach wie bei einem
Film oder Video möglich. Ein Film besteht ja auch aus aufeinander folgenden Bildern,
genau das bewirkt die draw() Routine!
Allerdings, der Programmierer muss sich der Tatsache stets bewußt sein, dass die draw() Sequenz ohne sein Zutun immer wieder durchlaufen wird. Alle Nutzerinputs, die eigentlich nur bei Bedarf abgefragt werden, müssen immer durch geeignete Verzweigungen aus dem steten Zyklus heraus vorgenommen werden.
Die Bildschirm-Refresh-Rate kann im setup() voreingestellt werden. Dafür gibt es das Kommando frameRate(). Wird diese Funktion mit dem Wert 50 aufgerufen, bedeutet dies, dass je Sekunde 50-mal das Bild gewechselt wird. Und damit jedes Bild für die Dauer von 1/50 s dargestellt wird. So wird für die Programmausführung ein festes Zeitraster vorgegeben. In der Regel orientiert sich diese Rate an der Physiologie unseres Sehens. Also 25 - 100 mal pro Sekunde wird das Bild auf dem Bildschirm erneuert, also wird die draw() Routine 25 - 100 mal pro Sekunde durchlaufen. Sollte allerdings der in draw() enthaltene Code so umfangreich oder so anspruchsvoll sein, dass die CPU die erforderliche Leistung nicht aufbringen kann, dann kann es zu einer Verringerung der refresh-Rate kommen. Dies hat Konsequenzen für die interne Zeitbasis, die wir zur Berechnung der Zeitfunktionen benötigen.
Allerdings, der Programmierer muss sich der Tatsache stets bewußt sein, dass die draw() Sequenz ohne sein Zutun immer wieder durchlaufen wird. Alle Nutzerinputs, die eigentlich nur bei Bedarf abgefragt werden, müssen immer durch geeignete Verzweigungen aus dem steten Zyklus heraus vorgenommen werden.
Die Bildschirm-Refresh-Rate kann im setup() voreingestellt werden. Dafür gibt es das Kommando frameRate(). Wird diese Funktion mit dem Wert 50 aufgerufen, bedeutet dies, dass je Sekunde 50-mal das Bild gewechselt wird. Und damit jedes Bild für die Dauer von 1/50 s dargestellt wird. So wird für die Programmausführung ein festes Zeitraster vorgegeben. In der Regel orientiert sich diese Rate an der Physiologie unseres Sehens. Also 25 - 100 mal pro Sekunde wird das Bild auf dem Bildschirm erneuert, also wird die draw() Routine 25 - 100 mal pro Sekunde durchlaufen. Sollte allerdings der in draw() enthaltene Code so umfangreich oder so anspruchsvoll sein, dass die CPU die erforderliche Leistung nicht aufbringen kann, dann kann es zu einer Verringerung der refresh-Rate kommen. Dies hat Konsequenzen für die interne Zeitbasis, die wir zur Berechnung der Zeitfunktionen benötigen.

Abb. prinzipieller Programmablauf
Noch ein Hinweis zur zeitabhängigen Darstellung eines bewegten Objektes. Da sich die draw()-Sequenz zyklisch wiederholt, werden ohne geeignete Maßnahmen für alle errechneten Orte das Objekt bleibend(!) dargestellt. Ein Spur entstünde dabei. Um das zu verhindern wird bei zu Beginn jedes draw()-Zyklus das letzte Bild vollständig gelöscht, um anschließend mit den neuen Werten neu gezeichnet zu werden. Der Befehl, der dies ausführt, ist der background()-Befehl.
Viele der hier vorgestellten Programme verwenden Funktionen oder Klassen von Funktionen, die in den unterschiedlichsten Situationen Anwendung finden. Sind diese Programme hinreichend allgemein gehalten, werden sie sinnvoller Weise nicht im Hauptprogramm (draw()) untergebracht, sondern separat in einer Library. So stehen sie allen Programmen zur Verfügung. In Processing können solche Programme mittels Tabs eingebunden werden (siehe ).

Abb. Einbindung von Tabs in Processing
Tabs sind die in oben beschrifteten Reiter (z.B. Basics_v2.0). Zweckmäßig ist in diesem Zusammenhang die Einrichtung eines Ordners "Libraries", in dem alle Programme und ihre Versionen allgemeingültiger Aufgaben abgelegt sind. In processing ist es allerdings notwendig, dass die erforderlichen Library-Programme in den Ordner des aufrufenden Hauptprogramms kopiert werden, erst dann stehen Sie als Tab zur Verfügung ()!
In processing müssen alle Unterprogramme physisch im Ordner des Hauptprogramms verfügbar sein! Das bedeutet, größte Sorgfalt beim Editieren der Unterprogramme walten zu lassen, da die Unterprogramme zunächst nur lokal in diesem Ordner abgespeichert sind. Erst, wenn diese Änderung hinreichend getestet wurde, kann sie als neue Version in die Library übernommen werden. Aus diesem Grunde stelle ich keine geschlossene Library für die processing-Versionen meiner Beispielprogramme zum Download zur Verfügung - alle erforderlichen Unterprogramme (Tabs) sind in jedes downloadbaren zip-File eingeschlossen!

Abb. Verfügbarmachung von Tabs in Processing
p5.js
Der grundsätzliche Programmablauf von "p5.js" unterscheidet sich nicht von dem in gezeigten Ablauf in "processing". Auch für "p5.js" gibt es ein geeignetes Tutorial.p5.js erzeugt ein script (javaScript), welches in eine html-Seite eingebunden - eingebettet - wird (). Im Beispiel ist dies das Programm "pGrund_0010mini.js". Des weiteren werden aber auch die Includes, die ebenfalls als scripte vorliegen, geladen. Hier ist zu unterscheiden in die "libraries", die von p5.js zur Verfügung gestellt und als Basis der Programmentwicklung eingefügt werden und die Includes, die den Tabs von Processing gleich zu setzen sind. Also entspricht z.B. pControls_v0.0.js, die alle Buttons, Schieberegler und sensitiven Elemente beinhaltet dem Tab controls_vX.X.pde der processing-Lösungen. Neu ist das file "canCSS.css", welches für das Styling der html-Seite verantwortlich ist.
Mit dem abschließenden <div id="pGrund_0010mini" class="canvasStyle"></div> wird die Ausführung des scriptes gestylt und auf der html-Seite positioniert.
Abb. Verfügbarmachung von Tabs und Aufruf eines p5.js- scripts in einer HTML-Seite
zeigt die zu
gehörende Ordnerstruktur. Anders als in Processing werden hier die Includes bzw. die
Libraries zentral in einem Ordner gelagert. Der Ordner p5-includes enthält alle Includes,
die für den Programm-Ablauf erforderlich sind, aber auch die Laufzeitumgebung p5.js und das
Styling css. Die zentrale Ablage dieser Files erleichtert die Pflege der
Includes, da eine Änderung alle vergangenen und künftigen Entwicklungen gleichermaßen betrifft.

p5 Library und Includes
Die Programmbeispiele
Einordnung der Programmbeispiele
Alle Programmbeispiele, ob im Fließtext eingebettet oder als ausführbares Programm (erreichbar über das PC-Symbol) stehen
zum freien Download zur Verfügung. Damit kann jeder Nutzer dieser site den Code herunter laden, lesen oder auch verwenden.
Dabei ist allerdings zu beachten, dass die Codes für beliebige Endgeräte geschrieben sind, also sowohl für Desktop, die mit
Maus-Interaktion, als auch für mobile Anwendungen, die mit touch-Bedienung funktionieren müssen. Zwangsläufig wird dadurch der Code
umfangreicher als für eine reine Desktop-Lösung. Im wesentlichen betrifft dies die Unterprogramme "basics_vX.x" und "controls_vX.x",
aber marginal auch andere Programme und Unterprogramme. Immer dann, wenn z.B. die Funktion getMediaType()
aufgerufen wird, wird getestet, welches Endgerät gerade in Benutzung ist. Der Rückgabewert ist eine ganze Zahl mit der Bedeutung:
0: Desktop, 1: mobile landscape bzw. -1: mobile portrait.
Mit dieser Information kann das Styling des Programms beeinflusst werden!
Alle Programmbeispiele können auch autonom laufen, wenn das gewünschte Beispielprogramm nach dem download in die nebenstehende Ordnerstruktur geladen wird (). Dazu wird in diesem Beispiel ein übergeordneter Ordner AGP Programme mit dem Unterordner application angelegt. In diesen Ordner wird das heruntergeladene, gezippte Beispielprogramm geladen und entpackt. Außerdem wird in den Ordner AGP Programme das gezippte Include-Verzeichnis p5_includes.zip geladen und entpackt. Dabei wird automatisch der Ordner p5_includes angelegt. Dieser enthält dann die p5-Library, alle verwendeten Include-Files und das Styling-File.
Im gezeigten Beispiel in ist das gezippte File pGrund_0023_Schraeger_Wurf.zip in den Ordner AGP Programme geladen worden. Nach dem Entpacken siehst Du den Ordner pGrund_0023_Schraeger_Wurf, der die Files pGrund_0023_Schraeger_Wurf.js und Pindex.html enthält.
Ein Doppelclick auf das File Pindex.html öffnet in der Regel das Beispielprogramm im Standard-Browser. Das klappt aber nicht immer! Enthält nämlich das Beispielprogramm Images, die hinzugeladen werden müssen, streikt der Browser aus Sicherheitsgründen. Obwohl die Images im gezippten Beispielordner mitgeliefert worden sind. Einzig mögliche Lösung ist die Installation eines lokalen web-Servers, wie z.B. den Apache, der dann das Starten der Beispielprogramme in einem localhost gestattet.
Alle Programmbeispiele können auch autonom laufen, wenn das gewünschte Beispielprogramm nach dem download in die nebenstehende Ordnerstruktur geladen wird (). Dazu wird in diesem Beispiel ein übergeordneter Ordner AGP Programme mit dem Unterordner application angelegt. In diesen Ordner wird das heruntergeladene, gezippte Beispielprogramm geladen und entpackt. Außerdem wird in den Ordner AGP Programme das gezippte Include-Verzeichnis p5_includes.zip geladen und entpackt. Dabei wird automatisch der Ordner p5_includes angelegt. Dieser enthält dann die p5-Library, alle verwendeten Include-Files und das Styling-File.
Im gezeigten Beispiel in ist das gezippte File pGrund_0023_Schraeger_Wurf.zip in den Ordner AGP Programme geladen worden. Nach dem Entpacken siehst Du den Ordner pGrund_0023_Schraeger_Wurf, der die Files pGrund_0023_Schraeger_Wurf.js und Pindex.html enthält.
Ein Doppelclick auf das File Pindex.html öffnet in der Regel das Beispielprogramm im Standard-Browser. Das klappt aber nicht immer! Enthält nämlich das Beispielprogramm Images, die hinzugeladen werden müssen, streikt der Browser aus Sicherheitsgründen. Obwohl die Images im gezippten Beispielordner mitgeliefert worden sind. Einzig mögliche Lösung ist die Installation eines lokalen web-Servers, wie z.B. den Apache, der dann das Starten der Beispielprogramme in einem localhost gestattet.

Abb. Ablage von Includes und Libraries
Strukturierung meiner Programmbeispiele
Die meisten meiner Beispielprogramme sind nach dem gleichen Strickmuster gearbeitet. Sieh Dir noch einmal die , die den Grundaufbau der processing oder p5.js-Programmabläufe zeigt, an. Da siehst Du, dass der unter der draw()-Sequenz befindliche Code maßgeblich für das gesamte Programm ist. Also sollten wir uns die draw()-Sequenz etwas genauer anschauen. Hier befinden sich alle Voreinstellungen, alle Berechnungsschritte, alle User-Interaktionen und alle Darstellungen der Objekte.Bevor wir auf die draw()-Sequenz näher eingehen, will ich aber noch ein Wort zur setup()-Routine sagen. Dort wird nach der Festlegung des Darstellungsbereiches (size(xmax, ymax) bzw. canvas(xmax, ymax)) mit Hilfe der Funktion evaluateConstants(xpos, ypos) die Position des START-Buttons festgelegt. Die Werte für xpos und ypos bewegen sich in einem Rahmen von 0 bis 100, wobei der Wert 100 dem rechten (xmax) bzw. dem unteren Rand (ymax) entsprechen. Die wirkliche Position des Buttons ergibt sich durch Multiplikation der normierten Werte xGrid bzw. yGrid mit den angegebenen Positionswerten xpos und ypos. Die Werte xGrid und yGrid spannen ein 100 x 100 - Gitternetz auf, dessen Maschen wie im Kapitel 2. Darstellung bewegter Objekte beschrieben, unter Berücksichtigung der Display-Auflösung berechnet worden sind. Viele der nachfolgend benutzten Funktionen greifen auf dieses Gitter zurück.
Und nun zur draw()-Routine. Bei der Analyse meiner Programmbeispiele stellt sich heraus, dass ich drei Grundvarianten in Benutzung habe. Diese Varianten unterscheiden sich eigentlich nur in ihrem Start-/Reset-Verhalten und im Zeitpunkt der Freischaltung von Mitteln zur Nutzerinteraktion.

Abb. a)
Processing: START/RESET des Programmablaufs
Processing: START/RESET des Programmablaufs

Abb. b)
p5.js: START/RESET des Programmablaufs
p5.js: START/RESET des Programmablaufs

Abb. c)
Processing bzw. p5.js: automatischer Programmstart
Processing bzw. p5.js: automatischer Programmstart
-
Variante: Hier wird nach dem Start des Programms auf eine Nutzereingabe, die
die Berechnung der Bewegungsabläufe startet, gewartet. Der Nutzer löst die
Berechnungen mit der Betätigung des START-Buttons aus. Vor dem START
kann der Nutzer per Eingabe mit der Maus bestimmte Bewegungsparameter, wie z.B. die
Fallhöhe beim freien Fall oder die Startgeschwindigkeit des zu bewegenden Objektes
voreinstellen. Nach dem START ist das nicht immer möglich, weil eine
nachträgliche Veränderung der Startparameter ggf. zu falschen Resultaten führen
würde. Nach dem Start des Programms, wechselt der START-Button seine Bedeutung
und wird zum RESET-Button. Eine Betätigung des RESET-Buttons führt zu
einem erneuten Bedeutungswechsel dieses Buttons. Er wird wieder zum START-Button
und eine Wiederholung das Experiment mit den alten oder aber auch mit neuen
Startparametern wird möglich. Ist das Experiment regulär beendet, weil eine
Endbedingung erfüllt ist, wird die Bewegungsberechnung beendet. Diese wird in der
Routine finaltest() bzw. endProgram() ausgetestet. Bei Erfüllung der
Bedingung wird der Zeitquant dt = 0 gesetzt, was zu einem Einfrieren
der Bewegung führt. Mit dem START wird u.a. der Zeitquant dt = 1/frmRate
gesetzt, womit eine erneute Bewegung möglich wird.
Zwischen den beiden Lösungen a) und b) bestehen kleine Unterschiede, die auf die unterschiedlichen Behandlungen von Variablen in Klassen (Processing) bzw. Objekten (p5.js) zurück zu führen sind. - Variante: Das ist die Spielvariante. Mit dem Programmstart wird auch sofort die Berechnung von Bewegungen möglich. Ein "Ende" gibt es nicht, darum auch kein RESET. Die Steuerung des Spielablaufs wird ausschließlich durch Nutzereingaben bestimmt, sofern nicht das Programm selbst Abläufe bestimmt.
-
Variante mit dem Aufruf der Funktion startProgram()
der Startbutton aktiviert und die Berechnung der Bewegungsabläufe beginnt.
Diese endet, wenn entweder die Endbedingung
(Processing: finalTest() bzw. p5.js: endProgram()) erfüllt ist
oder der RESET-Button betätigt wurde.
- Variante dieser Aufruf nicht erfolgt, da die Bewegungsberechnung sofort mit dem Start des Programms beginnt. Nach enthält sie die Programmabläufe der 1. Variante nur rudimentär. Als Beispiel sein hier das Programm Flipper genannt. Das zwar die Abfrage der START-Variablen beinhaltet, aber keinen solchen Button hat. Hier wird mit dem START-Ablauf nur eine Parametrisierung des Spiels vorgenommen, die aber ebensogut in der setup()-Routine erledigt werden könnte. Auch eine Abbruchbedingung gibt es, nämlich das Einlochen der Kugel, sie beendet aber nicht das Spiel, sondern stellt den Ausgangszustand wieder her. Hat die Kugel nämlich das Startloch wieder erreicht, kann sie per handle wieder losgeschickt werden.
Aus grundsätzlichen Überlegungen gibt es eine weitere Gliederung der Aufgaben innerhalb der draw()-Funktion. Diese Gliederung ergibt sich u.a. aus der Tatsache, dass
-
Bewegungsabläufe sinnvoller Weise in einem Abschnitt
Bewegungsberechnung
in den realen Größen wie Meter m, Geschwindigkeit m/s oder
Beschleunigung m/s2 berechnet werden sollten. Diese werden
dann
-
in einem Darstellungsabschnitt
mittels einer Maßstab-Umrechnung und
anschließender Koordinatentransformation
maßstäblich und örtlich korrekt plaziert und dargestellt.
- es schließlich noch administrative Aufgaben zu erledigen gibt. Dazu gehören z.B. textliche Ausgaben (Überschriften, Zahlenangaben) aber auch die unterschiedlichsten Bedienelemente (Buttons oder Scrollbars). Diese Elemente haben ja mit der Spiel-Szenerie nichts zu tun. Daher unterliegen sie keiner maßstäblichen oder örtlichen Transformation.




Wenn Du selbst ein Programm entwickeln möchtest
Schaust Du auf die offizielle Seite von p5.js wirst Du Hinweise und Werkzeuge für eine eigene Programmentwicklung finden. Dennoch möchte ich Dir hier eine alternative Möglichkeit für eigene Programme vorstellen, die auf den Funktionen der Dienstprogramme Includes aufbaut. Allerdings sind die hier im download der Includes_min verfügbaren Programme soweit vereinfacht, dass sämtliche Elemente, die für die Touch-Funktionen erforderlich sind, weggelassen wurden. Auch werden nur die Includes zur Verfügung gestellt, die Bezug auf die Bedienelemente (Maus aktv) und Gestaltung (z.B. Darstellung von Zeitfunktionen) haben.
Folgende Includes werden bereit gestellt:
1. pBasics_min
2. pConstants_min
3. pControls_min (detailierte Erläuterungen findest Du in den Headern der Funktionen!)
4. pFramework_min (detailierte Erläuterungen findest Du in den Headern der Funktionen!)
1. pBasics_min
function | task |
kXi(), kYi() | Koordinatentransformation: kartesisch [m] zu intern [pixel], bzgl. Nullpunkt xi0, yi0 |
iXk(), iYk() | Koordinatentransformation: intern [pixel] zu kartesisch [m], bzgl. Nullpunkt xi0, yi0 |
mouseClicked(), mousePressed(), mouseReleased(), mouseDragged() |
Maus-events: Mauskoordinaten werden mit den Systemvariablen mouseX [pixel] bzw. mouseY [pixel] übergeben |
keyPressed(), keyReleased() |
Tastaturevents, Resultat wird in der Systemvariablen key übergeben |
keyPressed(), keyReleased() |
Tastatur-events |
saveStringToFile(), loadStringFromFile(), loadError |
File-Operationen |
2. pConstants_min
function | task |
setConstants() | Constanten für responsives Design: gridX, gridY [pixel]: 1% von canvasWidth bzw. canvasHeight normPixelX, normPixelY [pixel]: 0.1% von canvasWidth bzw. canvasHeight normPixel [pixel]: geometrisches Mittel aus normPixelX und normPixelY fontSize [pixel]: responsive Schriftgröße basierend auf der Größe von normPixel buttonWidth, buttonHeight [pixel]: Button-Maße basierend auf gridX bzw. gridY |
3. pControls_min (detailierte Erläuterungen findest Du in den Headern der Funktionen!)
object | task |
Circle() / Objekt | Maus sensitiver Kreis, kartesisches Koordinatensystem function: inCircle result: status, Postion [m] |
Ring() / Objekt | Maus sensitiver Kreisring, kartesisches Koordinatensystem function: inCircle result: status, Radius [m], Postion [m] |
Arrow() / Objekt | Maus sensitiver Vektorpfeil, kartesisches Koordinatensystem function: moveArrow result: status, Postion [m], Betrag [m], Winkel [rad] |
Handle() / Objekt | Maus sensitiver Griff (rotierend), kartesisches Koordinatensystem function: moveHandle result: status, Winkel [rad] |
ToggleButton() / Objekt | Button, Zustand toggelnd, Positionierung im internen Koordinatensystem function: drawButton result: Zustand |
PushButton() / Objekt | Button, triggernd oder andauernd, wenn mousePressed, Positionierung im internen Koordinatensystem function: drawButton result: Zustand |
ScrollBar() / Objekt | Schieberegler, Positionierung im internen Koordinatensystem function: yValue result: Wert |
Path() / Objekt | Bezier-Pfad, kartesisches Koordinatensystem function: createPath function: usePath result: Wertpaare [m] |
4. pFramework_min (detailierte Erläuterungen findest Du in den Headern der Funktionen!)
function / object | task |
prepareScreen() | Headline/Subline, Positionierung im internen Koordinatensystem |
displayLine() | Textausgabe, Positionierung im internen Koordinatensystem |
formatNumber() | Formatierung von Gleitkommazahlen result: String [Vorkomma, Nachkomma] |
displayArrow() | Darstellung von Vektoren, kartesisches Koordinatensystem |
Diagramm() / Objekt | Darstellung von Zeitfunktionen, internes Koordinatensystem function: prepareWindow function: drawXScale function: drawYScale function: drawTimeLine |
Xaxis() / Objekt | Darstellung einer x-Achse, internes Koordinatensystem function: drawXaxis |
Yaxis() / Objekt | Darstellung einer y-Achse, internes Koordinatensystem function: drawYaxis |
Spring() / Objekt | Darstellung einer Feder, kartesisches Koordinatensystem function: drawSpring |
Zur Entwicklung eines javascript-Programms benötigst Du einen Browser wie z.B. Firefox oder
Chrome. Und einen geeigneten Editor wie z.B. Notepad++ oder
Eclipse. Auch p5.js macht hierzu passende Vorschläge.
Wenn Du das File pTemplate.zip geladen und entpackt hast, findest Du ein komplettes Archiv für eine eigenständige Entwicklung.

Abb. Sandbox: Ordnerhierarchie
Damit Du ein eigenes Programm entwickeln und vorführen kannst, ist zunächst der download des gezippten Files pTemplate.zip erforderlich. Dazu legst Du einen Ordner (in AGP sandbox genannt) an, in den das gezippte File pTemplate.zip lädst und dort entpackst. Damit wird eine Ordnerstruktur inclusive Inhalt gemäß erzeugt. Das Programm example.js ist ein Beispielprogramm, das die Nutzung der includierten Dienstprogramme demonstriert und von Dir auch als Grundstock für eigene Entwicklungen weiter verwendet werden kann. Doppelklick auf die index.html öffnet das Beispielprogramm im Standard-Browser.
Möchtest Du das Programm example.js umbenennen, dann vergiss nicht, diese Umbenennung auch in der index.html vorzunehmen!
Wenn Du das File pTemplate.zip geladen und entpackt hast, findest Du ein komplettes Archiv für eine eigenständige Entwicklung.

Abb. Sandbox: Ordnerhierarchie
Damit Du ein eigenes Programm entwickeln und vorführen kannst, ist zunächst der download des gezippten Files pTemplate.zip erforderlich. Dazu legst Du einen Ordner (in AGP sandbox genannt) an, in den das gezippte File pTemplate.zip lädst und dort entpackst. Damit wird eine Ordnerstruktur inclusive Inhalt gemäß erzeugt. Das Programm example.js ist ein Beispielprogramm, das die Nutzung der includierten Dienstprogramme demonstriert und von Dir auch als Grundstock für eigene Entwicklungen weiter verwendet werden kann. Doppelklick auf die index.html öffnet das Beispielprogramm im Standard-Browser.
Möchtest Du das Programm example.js umbenennen, dann vergiss nicht, diese Umbenennung auch in der index.html vorzunehmen!

p5: Template
example und includes_min
example und includes_min

Beispielanwendung starten
(RETURN nur über Browser-return möglich!)
(RETURN nur über Browser-return möglich!)
Arbeiten mit einer state machine
Spiele, insbesondere Computer-Spiele, sind durch eine Vielzahl unterschiedlicher Situationen gekennzeichnet. Dabei sind diese Situationen in ihrem Ablauf oder ihrer Aufeinanderfolge durch vorangegangene Situationen oder Zustände des Spiels bestimmt. Für die Programmierung eines Spiels bedeutet dies, dass die unterschiedlichen Zustände als Programmteil dargestellt sein müssen und, dass die Erkennung von Zustandsübergängen klar definiert sein muss. Dies führt auf die Idee der state-machine.Die state-machine muss im wesentlichen drei Aufgaben erfüllen:
- Ausführen der Bewegungsberechnung des aktuellen Status,
- Erkennen, wenn eine Wechsel des Status erfolgen muss. Benennen des nunmehr aktuellen Status,
- Übergabe der Parameter und Variablenwerte vom vorherigen an den folgenden Status, Herstellen der Ausgangssituation für den jetzt aktuellen Status.
Der Begriff der state-machine oder Zustandsmaschine ist in der Literatur weit verbreitet und wohl definiert. Meine Verwendung dieses Begriffs ist deutlich enger gefasst. Ich meine mit state-machine den vom Ablauf eines Spiels gesteuerten Wechsel von Spielsituationen. Im folgenden Beispiel des Minigolf-Spiels möchte ich das deutlich machen.
Im weitesten Sinn bedingen alle Handlungen bzw. die dazu erforderlichen Programmteile Zustände. Darum geht es mir aber nicht! Für den Spielablauf sind hier die Wechsel zwischen den Zuständen des Golf-Balls: Rollen auf der Ebene oder der Schräge, Fliegen im schrägen Wurf, Einlochen oder Bewegung bei Hindernissen wichtig. Das Erkennen der Wechsel in den Bewegungen des Golf-Balls und die Übergabe der physikalischen Parameter wie Ort, Geschwindigkeit oder Winkel ist für den kontinuierlichen Bewegungsverlauf des Balls von entscheidender Bedeutung! Die Situationen, die zu solchen Wechseln führen, zu erkennen und die erforderlichen Parameter bereit zu stellen, das ist meine state-machine!

Abb. Mini-Golf: Spielszenarium
Ganz kurz zur Spielidee (). Bei dem Minigolf-Spiel handelt es sich um eine vereinfachte Version des Golf-Spiels. Anders als in der Realität kann mein Golfer nur den Schläger (hier Putter genannt) bewegen, er selbst steht unverrückbar an der Abstoßstelle. Der Spieler fasst mit der Maus/linke Maustaste das untere Ende des Putters (hier durch einen grauen Kreis markiert) an und bewegt diesen im Bogen nach rechts. Dabei sind Heben oder Senken des Schlägers in einem engen Bereich möglich, um so den Flug des Golfballs steuern zu können. Mit dem Loslassen der Maustaste beginnt die Bewegung des Putters und in der Folge auch die des Golfballs. Ein Punkt wird gewonnen, wenn es dem Spieler gelingt, den Golfball "einzulochen". Zur Erschwerung des Einlochens
- weht ein unstetiger Wind, dessen Stärke und Richtung an dem Lochfähnchen zu ersehen ist,
- ist der Boden mit Rasen (grün) oder Sand (gelb) bedeckt,
- gibt es einen Wassergraben (blau), der den Lauf des Balles unterbricht.
- "on ground": der Ball bewegt sich auf dem Grund. Wie aus zu ersehen ist, besteht der Grund aus verschiedenen Segmenten, die - unabhängig von ihrer Neigung - alle wie schiefe Ebenen behandelt werden.
- "on flight": der Ball bewegt sich auf einer Wurfparabel.
- "start": hier wird der Putter bewegt. Diese Bewegung gleicht der eines Pendels, welches unter einer Federwirkung gespannt wird.
zeigt die Abhängigkeiten der Zustände von einander. Das Spiel beginnt mit dem Status "start". Hier bewegt der Spieler den Golfschläger aus seiner Ruhelage. Beim Loslassen der Maustaste pendelt der Schläger mit einer Winkelgeschwindigkeit ω, die der Auslenkung proportional ist, in Richtung Golfball. Stoßen Schläger und Golfball zusammen, erfolgt eine Wechselwirkung entsprechend der Stoß/Der freie elastische Stoß. Damit erfolgt der Übergang vom Status "start" zum Status "on flight" (1). Im Übergang (1) werden der Ort centerBall und die Ballgeschwindigkeit vxBall, vyBall übergeben.
Im Zustand "on flight" wirken die Gesetze des schrägen Wurfs unter den Einflüssen von Strömungsreibung und Wind. Während des Fluges wird laufend geprüft, ob und wo der Ball mit dem Grund (Rasen, Wasser, Loch, Sand) kollidiert. Ist dies der Fall, wird die Segment-Nummer des Landeorts, der Abstand s vom Beginn des betreffenden Segments vermerkt. Die Kollision mit dem Grund ist wieder ein Stoß-Ereignis, das eine zum Segment parallele vP bzw. normale Geschwindigkeitskomponente vN liefert. Ist die normale (senkrechte) Komponente groß genug, springt der Ball vom Segment ab (bouncing) und der Status "on flight" wird mit den Übergabewerten (2) erneuert. Das wiederholt sich solange, bis die Bedingung für das Bouncing nicht mehr erfüllt ist, dann erfolgt der Übergang (4) zum Status "on ground". Hier muss ggf. noch eine Korrektur des y-Wertes erfolgen, weil infolge der Zeitquantisierung eine Unterschreitung des Bodenniveaus erfolgt sein kann.
Ergibt die Kollision-Prüfung, dass der Ball aus dem Zustand "on flight" direkt einlocht oder in den Wassergraben fällt, dann erfolgt ein Übergang zu den Prozessen "hole" oder "water".

Abb. Mini-Golf: state-machine
Im Zustand "on ground" rollt der Ball auf den Segmenten, die allesamt schiefe Ebenen mit unterschiedlichen Neigungswinkeln "β" darstellen. Rollt der Ball von einem Segment zum nächsten oder auch vorherigen Segment, erfolgt eine permanente Parameterübergabe (6) innerhalb dieses Zustands. In diesem Zustand ist zu prüfen, ob der Ball in den Wassergraben oder das Loch rollt. Auch hier erfolgt ein Übergang zu den Prozessen "hole" oder "water", was zur Beendigung des aktuellen Spielversuchs führt.
Es kann aber auch geschehen, dass der Ball bei großen Geschwindigkeiten und entsprechenden Neigungswinkeln von der Segmentoberfläche abhebt. Dann geht der aktuelle Zustand in den Status "on flight" zurück, wobei wieder eine Parameterübergabe (5) erfolgen muss.
Ist die Ballgeschwindigkeit aber zu klein geworden, bleibt der Ball auf dem Spielfeld liegen. Nur ein "NEW" oder ein "RESET" ermöglicht, ebenso wie nach "hole" oder "water", eine Fortsetzung des Spiels
Dieses Beispiel enthält neben den oben gezeigten Verlinkungen weitere Vorgriffe auf viele der in den folgenden Kapiteln ausgeführten
physikalischen und mathematischen Teilaufgaben. Genannt seien
hier:
• Maßstäbe, responsives Design und Koordinatentransformation
• Kollision, Fehlerbehandlung sowie dezentraler Stoß und
• numerische Lösung von Differentialgleichungen
• Maßstäbe, responsives Design und Koordinatentransformation
• Kollision, Fehlerbehandlung sowie dezentraler Stoß und
• numerische Lösung von Differentialgleichungen

