2D Skeleton

2D Skeleton

Was sind Skeletons?

In der Spieleprogrammierung sind Sekeletons Bestandteil einer Animationstechnik, die sowohl im 3D als auch im 2D Raum Anwendung findet. Hier beschäftigen wir uns allerdings nur mit 2D Skeletons. Trotzdem bleibt es im Grunde die selbe Logik.

Wenn man eine "normale" Animation erstellt, nimmt man gewöhnlicherweise eine Bilddatei mit mehreren Frames, welche man dann mit Zeitverzögerung abwechselnd anzeigt. Das ist eine sehr traditionelle Art und Weise Dinge zu animieren und ist bis heute die gängigste Form.

Allerdings ist das ganze, soll toll es auch ist, sehr statisch. Man hat wenig Einfluss auf die Animation bzw. kann kaum einzelne Frames zur Laufzeit verändern. Man stelle sich außerdem mal vor, man hätte hundert verschiedene Schwerter in seinem Spiel und müsste für jedes die selben Animationen realisieren. Ein schrecklicher Aufwand.

Recycling

Eine Animation die man im Gegensatz mit Skeletons realisiert, kann immer und immer wieder verwendet werden. Somit müsste man beispielsweise die Schwertschwung Animation nur einmal erstellen und könnte sie dann für jedes Schwert verwenden. Nützlich, oder?

Bones, Joints, ...

Der Begriff "Skeleton" kommt, wie man sich vielleicht denken kann, aus dem englischen und bedeutet: Skelett. Genau so sollte man sich auch, beim realisieren von Animationen mit Skeletons, die Bewegungen vorstellen.

Ein Skeleton Arm, welcher einen Schwertschwung ausführt.

Die Animation oben besteht aus drei Sprites: Oberarm, Unterarm und Hand. Diese Sprites werden per Code "zusammengehalten". Und genau damit fängt die Entwicklung eines Skeletons an, nämlich mit der Positionierung.

Empfehlenswert wäre es hierbei erst mal die Ursprungspunkte der Sprites zu setzen, quasi den Punkt um den die Sprites sich später auch drehen sollen.

Der Ursprung liegt bei (5,5) relativ zum Oberarm.

Um beispielsweise den Unterarm nun mit dem Oberarm zu verbinden, müssen wir einfach die Position des Oberarms nehmen und einen Punkt, an dem wir beide verbinden wollen.

Jetzt muss nur noch die Position, am besten in jedem Frame, gesetzt werden. So wird dann der Unterarm bei jeder Bewegung des Oberarms neu positioniert und es sieht so aus, als wenn beide Sprites eins wären.

Soweit so einfach

Bewegungen haben wir jetzt abgedeckt. Die Sprites sind verbunden und bleiben es auch. Nur wenn man jetzt versucht den Oberarm zu rotieren, verhält sich der Unterarm nicht so wie man es sich erhofft. Warum?

So soll es nicht aussehen.

Durch die Rotation dreht sich nur die Grafik, die Position allerdings bleibt die selbe. Somit bleibt der Unterarm unberührt an seiner Position. Wie positionieren wir nun den Unterarm richtig?

Wir müssen eine Rotationsmatrix anwenden. Ohne jetzt zu sehr ins mathematische überzugehen, so sieht die 2D Rotationsmatrix aus:

Bitte nicht erschrecken. So kompliziert ist es nicht!

Ohne genauer ins Detail zu gehen und die Fragen "Wieso? Weshalb? Warum?" zu klären, erkläre ich hier nur (ähnlich wie im Mathe Unterricht in der Schule) wie man das ganze benutzt. x' und y' sind die Koordinaten die wir suchen und brauchen um unseren Unterarm nach der Rotation richtig zu positionieren. Um diese zu erhalten müssen wir die 2x2 x 2x1 Matrix erst mal "ausrechnen". Das funktioniert wie folgt:

(2x2)x(2x1) Matrix berechnen.

Vielleicht auch interessant
Bazooka - in Mausrichtung schießen
Bazooka - in Mausrichtung schießen

Wie man Spielelemente in Mausrichtung ausrichtet und bewegt.

Wo ist der Code???

Vielleicht sieht das alles auf den ersten Blick komplizierter aus als es ist. Deshalb kommen wir jetzt zur Praxis. In Code sieht das ganze vielleicht verständlicher aus.

float nx = cos(a) * x - sin(a) * y;
float ny = sin(a) * x + cos(a) * y;

Jetzt müssen wir die unbekannten Variablen x, y und a definieren. Hier gilt folgendes: Die meisten Kosinus und Sinus Funktionen arbeiten mit RAD (0-1) und nicht DEG (0°-360°)! Deshalb müssen wir den Winkel umrechnen.

float pi = 3.14159265359f;
float a = arm.getRotation() * pi / 180.f;

Die Positionen werden relativ zum Oberarm angegeben! Das bedeutet, wenn der Oberarm die Position (100, 100) in der Spielwelt hat und der Verbindungspunkt den wir uns wünschen bei der Koordinate (126, 105) liegt, ist der relative Punkt zum Oberarm: (26, 5).

float x = 26;
float y = 5;

Jetzt nehmen wir die ausgerechnete Position des Verbindungspunkt (nach der Rotation) und addieren diese zur aktuellen Arm Position. Code sagt mehr als tausend Worte:

float pi = 3.14159265359f;
float a = arm.getRotation() * pi / 180.f;

float x = 26;
float y = 5;

x -= arm.getOrigin().x;
y -= arm.getOrigin().y;

float nx = cos(a) * x - sin(a) * y;
float ny = sin(a) * x + cos(a) * y;
			
unterarm.setPosition(arm.getPosition().x + nx, arm.getPosition().y + ny);

Tadaaa!

Das ganze kann man jetzt auch für die Hand machen und schon hätte man einen verbundenen Skeleton Arm aus drei Sprites. Natürlich kann man sich jetzt auch das Leben einfacher machen und mit dem neuen Wissen eine Skeleton Animationsklasse realisieren. Die meisten Frameworks bieten übrigens Funktionen fürs berechnen von Matrizen, so müsste man nicht händisch die Rotationsmatrix berechnen. Aber es schadet nie zu wissen, wie es grob funktioniert!

Hinterlasse gerne einen Like oder Kommentar (~‾▿‾)~
Name Text