Meteoritenalarm

repl.it?

Wie fuktioniert der Editor?

  1. www.repl.it öffnen und einen Account erstellen
  2. Neuen Repl erstellen und Python als Sprache auswählen
  3. Einen sinnvollen Namen für das Projekt auswählen

Worauf sollte beim Kurs geachtet werden?

  1. Je nachdem wie viel Erfahrung die Teilnehmenden mitbringen, sollten die Teams möglichst einheitliche bzw. homogen eingeteilt werden
  2. Die Codebeispiele sind nicht dafür da um sie zu 100% vorzuführen. Es sollte darauf geachtet werden, das die Teilnehmer versuchen mit einigen Tipps des Inspirers die Lösung selber zu finden
  3. Für jeden Teil des Kurses sollte von den Teilnehmern ein „How to“ angelegt werden. Hier soll die Kernfunktionalität des Themas festgehalten werden um zur Not nochmal nachlesen zu können. (Die „How tos“ sollten den Codebeispielen ähnlich sehen und Kommentiert sein)
  4. Für viele Teilnehmer ist dieser Kurs das erste mal, dass mit einer „richtigen“ Programmiersprache gearbeitet wird. Legt also Wert auf die saubere Arbeit. Lesbarkeit des Programms sowie Kommentare und sauberer Code sind ein wichtiger Bestandteil des Kurses auch wenn es hierzu keine eigenen Lektionen gibt.

Spielfeld erstellen

  • Wie legen wir die Breite und Höhe unserer Leinwand fest?
  • Wie funktioniert ein Koordinatensystem?
  • Wie geben wir der Leinwand eine Farbe?
  • Was ist ein String?
1
2
3
4
5
function setup() {
// Unsere "Zeichenfläche" (Canvas = Leinwand)
createCanvas(450, 300)
// Wir malen auf schwarzem Hintergrund. Der Weltraum ist nachher auch schwarz :)
background("grey")}

Formen zeichnen 1

Jetzt wo wir unsere Leinwand erstellt haben, wollen wir auch etwas darauf machen. Wir fangen damit an, ein rotes und ein blaues Viereck zu zeichnen.

  • Was ist ein Parameter?
  • Wie positionieren wir ein Objekt auf unserer Leinwand (x, y)?
  • Was ist eine Funktion und wie programmieren wir sie?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function draw() {
        // So werden Formen ohne Rand gezeichnet
        noStroke()

        // Ein rotes Rechteck (rectangle)
        // rect(x, y, w, [h])
        fill("red")
        rect(0,0,100,50)

        // ohne Höhe wird das Rechteck zum Quadrat [h]ist optional
        fill("blue")
        rect(110,0,50)
}

Formen zeichnen 2

Vierecke können wir jetzt. Also machen wir uns dran auch einen Kreis zeichnen zu können. Zusätzlich gucken wir uns an, wie wir unsere Farbauswahl auf das nächste Level bringen können.

  • Wie funktioniert die Positionierung eines Kreises
  • Wie legen wir die Größe des Kreises fest?
  • Was ist RGB und wie können wir es nutzen?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16

// Ein gelber Kreis
// circle(x, y, d)
// d - Durchmesser
fill("yellow")
circle(170,0,50)
//ups, hier ist x,y der Mittelpunkt
// Also 25 nach unten und 25 nach rechts (Koordinatesystem üben ;) )
circle(195,25,50)
//jetzt könnte man den oberen Kreis auch auskommentieren, oder man ändert die Koordinaten gleich im ersten Circle.

// Jetzt ein Rechteck in einer
// https://htmlcolorcodes.com/color-picker/
// Dort kann man mit copy&paste den RGB Wert kopieren
// Alternativ: "colorpicker" googeln
fill(32, 196, 194)
rect(230, 0, 100,50)

