image image


image

Tutorial: Basic Side Scroller mit Processing.py (1)

Hier hatte ich geschrieben, daß ich gerne einmal einen Side-Scroller mit Bewegungsparallaxe programmieren möchte. Ursprünglich hatte ich dafür Pygame Zero vorgesehen, aber nachdem ich schon ein erstes Tutorial mit Algorithmen für Spieleprogrammierer (Tile Based Movement) in Processing.py geschrieben hatte, dachte ich, daß solch ein Side-Scroller auch in die Kategorie »Algorithmen für Spieleprogrammierer« gehöre und habe ihn daher ebenfalls in Processing.py implementiert.

In diesem ersten Teil geht es nur darum, die Bewegungsparallaxe vorzustellen. Ich möchte Euch zeigen, wie diese funktioniert. Dazu habe ich drei Ebenen erschaffen, erstens die Ebene mit den Wolken, dann eine Hintergrundebene mit großen Hügeln und eine letzte Ebene mit kleinen, dunkelgrünen Hügelchen. Der Einfachheit halber habe ich diese Hügel als (Halb-) Kreise implementiert. Sie leiten sich alle von einer Klasse ab:

class Hill(object):
    
    def __init__(self, x, r, s, c):
        self.xpos = x
        self.radius = r
        self.step = s
        self.col = c
    
    def update(self):
        self.xpos += self.step
        if self.xpos <= -self.radius:
            self.xpos = width + self.radius
    
    def show(self):
        fill(self.col)
        circle(self.xpos, 400, 2*self.radius)

Auch die Wolken (eigentlich gibt es nur eine, die immer wieder über den Hintergrund geschoben wird) setzt sich aus Kreisen zusammen:

class Cloud(object):
    
    def __init__(self, x, s):
        self.xpos = x
        self.step = s
    
    def update(self):
        self.xpos += self.step
        if self.xpos <= -200:
            self.xpos = width + 200
    
    def show(self):
        fill("#ffffff")
        circle(self.xpos, 150, 100)
        circle(self.xpos, 200, 100)
        circle(self.xpos - 50, 200, 100)
        circle(self.xpos + 50, 200, 100)

Der Clou ist hierbei, daß die Wolke nur eine Koordinate (xpos) für den Hauptkreis benötigt, die anderen Koordinaten werden davon abgeleitet.

Der Eindruck einer Bewegungsparallaxe entsteht dadurch, daß sich die Ebenen mit unterschiedlichen, gestaffelten Geschwindigkeiten von rechts nach links über den Bildschirm bewegen. Der Hintergrund schiebt sich langsam mit einem Pixel per Frame durch das Bild, die großen, hellgrünen Hügel bewegen sich mit zwei Pixeln pro Frame und die kleinen Hügel vorne rasen mit sagenhaften drei Pixeln per Frame vorbei:

Ganz vorne ist dann noch die Ebene, auf der sich der Spieler bewegt. Diese habe ich einfach durch ein passendes, hellbraunes Rechteck in voller Fensterbreite dargestellt, das sich – genau wie der Spieler – nicht bewegt:

    for cloud in clouds:
        cloud.update()
        cloud.show()
    # Große Hügel im Hintergrund
    for hill in bighills:
        hill.update()
        hill.show()
    # Kleine Hügel im Vordergrund         
    for hill in smallhills:
        hill.update()
        hill.show()
    # Erdboden    
    fill("#ffd05e")
    rect(0, 400, width, 50)
    # Sprites (erst einmal nur das rosa Alien)
    for sprite in sprites:
        sprite.update()
        sprite.show()

Der Spieler klebt tatsächlich an einer festen Position. Der Eindruck der Bewegung entsteht nur durch die vorbeigleitenden Hintergründe.

image

Der Screenshot kann natürlich nur einen Hauch des Eindrucks der Tiefe vermitteln, den die Animationen tatsächlich dem Zuschauer vorgaukelt.

Zur Unterstützung dieses Bewegungseindrucks lasse ich den Spieler – ein kleines rosa Alien aus der freien Sprite-Sammlung von Kenney.nl, daß ich hier auch schon mal verwendet hatte – ein wenig zappeln (ich tausche zwei Bildchen in regelmäßigen Abständen aus):

    def show(self):
        if self.status == "walking":
            self.count += 1
            if self.count > 15:
                self.count = 0
            if self.count < 8:
                image(self.im1, self.x, self.y)
            else:
                image(self.im2, self.x, self.y)

