Diese Methode zur Bewegung eines Objektes nennt sich in der Spieleprogrammierung auch velocity (z.Dt. Geschwindigkeit). Dabei geht es um die permanente Abfrage ob eine Geschwindigkeit in eine der 2 oder 3 möglichen Dimensionen stattfindet, also eine entsprechende Bewegung erzeugt werden soll.
In Javascript müsste man zusätzlich eine Funktion erstellen, welche diese Bewegung am DOM-Element erzeugt und sich selbstverständlich auch auf mehrere Objekte anwenden lässt ohne den Garbage Collector zu füllen. Letzteres ist in Javascript oft gar nicht so einfach wie es sein sollte.
Vernünftige Bewegung, Kollision, Animation ist ohne ein solides Basiswissen übrigens keinen Versuch wert, meiner Meinung nach sollte man in der Schule eventuell einfachere Dinge praktizieren. Ich entnahm aus deinem Code einfach mal das du nicht außerordentlich viel Durchblick besitzt. Das meine ich keineswegs negativ, der Code ist nur äußerst laienhaft, verstärkt durch grausame Einrückung (welche ich schon beseitigt habe).
Ich habe mich trotzdem mal an die Arbeit gemacht und ein kleines Beispiel dazu erstellt. Die erste Hürde ist die Möglichkeit zur Anwendung auf mehrere Objekte. Hierzu sind Klassen nötig, also wird simpel eine Klasse erstellt. Zur einfachen Instanziierung erstellt sich diese am Besten über eine Funktion. Möchte man nun ein Element übergeben sähe das wie folgt aus:
function player(element)
{
this.element = element;
}
var player1 = new player(document.getElementById("player1"));
Für Bewegung und insbesondere für Collider sind einige Größen des Elementes Voraussetzung zu wissen. Richtige Collider gibt es in diesem Beispiel nicht, sie werden lediglich in der später erläuterten Update-Funktion simuliert. In Javascript ist es leider nicht sinnvoll und oft auch einfach unmöglich verschiedene Aufgaben auf unterschiedliche Klassen aufzuteilen, wie man es eigentlich gewohnt ist. Darum befindet sich auch fast alles in einer Klasse.
Die benötigten Größen sind die Abmessungen, die ursprüngliche Position im Koordinatensystem (hier in Pixeln), die Geschwindigkeit (velocity) und die Verschiebung zu den Seiten, wobei die letzteren beiden Werte initial auf 0 gesetzt werden. Jeder Wert wird äquivalent für jede Dimension angegeben. In dieser Szene gibt es nur 2 Dimensionen und zwar x und y.
Zusätzlich zu den Informationen über das zu bewegende Element braucht es noch Informationen über das Elternelement. In der Spieleprogrammierung spricht man beim Container z.B. eines Levels oder Abschnitts von Szenen, die Szene ist hier die einzige Ausnahme welche in einer seperaten Klasse angelegt wird, eine Referenz wird in die player-Klasse implementiert.
function scene(element)
{
this.element = element;
this.dimension =
{
x: this.element.offsetWidth,
y: this.element.offsetHeight
}
}
function player(element, scene)
{
this.element = element;
this.dimension =
{
x: this.element.offsetWidth,
y: this.element.offsetHeight
}
this.position =
{
x: this.element.offsetLeft,
y: this.element.offsetTop
}
this.translate =
{
x: 0,
y: 0
}
this.velocity =
{
x: 0,
y: 0
}
}
var scene1 = new scene(document.getElementById("scene1"));
var player1 = new player(document.getElementById("player1"), scene1);
Alles anzeigen
Jetzt lassen sich bereits mehrere DOM-Objekte als Szenen oder player definieren. Die Bezeichnung player ist leicht irreführend, da es sich eigentlich um simple Objekte handelt, da im Beispiel aber nur der Spieler vorkommt und ein Aufteilen in Player und Object Klassen wie bereits genannt nicht unbedingt praktikabel ist, beschränke ich mich hier mal auf die eigentlich nicht ganz korrekte Bezeichnung.
var scene1 = new scene(document.getElementById("scene1"));
var player1 = new player(document.getElementById("player1"), scene1);
var player2 = new player(document.getElementById("player2"), scene1);
Es fehlt die Animation an sich. Nun wäre dies wieder eine neue Klasse, klappt nicht gut, also in die player Klasse implementieren. Man käme nun theoretisch als erstes auf die Idee dafür die Interval oder Timeout-Funktion des window Objektes zu nutzen, das ist jedoch eine blöde Idee, da die Animation dann nicht mit der Bildwiederholungsrate des Anzeigegerätes synchronisiert wurde. Besser zu nutzen ist die requestAnimationFrame Methode.
Da sich die Animation in der player Klasse befindet und Referenzen dadurch recht schwierig zu erstellen sind, erstelle ich vorher eine nicht objektorientierte Referenz und nutze diese dann simpel in der Update Methode.
Die Methode an sich überprüft die Position des Objektes,die angegebene Geschwindigkeit und bewegt es dann in die entsprechende Richtung. Wie das funktioniert ist keine Zauberei sondern reine Mathematik. Wenn das Objekt den Rand der Szene erreicht wird die Geschwindigkeit auf 0 gesetzt, andere Collider sind hier nicht notwendig da es laut Spielprinzip nicht zu Kollisionen von Objekten (außer dem Geschoss) kommen muss. Es wird keine Angabe für links oder rechts benötigt. Positive Werte erzeugen Bewegung nach rechts/unten und negative nach links/oben.
Bsp.:
Translate: 50px
Velocity-x: -5px
Translate neu: 50px + (-5px) = 45px.
Benutzt wird das CSS transform Attribut mit translate, so verändert sich die reine CSS Position des Objektes nicht. Nach Ablauf der Funktion findet eine Rekursion mittels requestAnimationFrame statt, so wird laufend geprüft ob velocity gesetzt ist oder nicht, dementsprechend wird animiert oder gestoppt, sowohl für die x-als auch für die y-Achse. Interessant ist hier wegen Spielprinzips beim Spieler nur die x-Achse.
function player(element, scene)
{
[...]
var handle = this;
function update()
{
handle.scene.dimension.x = handle.scene.element.offsetWidth;
handle.scene.dimension.y = handle.scene.element.offsetHeight;
if(handle.velocity.x > 0)
if (handle.translate.x + handle.velocity.x + handle.position.x + handle.dimension.x >= handle.scene.dimension.x) {
handle.velocity.x = 0;
handle.translate.x = handle.scene.dimension.x - handle.dimension.x - handle.position.x - 1;
}
else
{
handle.translate.x += handle.velocity.x;
}
else if(handle.velocity.x < 0)
if(handle.translate.x + handle. position.x + handle.velocity.x <= 0)
{
handle.velocity.x = 0;
handle.translate.x = -handle.position.x;
}
else
{
handle.translate.x += handle.velocity.x;
}
if (handle.velocity.y > 0)
if (handle.translate.y + handle.velocity.y + handle.position.y + handle.dimension.y >= handle.scene.dimension.y) {
handle.velocity.y = 0;
handle.translate.y = handle.scene.dimension.y - handle.dimension.y - handle.position.y;
}
else {
handle.translate.y += handle.velocity.y;
}
else if (handle.velocity.y < 0)
if (handle.translate.y + handle.position.y + handle.velocity.y <= 0) {
handle.velocity.y = 0;
handle.translate.y = -handle.position.y;
}
else {
handle.translate.y += handle.velocity.y;
}
handle.element.style.transform = "translate(" + +handle.translate.x + "px, " + handle.translate.y + "px)";
requestAnimationFrame(update);
}
requestAnimationFrame(update);
}
Alles anzeigen
User Input verarbeiten ist nun auch nicht mehr so schwer, einfach je nach Bedingung den Wert für velocity ändern. Dazu ist an der Stelle auch nicht viel zu erklären.
document.addEventListener("keypress", function (event) {
if (event.charCode == 119 || event.charCode == 97 || event.charCode == 115 || event.charCode == 100 ||
event.charCode == 87 || event.charCode == 65 || event.charCode == 83 || event.charCode == 68 ||
event.keyCode <= 40 && event.keyCode >= 37
)
event.preventDefault();
var lvl1 = 3;
var lvl2 = 9;
if (event.keyCode == 39 || event.charCode == 100 || event.charCode == 68)
if (player1.velocity.x < 0)
player1.velocity.x = 0;
else if (player1.velocity.x == 0)
player1.velocity.x = lvl1;
else
player1.velocity.x = lvl2;
if (event.keyCode == 37 || event.charCode == 97 || event.charCode == 65)
if (player1.velocity.x > 0)
player1.velocity.x = 0;
else if (player1.velocity.x == 0)
player1.velocity.x = -lvl1;
else
player1.velocity.x = -lvl2;
});
Alles anzeigen
Erstellt ohne jQuery oder andere Frameworks. Frameworks sind schön, helfen aber beim lernen <0.
Der ganze Kram kombiniert sieht dann irgendwie so aus: codepen.io velocity
Pfeiltasten links/rechts oder A/D benutzen um Bewegung nach links oder rechts zu erzeugen. Doppelt drücken erhöht die Geschwindigkeit, bei entgegengesetzter Richtung wird zunächst ein Stillstand erzeugt.
Solltest du hier jemals wieder rein gucken viel Spaß damit, bei Fragen kann ich auch gerne genauere Erläuterungen liefern.