Aufgaben zu Teil 1

  • Zeichnet jetzt entlang der y-achse (also senkrecht) die gleichen Formen. Versucht auch immer 10 Pixel Abstand zu lassen.
  • Probiert jetzt frei auf der Fläche verschiedene Formen aus! Lasst Eurer Kreativität freien Lauf!
  • Versucht vorher mit Euren Partner mit dem "Markierungstool"(Wenn die Konferenzsoftware das hat? Oder wenn ihr zusammen vorm Laptop sitzt mit der Maus anzeigen) den Ort der Form zu zeichnen. Liegt Ihr richtig? (Ihr sollt ein Gefühl für die Koordinaten und die Größe bekommen)
  • Man kann schwarz als fill(0) oder fill (0,0,0) oder fill("black") schreiben. Wie kann man weiß auf diese drei Arten schreiben? In der nächsten Übung (5) wird ein weißes Quadrat gemalt. probiert es dort aus.
  • Malt genau in der Mitte ein Quadrat mit einer Seitenlänge von 100 in der Farbe Weiß
  • Malt genau in der Mitte einen Kreis mit dem Durchmesser 100 in der Farbe des Hintergrundes!

Anmerkung: zu 5. und 6. Fällt Euch was auf? Wie sehen die vier "Ecken" aus? (Wie ein Raumschiff ;) )

Raumschiff zeichnen

  • Aufbauend auf der Liste wird jetzt das Konzept der Tupelliste gezeigt. Dabei soll jedes Tupel eine Frage und die dazu passende Antwort enthalten
  • Aufgabe 5: Findet heraus wie man auf der Grundlage der Tupelliste auch einzelne Elemente aus der Tupelliste aufrufen kann.
1
2
3
4
5
6
7
8

// Ein oranges Dreieck
// triangle(x1, y1, x2, y2, x3, y3)
fill("orange")
triangle(0,50,25,0,50,50)

// Vielleicht ein bisschen spitzer, dann sieht es so aus wie ein wendiges Raumschiff
fill(192)
triangle(0,100,15,50,30,100)

Raumschiff und Ränder

Jetzt, wo wir unser Raumschiff gebaut haben, wollen wir ein bisschen mit Umrandungen bzw. strokes rumprobieren.

  • Wie legen wir die Dicke der Umrandung fest?
  • Wie legen wir die Farbe der Umrandung fest?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

// noStroke() sorgte dafür, dass keine "Ränder" um die Formen gezeichnet werden. Lässt man noStroke() weg, dann tut p5.js so, als wenn man stroke(0) oder stroke("black") angibt.
//Wollen wir uns mal rote Ränder angucken um das zu visualisieren.
stroke("red")
fill("blue")
rect(60,0,50)

// Oder mal die "Standardeinstellung" in schwarz und mal versetzt über dem vorherigen Quadrat, damit man das auch sieht.
stroke(0)
fill("DARKORCHID")
rect(100,20,50)

// Auch die Dicke des Randes hat einen Standard, der ist 1 und bedeutet 1 pixel aussen und 1 pixel innen
// Jetzt doppelt so dick machen
strokeWeight(2)
stroke("white")
fill(128,192,64)
rect(180,0,50)

Andere Formen

  • Wie zeichnet man Linien?
  • Wie positioniert man Linien auf der Leinwand?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

/* Durch den Rand werden die Formen größer. Es werden bei strokeWeight(1) ein Pixel Innen und einer Außen gezeichnet, also insgesamt ist der Rand 2 Pixel stark. */

// strokeWeight() ist auch die Linienstärke für Punkte und Linien.

// Ein gelber Punkt oben links beim blauen Quadrat
stroke("yellow")
//strokeWeight - Strichstärke
strokeWeight(1)
point(60,0)

//Punkte können auch zu Kreisen werden. Auch hier ist die Koordinate der Mittelpunkt
stroke("yellow")
strokeWeight(50)
point(325,25)

// Linien haben einen Anfangs- und Endpunkt
// line(x1, y1, x2, y2)
stroke("magenta")
strokeWeight(1)
line(0,150,450,150)
//oder Dicker (Wenn keine neue Farbe angegeben wirde, wird weiter mit Magenta gemacht)
strokeWeight(5)
line(0,160,450,160)

