Meine kleine Hommage an Daniel Shiffmans Coding Train in Form eines Computerspiels mit einem hüpfenden Einhorn, das einen Regenbogen hinter sich her zieht und den bösen »thisdot«-Lokomotiven ausweichen muß, ist fertig. Ich habe noch ein passendes Hintergrundbild eingefügt und einen nervigen Hintergrundsound (den disdot-Song) in einer Endlosschleife abspielen lassen. Kollidiert das Einhorn mit einem der Züge gibt es noch einen finalen Soundeffekt und das Spiel ist zu Ende.
Für diese finale Version waren keine Änderungen mehr an den Klassen CodingTrain
und UnicornRainbow
nötig. Lediglich im Hauptsketch habe ich noch einige Ergänzungen vorgenommen: Zum einen habe ich im setup()
mit
bg = loadImage("bg.jpg")
das Hintergrundbild geladen. Es ist das gleiche Bild, das Daniel Shiffman auch für seine 147. Coding Challenge »Chrome Dinosaur Game« verwendet hat und ich habe es seinem GitHub Repositorium entnommen und mit der Bildbearbeitung meines Vertrauens auf die Größe des Processing-Fensters (720x360 Pixel) verkleinert und zurechtgeschnitten. Das Coding Train Repositorium steht unter einer MIT-Lizenz, daher gehe ich davon aus, daß mir die Verwendung erlaubt ist.
Musik wird oft nicht schön gefunden,
weil sie stets mit Geräusch verbunden.
(Wilhelm Busch)
Nun zu den Geräuschen: Ich muß gestehen, ich gehöre zur »Generation Großraumbüro« und daher habe ich mich mit den Processing(.py)-Funktionen, mit denen man Lärm machen kann, bisher noch nicht befaßt, ich mußte es tatsächlich nachschlagen. Aber in diesem Falle dachte ich, daß es paßt, da die Nyan Cat als eine der Inspirationsquellen zu diesem Sketch ja ebenfalls mit einem nervenden Remix unterlegt ist und es Wettbewerbe gibt, wie lange man dies aushält. Als erstes habe ich daher mit
add_library('sound')
die notwendige Bibliothek geladen, die ich vorher noch in meine Umgebung importieren mußte. Dann habe ich den Quellcode zu dem This Dot Jumper auf den Seiten von swiftpotato heruntergeladen, weil das .zip-File auch die Soundfiles enthielt. Die habe ich in das data
-Verzeichnis meines Sketches kopiert und dann im setup()
mit
fail = SoundFile(this, "fail4.mp3") thisdot = SoundFile(this, "this.mp3") thisdot.loop()
die Dateien geladen und den Loop des »This Dot Songs« gestartet. In draw()
habe ich dann folgende Ergänzungen eingefügt:
for train in trains: if train.rect_collision(unicorn): thisdot.stop() fail.play() # print("Game Over") noLoop()
Wenn das Einhorn mit einem der Züge kollidiert, wird zuerst einmal der Song abgeschaltet und dann ein Soundeffekt abgespielt, bevor das Spiel endet.
Zu guter Letzt habe ich noch eine kleine Änderung vorgenommen. Die Punktanzeige oben rechts erfolgte in Lila, weil (129, 122, 198)
die letzte Farbe des Regenbogens war und danach im Quellcode kein weiteres fill()
mehr aufgerufen wurde. Um dies nicht als Seiteneffekt stehen zu lassen, der bei späteren Änderungen eventuell überschrieben wird, habe ich vor der Textausgabe explizit noch einmal mit
fill(129, 122, 198)
die Farbe gesetzt. Ist einfach sauberer so.
Wie gewohnt zum Schluß der vollständige Quellcode. Zuerst der Reiter unicornrainbow.py
:
class UnicornRainbow: def __init__(self): self.rainbow = [] self.side = 6 self.im = loadImage("unicorn.png") self.d = 90 # Durchmesser self.score = 0 self.x = 240 self.y = 100 self.offset_rainbow = self.x + 30 self.gravity = 0.6 self.lift = -12 self.velocity = 0 def add_rainbow_stripes(self): rectMode(CENTER) self.rainbow.append(([self.offset_rainbow, self.y + (self.side*7), self.side, self.side], color(240, 80, 37))) self.rainbow.append(([self.offset_rainbow, self.y + (self.side*8), self.side, self.side], color(248, 158, 80))) self.rainbow.append(([self.offset_rainbow, self.y + (self.side*9), self.side, self.side], color(248, 239, 34))) self.rainbow.append(([self.offset_rainbow, self.y + (self.side*10), self.side, self.side], color(49, 197, 244))) self.rainbow.append(([self.offset_rainbow, self.y + (self.side*11), self.side, self.side], color(240, 99, 164))) self.rainbow.append(([self.offset_rainbow, self.y + (self.side*12), self.side, self.side], color(129, 122, 198))) def delete_stripes(self): rainbow_copy = [stripe for stripe in self.rainbow if stripe[0][0] >= 0] self.rainbow = rainbow_copy # print(len(self.rainbow)) def up(self): self.velocity += self.lift def update(self): self.velocity += self.gravity self.velocity *= 0.9 self.y += self.velocity # check borders if self.y >= height - self.d: self.y = height - self.d self.velocity = 0 elif self.y <= 0: self.y = 0 self.velocity = 0 if self.rainbow: self.delete_stripes() for stripe in self.rainbow: stripe[0][0] -= 2 def show(self): for stripe in self.rainbow: col = stripe[1] fill(col) noStroke() rect(stripe[0][0], stripe[0][1], stripe[0][2], stripe[0][3]) image(self.im, self.x, self.y)
Dann die zweite Klasse, der Reiter codingtrain.py
:
class CodingTrain: def __init__(self, x): self.im = loadImage("train.png") self.d = 90 # Durchmesser self.pos = PVector(width + x, random(height - 100)) self.speed = 5 self.reset = False def update(self): self.pos.x -= self.speed if self.pos.x < -100: self.reset = True self.pos = PVector(width + 200, random(height - 100)) def show(self): image(self.im, self.pos.x, self.pos.y) self.reset = False def rect_collision(self, other): distanceX = (self.pos.x + self.d/2) - (other.x + other.d/2) distanceY = (self.pos.y + self.d/2) - (other.y + other.d/2) halfW = self.d/2 + other.d/2 halfH = self.d/2 + other.d/2 if (abs(distanceX) < halfW): if (abs(distanceY) < halfH): return True return False
Und schließlich der Hauptsketch, der einzige Reiter, an dem ich für die finale Version noch Änderungen vorgenommen habe:
# The Coding Train designs and characters by Jason Heglund: # https://jasonheglund.com/#/the-coding-train/ add_library('sound') from unicornrainbow import UnicornRainbow from codingtrain import CodingTrain trains = [] NO_TRAINS = 2 def setup(): global unicorn, trains, bg, fail, thisdot size(720, 360) this.surface.setTitle("Coding Train Unicorn Rainbow Final Stage") bg = loadImage("bg.jpg") # Font: https://fonts.google.com/specimen/Ranchers font = createFont("Ranchers-Regular.ttf", 30) textFont(font) unicorn = UnicornRainbow() for i in range(NO_TRAINS): train = CodingTrain((i * 400) + 200) trains.append(train) fail = SoundFile(this, "fail4.mp3") # This Dot Song by Kristian Pedersen: # https://soundcloud.com/kristianpedersen/this-dot-feat-daniel-shiffman # https://soundcloud.com/kristianpedersen thisdot = SoundFile(this, "this.mp3") thisdot.loop() def draw(): global unicorn, trains, bg, fail, thisdot background(bg) for train in trains: train.update() if train.reset: unicorn.score += 1 # print(unicorn.score) unicorn.add_rainbow_stripes() unicorn.update() for train in trains: train.show() unicorn.show() for train in trains: if train.rect_collision(unicorn): thisdot.stop() fail.play() # print("Game Over") noLoop() fill(129, 122, 198) textSize(30) text("Score: " + str(unicorn.score), 15, 40) def keyPressed(): if (key == " "): unicorn.up()
Wie in den Kommentaren des Quelltextes angemerkt, sind die beiden Bilder vom Einhorn und vom Coding Train von Jason Heglund und der This Dot Song ist ein Remix von Kristian Pederson.
Beim ersten Start des Spiels müßt Ihr eventuell ein paar Sekunden warten. Zumindest mein betagtes MacBook Pro braucht diese Zeit, um den Song zu laden.
Natürlich gibt es den Quellcode und sämtliche Assets auch in meinem GitHub-Repositorium.
Hier noch die ersten drei Beiträge, in denen ich die Entwicklung dieses Spiels beschrieben habe:
Über …
Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter Rentner, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!
Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.
Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.
Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes
von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.
Werbung
Diese Spalte wurde absichtlich leergelassen!