Den kompletten Code habe ich – wie man dem Headerbild entnehmen kann – auf drei Reiter aufgeteilt. Der erste enthält das Hauptprogramm:

# Side Scroller 1
from backgrounds import Hill, Cloud
from sprites import Alien

FPS = 60

clouds = []
bighills = []
smallhills = []
sprites = []

def setup():
    size(800, 450)
    this.surface.setTitle("Side Scroller 1")
    clouds.append(Cloud(400, -1))
    for i in range(3):
        bighills.append(Hill(i*400, 200, -2, "#63e06b"))
    for i in range(6):
        smallhills.append(Hill(i*200, 100, -3, "#217424"))
    sprites.append(Alien(66, 320))
    frameRate(FPS)
    noStroke()

def draw():
    background(64, 176, 226)
    # Wolke(n) im Hintergrund
    for cloud in clouds:
        cloud.update()
        cloud.show()
    # Große Hügel im Hintergrund
    for hill in bighills:
        hill.update()
        hill.show()
    # Kleine Hügel im Vordergrund         
    for hill in smallhills:
        hill.update()
        hill.show()
    # Erdboden    
    fill("#ffd05e")
    rect(0, 400, width, 50)
    # Sprites (erst einmal nur das rosa Alien)
    for sprite in sprites:
        sprite.update()
        sprite.show()

Der zweite Reiter backgrounds.py exportiert die Klassen Hill() und Cloud, wobei ich die Klasse Hill(), wie oben schon kurz erwähnt, so allgemein gehalten habe, daß sie sowohl als Blaupause für die großen wie auch für die kleinen Hügel herhalten kann:

# coding=utf-8

class Hill(object):
    
    def __init__(self, x, r, s, c):
        self.xpos = x
        self.radius = r
        self.step = s
        self.col = c
    
    def update(self):
        self.xpos += self.step
        if self.xpos <= -self.radius:
            self.xpos = width + self.radius
    
    def show(self):
        fill(self.col)
        circle(self.xpos, 400, 2*self.radius)

class Cloud(object):
    
    def __init__(self, x, s):
        self.xpos = x
        self.step = s
    
    def update(self):
        self.xpos += self.step
        if self.xpos <= -200:
            self.xpos = width + 200
    
    def show(self):
        fill("#ffffff")
        circle(self.xpos, 150, 100)
        circle(self.xpos, 200, 100)
        circle(self.xpos - 50, 200, 100)
        circle(self.xpos + 50, 200, 100)

Mit diesen beiden Reitern läßt sich die Simualtion der Bewegungsparallaxe schon sehr schön zeigen. Der letzte Reiter ist noch sehr unvollständig und hübscht mit dem rosa Alien die Szene nur ein wenig auf:

# coding=utf-8

class Sprite(object):
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def update(self):
        pass
    
    def show(self):
        pass

class Alien(Sprite):
    
    def __init__(self, x, y):
        Sprite.__init__(self, x, y)
        self.status = "walking"
        self.im1 = loadImage("alienwalk1.png")
        self.im2 = loadImage("alienwalk2.png")
        self.count = 0
        
    def show(self):
        if self.status == "walking":
            self.count += 1
            if self.count > 15:
                self.count = 0
            if self.count < 8:
                image(self.im1, self.x, self.y)
            else:
                image(self.im2, self.x, self.y)

Später sollen hier noch die Gegner des Spielers wie auch Hindernisse und andere Objekte hinzukommen, die dann alle von der (momentan noch sehr rudimentären) Klasse Sprite() abgeleitet werden.

Und damit Ihr den Sketch nicht nur nachvollziehen, sondern auch nachprogrammieren könnt, hier die beiden Bildchen des Alien:

image image

In einem nächsten Beitrag werde ich dieses Alien auch noch hüpfen lassen, damit es Hindernissen und Gegnern ausweichen kann. Und vielleicht wird es auch noch einen dritten Teil geben, in dem ich die Hügel und Wolken mit weiteren Bildern aus dem unerschöpflichen Fundes von Kenney.nl aufhübsche. Still digging!


(Kommentieren) 

image image



Über …

Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter, 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


Werbung


image  image  image
image  image  image


image