// Es gibt die Variablen height und width, die Euch p5.js anhand der Canvas-Größe gibt :)
stroke("cyan")
strokeWeight(1)
// minus Eins weil die Koordinaten ja bei 0 anfangen.
line(0,0, width-1, height-1)

// Und ein Punkt in der Mitte kann man dann mit width/2 und height/2 darstellen. (Anmerkung: height oder width ungerade sind, dann ist ja die Hälfte irgendwas.5 . Dann schneidet point() einfach die Nachkommastelle ab )
stroke("white")
strokeWeight(3)
point(width/2, height/2)

Aufgaben zu Teil 2

  • Zeichnet verschieden Formen, mit verschiedenfarbigen Rändern und unterschiedlicher Dicke auf dem gesamtenSpielfeld :)
  • Malt eine grüne Linie (egal welches grün) von rechts oben, nach links unten.
  • Malt eine rote Linie (egal welches rot) von der Mitte in die linke obere Ecke.
  • Malt eine Linie von rechts unten zur Mitte (sucht Euch eine Farbe aus)
  • Zeichnet das Raumschiff (graues Dreieck) in genau der gleichen Größe wie oben. Die Position soll mittig am unteren Rand sein. Dann zeichnet einen Kreis mit dem Mittelpunktauf der Mitte der kurzen unteren Seite des Raumschiffs in der Farbe schwarz (Hintergrundfarbe) Was passiert? Wie sieht das aus?

Anmerkungen: Für 2./3./4.: Versucht die Variablen width und height zu benutzen. (Ihr könnt aber erstmal anhand der CanvasGröße das 450x300 die Koordinaten ausrechnen und danach eine "Formel" entwickeln.)

Meteoriten

Nachdem wir uns jetzt mit den meisten Formen und Positionierungen gut auskennen, wollen wir lernen wie wir unsere Meteoriten programmieren.

  • Was macht die Funktion random?
  • Warum setzen wir width und height als Maximum?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

// mit let werden Variablen erzeugt
// (1) man kann auch erstmal für x_rand und y_rand konkrete Zahlen einsetzen.
// (2) mit random(von, bis) wird eine zufällige Zahl erzeugt. Die Zahl "von" kann dabei sein, die Zahl "bis" ist aber nie dabei.
// Info: Genaugenommen wird eine Zahl mit Nachkommastellen erzeugt. Die werden aber einfach abgeschnitten, wenn man sie als Farbwerte oder Koordinaten einsetzt :)
let x_rand = random(0,width)
let y_rand = random(0,height)

// (3) Auch zufällige Farben sind möglich
let r_rand = random(0,256)// 256 ist nicht dabei!
let g_rand = random(0,256)
let b_rand = random(0,256)
//let farbe_rand = color(r_rand, g_rand, b_rand)

Meteoriten 2

Was macht eine Liste und wie nutzen wir sie hier?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

// (4) wollt Ihr nur aus ein paar Farben auswählen, geht das auch so:
//Achtet auf die eckigen Klammern []
let farbname_rand = random(["gold", "silver"])
//let farbe_rand = color(farbname_rand)

// Mit stroke("white") wird ein Sternenhimmel erzeugt. (Leider können wir den nicht als Hintergrund nehmen, weil das zu nachher zu kompliziert wird)
// Hier 2 für den Sternenhimmel und 10 für die bunte Punktewolke
strokeWeight(2)
// (1)(2)
stroke("white")
//(3)(4)
//stroke(farbe_rand)

point(x_rand,y_rand)

Meteoriten Bewegung

Wir wollen nun versuchen unsere Meteoriten in Bewegung zu bringen.

  • Wie funktioniert die Punktnotation?
  • Wie können wir die Position eines Objekts verändern?
  • Wie funktioniert eine Schleife?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/*
Die Funktion draw() wird dauernd (mehrmals pro Sekunde) ausgeführt. So können wie später ein Spiel programmieren
*/
function draw() { // (1) immer wieder das Canvas "löschen" background("black") noStroke() fill(255) circle(meteor.X, meteor.Y, 20) // man kann auch + 2 oder + 3 machen um den meteor schneller zu machen. meteor.Y = meteor.Y + 1 //print(meteor.Y)
}

