In diesem Schnelltipp zeige ich Ihnen, wie Sie das verwenden Sinus
Mit dieser Funktion können Sie die Objekte Ihres Spiels sanft vor und zurück bewegen - keine harten Zickzackbewegungen mehr, bei denen Ihre schwebenden Feinde gegen eine unsichtbare Wand zu springen scheinen!
Lassen Sie mich zunächst die Art der sanften Hin- und Herbewegung zeigen, die ich meine. (Die Grafiken stammen aus unserem völlig kostenlosen Shooter-Sprite-Paket.)
Dieser Feind bewegt sich auf und ab und schießt in regelmäßigen Abständen Kugeln ab:
Dieser Feind spinnt über den Bildschirm:
Beide Bewegungsarten sind praktisch für Shoot'em-Up-Spiele. Beachten Sie, wie glatt und allmählich sich die Bewegung anfühlt - keine plötzlichen Bewegungen, kein "Ruck", wenn der Feind seine Richtung ändert. Das steht im krassen Gegensatz zu…
Ein häufiger erster Versuch, eine Hin- und Herbewegung zu erzeugen, besteht darin, Folgendes zu tun:
var goingUp = falsch; // Funktion läuft alle paar Millisekunden. // Siehe: http://gamedev.tutsplus.com/articles/glossary/quick-tip-what-is-the-game-loop/ function gameLoop () if (ufo.y> = bottomOfRange) goingUp = true ; else if (ufo.y <= topOfRange) goingUp = false; if (goingUp) ufo.y -= ufo.ySpeed; else ufo.y += ufo.ySpeed; ufo.x += ufo.xSpeed;
Im Grunde bedeutet dies, dass sich der Feind mit einer konstanten Geschwindigkeit (dh mit der gleichen Anzahl von Pixeln) nach unten bewegt, bis er den niedrigsten Punkt in seinem zulässigen Bereich erreicht, und sich dann mit derselben konstanten Geschwindigkeit nach oben bewegt, bis er den höchsten Punkt in erreicht seine erlaubte Reichweite immer und immer wieder.
Der Feind kann durch Setzen seiner Einstellung dazu gebracht werden, sich horizontal zu bewegen xSpeed
auf eine andere Zahl als Null: Eine negative Zahl bewegt sich nach links und eine positive Zahl bewegt sich nach rechts.
Diese Beispiele zeigen, wie diese Art von Bewegung aussieht. Erstens ohne horizontale Bewegung:
Nun mit horizontaler Bewegung:
Es erreicht das Ziel des Hin- und Herbewegens, aber es ist sicherlich nicht so glatt wie bei unserem vorherigen Beispiel.
Der Grund für diese holprige Bewegung ist, dass die vertikale Geschwindigkeit des Feindes eine plötzliche große Änderung vornimmt - auch wenn der Wert von ufo.ySpeed
bleibt gleich.
Annehmen ufo.ySpeed
ist 10
. Auf dem Weg nach oben bewegt sich der Feind mit 10 Pixeln / Tick (Pixel pro Tick, wobei "Tick" die Länge einer Spielschleife ist) aufwärts. Sobald der Feind den Gipfel erreicht hat, kehrt er die Richtung um und bewegt sich plötzlich mit 10 Px / Tick abwärts. Die Verschiebung von + 10px / Tick auf -10px / Tick ist ein Unterschied von 20px / Tick, und das ist das, was so auffällt.
Wenn die Ursache so beschrieben wird, scheint die Lösung naheliegend: Verlangsamen Sie den Gegner in der Nähe der höchsten und niedrigsten Punkte! Auf diese Weise ist die Geschwindigkeitsänderung nicht so groß, wenn die Richtung umgekehrt wird.
Ein erster Versuch könnte so aussehen:
var goingUp = falsch; var movingSlowly = falsch; // Funktion läuft alle paar Millisekunden. // Siehe: http://gamedev.tutsplus.com/articles/glossary/quick-tip-what-is-the-game-loop/ function gameLoop () if (ufo.y> = bottomOfRange) goingUp = true ; else if (ufo.y <= topOfRange) goingUp = false; if (ufo.y <= bottomOfRange + 100) movingSlowly = true; else if (ufo.y >= topOfRange - 100) movingSlowly = true; else movingSlowly = falsch; if (movingSlowly) if (gehend) ufo.y - = ufo.ySpeed / 2; else ufo.y + = ufo.ySpeed / 2; else if (goingUp) ufo.y - = ufo.ySpeed; else ufo.y + = ufo.ySpeed; ufo.x + = ufo.xSpeed;
Dieser Code ist unordentlich, aber Sie haben die Idee: Wenn sich der Feind innerhalb von 100 Pixeln der höchsten oder niedrigsten Grenzen befindet, bewegt er sich mit der Hälfte seiner normalen Geschwindigkeit.
Das funktioniert, obwohl es nicht perfekt ist. Der Feind hat immer noch einen "Sprung" in der Geschwindigkeit, wenn er die Richtung ändert, aber es wird zumindest nicht so auffallen. Der Gegner hat jedoch jetzt zusätzliche Geschwindigkeitssprünge, wenn er sich vom normalen Tempo auf das langsamere Tempo bewegt! Dang.
Wir könnte Beheben Sie dies, indem Sie den Bereich in kleinere Abschnitte aufteilen oder die Geschwindigkeit um ein Vielfaches der exakten Entfernung vom Feind bis zu seinen Grenzen erhöhen. Es gibt jedoch einen einfacheren Weg.
Stellen Sie sich einen Modellzug vor, der auf einer perfekt kreisförmigen Strecke verläuft. Der Zug ändert ständig seine Richtung und dennoch bewegt er sich in einem gleichmäßigen Tempo ohne "Sprünge".
Stellen Sie sich jetzt eine Wand auf einer Seite der Kreisbahn und ein großes helles Licht auf der gegenüberliegenden Seite vor (also sind die Strecke und der Zug zwischen den beiden). Der Zug wirft einen Schatten auf die Wand. Aber natürlich bewegt sich dieser Schatten nicht im Kreis, weil die Wand flach ist: Sie wird geradlinig vor- und zurückbewegt, jedoch mit der gleichmäßigen sprungfreien Bewegung des Zuges!
Genau das wollen wir. Und zum Glück gibt es eine Funktion, die es uns gibt: die Sinus Funktion. Dieses animierte GIF von Wikipedia zeigt:
Die rote Linie ist die Kurve von y = sin (x)
. So, sin (0,5 * pi)
ist 1, sin (pi)
ist 0 und so weiter.
Es ist etwas unpraktisch, dass pi (π) die Basiseinheit für diese Funktion ist, aber wir können es schaffen. Wir können es wie folgt verwenden:
var numberOfTicks = 0; function gameLoop () numberOfTicks ++; ufo.y = sin (numberOfTicks * pi); ufo.x + = ufo.xSpeed;
Sehen Sie, was hier passiert. Nach einem Tick, ufo.y
wird auf gesetzt Sünde (1 * pi)
, welches ist 0
. Nach zwei Zecken, ufo.y
wird auf gesetzt sin (2 * pi)
, welches ist… 0
, nochmal. Oh. Abwarten.
var numberOfTicks = 0; function gameLoop () numberOfTicks ++; ufo.y = sin (numberOfTicks * 0,5 * pi); ufo.x + = ufo.xSpeed;
Jetzt nach einem Tick, ufo.y
wird auf gesetzt sin (0,5 * pi)
, welches ist 1
. Nach zwei Zecken, ufo.y
wird auf gesetzt Sünde (1 * pi)
, welches ist 0
. Nach drei Zecken, ufo.y
wird auf gesetzt sin (1,5 * pi)
, welches ist -1
, und so weiter. (Die Sinusfunktion wiederholt sich so sin (a) == sin (a + (2 * pi))
, immer - Sie müssen sich nicht darum kümmern ein
ist unter einer bestimmten Anzahl!)
Offensichtlich geht es ab 1
zu 0
zu -1
und so weiter wollen wir nicht. Zuerst wollen wir, dass die Grenzwerte etwas anderes sind 1
und -1
. Das ist einfach - wir multiplizieren das Ganze einfach Sünde
Funktion durch unsere gewünschte maximale Grenze:
var numberOfTicks = 0; function gameLoop () numberOfTicks ++; ufo.y = 250 * sin (numberOfTicks * 0,5 * pi); ufo.x + = ufo.xSpeed;
Nun geht der Feind weg y = +250
zu y = -250
. Wenn wir wollen, dass es geht 100
zu 600
, Wir können nur noch ein Extra hinzufügen 350
auf diesen Wert (seit 250 + 350 = 600
und -250 + 350 = 100
):
var numberOfTicks = 0; function gameLoop () numberOfTicks ++; ufo.y = (250 * sin (numberOfTicks * 0,5 * pi)) + 350; ufo.x + = ufo.xSpeed;
Aber der Wert springt immer noch ab 100
zu 350
zu 600
, weil der sin (numberOfTicks * 0,5 * pi)
springt immer noch aus -1
zu 0
zu 1
.
Aber wissen wir warum das ist passiert: es ist weil der Wert von numberOfTicks * 0,5 * pi
springt aus 0,5 * pi
zu 1 * pi
zu 1,5 * pi
. Schauen Sie sich die GIF noch einmal an, wenn Sie nicht wissen, warum dies dazu führen würde:
Wir müssen also nur eine andere Lücke zwischen der Anzahl wählen, die wir in die eingeben Sünde()
Funktion statt numberOfTicks * 0,5 * pi
. Wenn Sie möchten, dass die Hin- und Herbewegung zehnmal so lange dauert, verwenden Sie numberOfTicks * 0,5 * pi / 10
. Wenn Sie möchten, dass es 25 Mal so lange dauert, verwenden Sie numberOfTicks * 0,5 * pi / 25
, und so weiter.
Sie können diese Regel verwenden, um die Bewegung genau so lange dauern zu lassen, wie Sie möchten. Wenn Ihre Spielschleife alle 25 Millisekunden einmal (40 Mal pro Sekunde) ausgeführt wird, können Sie dies verwenden numberOfTicks * 0,5 * pi / 40
den Feind genau einmal pro Sekunde vom Zentrum zur Spitze zu bewegen, oder numberOfTicks * 0,5 * pi / (40 * 2)
um es von oben nach oben zu bewegen Unterseite genau einmal pro Sekunde.
Natürlich können Sie das alles einfach vergessen und mit verschiedenen Zahlen experimentieren, um zu sehen, was sich richtig anfühlt. Diese Demo verwendet sin (numberOfTicks / 50)
, und ich mag das Ergebnis:
Experimentieren und Spaß haben!