How-To 'Moorhuhn'-Klon in Godot Part 5

Animationen

Ein kleiner Schritt für das Schweinchen, ein großer Schritt in Richtung Animationskarriere

Nachdem wir im letzten Part dafür gesorgt haben, dass wir eine hübsche UI für unsere Punktzahl haben, wird es nun Zeit unser Moorschwein aufzubessern. Und da wir auch ein wenig Bewegung in die Sache bringen wollen, animieren wir unser Schweinchen ein wenig. Leider sind meine Zeichen- und Animationskünste nicht die besten, weswegen wir uns mit zwei Frames genügen müssen. Nichts desto trotz sollte es reichen um euch das Prinzip näher zu bringen. Als erstes solltet ihr im Github vorbeischauen und dort die beiden Bilder pig00.png und pig01.png herunterladen und in euer Projekt importieren. Legt diese im “assets” Ordner ab.
Als nächstes öffnen wir die Moorschweinszene und schauen uns unser Sprite genauer an. Da diese uns keine Animationsmöglichkeiten bietet, müssen wir sie ersetzen. Klickt mit der rechten Maustaste auf die Sprite und wählt Typ ändern. Sucht im folgenden Fenster nach “AnimatedSprite” und wählt diese aus. Im Inspektor sollte nun die Option Frames vorhanden sein. Wählt diese aus und wählt “Neues SpriteFrames”. Klickt dieses dann danach erneut an und es öffnet sich das Animationsdock.

In Bereich 1 werden alle verfügbaren Animationen angezeigt. Durch den Button links über den Bereich kann eine neue Animation hinzugefügt werden. Standardmäßig wird uns eine Animation mit dem Namen default angelegt, welche uns erst einmal genügt.
Im Bereich 2 werden die Bilder, die für die Animation verwendet werden, angezeigt. Um der Animation neue Bilder hinzuzufügen, können wir einfach Bilder aus dem Dateimanager in diesen Bereich ziehen. Genau das machen wir auch gleich, und zwar so: Zieht die Bilder pig00.png und pig01.png in den Bereich 2. Sobald ihr das getan habt, sollte das Schwein auch im 2D Bereich angezeigt werden.
Im Bereich 3 könnt ihr einstellen, in welcher Geschwindigkeit die Bilder weitergeschaltet werden sollen. Umso höher die Zahl, umso schneller wechseln die Anzeige zwischen den einzelnen Frames. Durch die Flag-Wiederholung wird bestimmt, ob die Animation von vorne beginnen soll, sobald der letzte Frame erreicht wurde. Belasst beide Einstellungen erstmal auf den vorgegebenen Werten.

Damit wir jetzt aber auch Bewegung sehen müssen wir im Inspektor die Eigenschaft “Playing” auf An setzen und schon bewegt sich unser kleines Schwein!

Durch die Eigenschaft “Flip H” können wir unser Bild horizontal spiegeln, was wir brauchen werden, wenn unser Schwein von rechts nach links fliegt.

Jetzt ergeben sich aber noch zwei Probleme:

  1. Unsere CollisionShape passt nicht mehr zu unserem Bild
  2. Wenn wir die Animation spiegeln wird die CollisionShape nicht mit gespiegelt. Da unser Schwein nicht mittig im Bild ist, überlappen sich CollsionShape und Animation nicht mehr.

Kümmern wir uns zuerst um Punkt 1. Wir wählen die CollsionShape aus und ändern die Shape zu CapsuleShape. Dann passen wir deren Radius und Height, sowie die Position der CollisionShape so an, dass sie mit dem Bild übereinstimmt. Entnehmt die Werte einfach dem folgenden Bild:

Jetzt zu Punkt 2. Hierzu müssen wir die Position der Collisionshape programmatisch anpassen, wenn sich die Richtung ändert. Öffnet das Moorschwein.gd und legt eine neue Variable unter m_start_position an und erweitert die ready Methode:

1
2
3
4
5
var m_dir : int = 1

func _ready() -> void:
m_start_position = position
$Area2D/CollisionShape2D.position.x *= m_dir

Dadurch spiegeln wir die x Position unserer Shape, wenn der Wert m_dir -1 ist. Jetzt fragt ihr euch wahrscheinlich, wie der Wert jemals -1 sein kann, wenn die Multiplikation bereits in der _ready Methode geschieht. Dazu muss man wissen, dass die _ready Methode erst aufgerufen wird, wenn eine Node einem Szenentree hinzugefügt wurde. Instanziiert man also eine Node programatisch, wir die ready Methode erst aufgerufen, wenn man die Instanz per add_child Befehl dem Baum hinzufügt.
Schreiben wir jetzt also eine Methode, die m_dir auf -1 setzt und unser Schwein spiegelt:

1
2
3
4
5
6
func flip_pig(flip_h : bool) -> void:
$Sprite.flip_h = flip_h
if flip_h:
m_dir = -1
else:
m_dir = 1

Diese müssen wir jetzt nur noch in unserem Level Skript aufrufen, falls das Schwein von rechts nach links fliegen soll:

1
2
3
4
5
6
7
8
9
10
func _build_pig(points : int, horizontal_speed : float, vertical_speed :float, amplitude : float, scale : Vector2) -> Area2D:
var pig = PIG.instance()
# ...
if dir == 2:
pig.HORIZONTAL_SPEED *= -1
pig.flip_pig(true)
x = get_viewport_rect().size.x
pig.position = Vector2(x, randi()%screen_size+25)
pig.connect("killed", self, "_on_pig_killed")
return pig

Damit sollte alles bereit sein und ihr könnt das Level austesten. Schaltet dabei ruhig im Menü “Debuggen” den Punkt “Collision Shapes sichtbar” an, um euch zu vergewissern, dass die CollisionShapes in jede Richtung richtig platziert sind.

Ein kleiner Fix unserer Timer

Vielleicht ist euch schon aufgefallen, dass unsere Schweine immer gleich spawnen, trotz Zufallszahlen. Das liegt daran, dass wir eine wichtige Funktion vergessen haben.

Öffnet das Levelskript und ändert die _ready Methode wie folgt um:

1
2
3
func _ready():
$CanvasLayer/UI.update_points(mPoints)
randomize()

Die Godot Doku schreibt dazu wie folgt:
“Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.”

Damit stellen wir sicher, dass bei jedem Start des Levels die Zahlen, die der Zufallsgenerator ausspuckt neu gemischt werden.

Das soll es dann auch für diesen Part erst einmal gewesen sein. Im nächsten Part kümmern wir uns um ein funktionierendes Hauptmenü.