Meteoriten Bewegung 2

Hier wollen wir die Position unsere Meteoriten im Blickbehalten um ihn rechtzeitig verschwinden zu lassen. Dazu brauchen wir eine Abfrage.

  • Was ist eine If-Abfrage?
  • Wie lassen wir den Meteoriten wieder verschwinden?
  • Was ist ein Integer?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21

// (2) ups wo ist er hin?
//print(meteor)
//(3)(1) ohne +10
//(3)(2) Man sollte dann auch height +10 (also plus Durchmesser_vom_Meteor/2 vergleichen damit der Meteor unten auch verschwindet)
// false && ist einfacher als auskommentieren
if(meteor.Y > height + 10){ //(3)(1) un (3)(2) print(meteor.Y) //noLoop() // Wenn er also verschwunden ist, dann erscheint ein neuer Meteorit oben. Ja, ist eigentlich der alte, aber Pssst! 😆 meteor.Y = 0 //(3)(3) // Und jetzt kommt der Zufall ins Spiel: meteor.X = random(0,width) //print(meteor.X) //Damit wir das alles besser lesen können, schneiden wir selber die Nachkommastellen mit int() ab. (Wurde ja schon erwähnt) meteor.X = int(meteor.X) //print(meteor.X)
}

//noLoop()

Aufgaben zu Teil 4

  • Lasst den ersten Meteoriten auch an einer zufälligen Position erscheinen. Es gibt verschiedene Möglichkeiten, hauptsache es funktioniert!
  • Wie kann man Meteoriten diagonal fliegen lassen?

Mehr Meteoriten

Weil wir jetzt wissen, wie wir einen Meteoriten erstellen und sich bewegen lassen, können wir das Konzept auf mehr Meteoriten übertragen um unserem Ergebnis näher zu kommen

  • Wie erstellen wir eine Variable der wir direkt eine X und Y Wert vermitteln?
  • Wie fügen wir bestehende Variablen in ein Array ein?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

// Oben haben wir schon meteors definiert, das soll eine Auflistung aller Meteoriten sein
// Und einzelne Meteoriten sehen dann so aus
let meteor1 = {X: 10, Y:0}
let meteor2 = {X: 65, Y:0}
let meteor3 = {X: 180, Y:0}
let meteor4 = {X: 200, Y:0}
let meteor5 = {X: 400, Y:0}

// mit push() werden die dann in Auflistung aller Meteoriten (ein Array) angefügt.
meteors.push(meteor1)
meteors.push(meteor2)
meteors.push(meteor3)
meteors.push(meteor4)
meteors.push(meteor5)

// Tipp: meteor1, meteor2 sind nur Hilfsvariablen gewesen. Mann kann auch direkt auf das Array pushen:
// meteors.push({X: 10, Y:0}) usw.

  • Wie lassen wir uns einzelne Elemente aus einem Array ausgeben?
  • Wie können wir den Inhalt eines Arrays lesen und verstehen?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// So sieht die Datenstruktur dann aus (Achtung,
//print("Datenstruktur:\n",meteors)
// Zugegriffen wir dann mit eckigen Klammern und zwar wird hier von 0 an gezählt:
print("\nUnd die Meteoriten sehen wie im Code aus:")
print(meteors[0])
print(meteors[1])
print(meteors[2])
print(meteors[3])
print(meteors[4])
// Das klingt erstmal komliziert, ist aber gewöhnungssache. Arrays sind flexibler als wenn man meteor1, meteor2 usw. als Variablen hat

Mehr Meteoriten in Bewegung

