image image


Das Coding Train Unicorn Rainbow Game hat fertig

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.

image

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:


(Kommentieren) 

image image



Ü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!


Werbung


image  image  image
image  image  image


image