Ähnlich wie bei der ursprünglichen Meteoritenbewegung, wollen wir jetzt auch die anderen Meteoriten gleichzeitig bewegen.

  • Was ist eine for Schleife und wofür können wir sie hier nutzen?
  • Wie nutzen wir eine for Schleife in Verbindung mit einem Array um alle Objekte in nur einer Schleife bewegen zu können?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function draw() {
        background("black")
        noStroke()
        fill(255)
        // meteors.length ist die Länge des Arrays
        // Mit dieser Schleife wird in der variablen i gezählt und zwar von 0 bis 2, also 0,1,2
        for (let i = 0; i < meteors.length; i  = i + 1){
                // Hier definieren wir mit current_meteor, den aktuellen Meteor in diesen Schleifendurchlauf
                let current_meteor = meteors[i]

                // Der Meteor wird gezeichnet
                circle(current_meteor.X, current_meteor.Y, 20)
                // Und lassen ihn nach unten wandern indem wir die y-koordinate um eins nach oben zählen.
                current_meteor.Y = current_meteor.Y + 1

                // Warum =10 und -10? Einfach mal "P" im richtigen Moment drücken :)
                if(current_meteor.Y > height + 10){//Warum +10

                        current_meteor.Y = - 10 //Warum -10?
                        current_meteor.X = random(0,width)
                        // int() schneidet die Nachkommastellen ab, die random() liefert.
                        current_meteor.X = int(current_meteor.X)
                }
        }
}

Aufgaben zu Teil 5

  • "Versetzte Meteoriten": Wie kann man die Meteoriten auch horizontal versetzen, damit sie nacheinander unten ankommen?
  • "Farbige Meteoriten": Weist den Meteoriten eine zufällige Farbe zu.

Tipp: Das ist mit Fleißarbeit verbunden, den Anfangsmeteoriten Farben zu geben. Hier muss man keine zufälligen mit random() wählen, sondern kann wie die Anfangskoordinaten auch selbst was "zufälliges" auswählen.

Ihr könnt neue "Untervariablen" in meteors einfügen. Entweder R,G und B oder einfach nur color, wo ihr mit color() die Farbe schon in eine p5-Farbe in einer Variablen speichert.

Erst in der if-Bedingung kommt neben der neuen x-Koordinate die Zufallsfarbe hinzu.

Raumschiff Bewegung 1

Jetzt müssen wir noch unser Raumschiff einfügen..

  • Was ist die Framerate?
  • Wo wird unser Raumschiff erstellt, wenn wir es an x:width/2 einfügen?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

let ship = {}

// Die Funktion setup() wird einmalig am Anfang des Programms ausgeführt
function setup() { createCanvas(450, 300) // Wir machen die Bewegungen erstmal langsam // framerate bedeutet "Wiederholungen pro Sekunde" // (0) Hier erstmal 30 oder so einsetzen frameRate(60) background("black") //erst hier ist width definiert // Und so kann ship initialisiert werden ship = { X: width/2 }
}

Raumschiff Bewegung 2

Nachdem unser Raumschiff erstellt wurde wollen wir es noch in Bewegung bringen.

  • Was macht die Funktion keyIsDown(key)
  • Wie können wir das Raumschiff mit Tasten bewegen?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

function draw() { background("black") noStroke() // *** Schiffscode ANFANG *** fill(255) // Keycodes kann man hier ausprobieren: // https://keycode.info/ // '<-' pressed if (keyIsDown(37)) { if (ship.X > 0) { // wenn man hier 2 anstatt 1 wird"s schneller ship.X = ship.X - 1 } } // '->' pressed if (keyIsDown(39)) { if (ship.X < width + 1) { // auch hier natürlich 2 anstatt 1 ändern ship.X = ship.X + 1 } } drawShip() // *** Schiffscode ENDE***
}

function drawShip(){ // Die 295 kommt daher, dass 5 pixel Luft unter dem Raumschiff natürlicher wirken. (Bei 299 wäre es ja direkt unten am Rand kleben!) triangle(ship.X-8, 294, ship.X, 269, ship.X+8, 294) // Kannst Du die Geometrie des Raumschiffs erklären? Tipp: ship.X ist die x-Koordinate dees Raumschiffs, gemeint ist hier die Spitze.
}