Steuerung vom Snake-Spiel ist fehlerhaft.

AlanHorman

Mitglied
Ich arbeite an einem Snake-Spiel mit JavaScript bzw. Three.js.
Die Snake als Objekt habe ich erzeugt.

Code:
                this.distance = distance;
                this.direction = direction;

Hier sind zwei globale Variablen innerhalb der Snake, die den Abstand zum nächsten Feld (Distance) und die Richtung der Snake angeben.

Code:
this.move = function ()
                {
                    for (var i = this.cube.length - 1; i > 0; i--)
                    {
                        this.cube[i].position.x = this.cube[i - 1].position.x;
                        this.cube[i].position.y = this.cube[i - 1].position.y;
                        this.cube[i].position.z = this.cube[i - 1].position.z;
                    }

                    if (this.direction == "right")
                    {
                        this.cube[0].position.x += this.distance;
                    }
                    else if (this.direction == "left")
                    {
                        this.cube[0].position.x -= this.distance;
                    }
                    else if (this.direction == "up")
                    {
                        this.cube[0].position.z -= this.distance;
                    }
                    else if (this.direction == "down")
                    {
                        this.cube[0].position.z += this.distance;
                    }
};
Hier ist die Move-Funktion, mit der die Snake bewegt werden soll.

Code:
document.body.addEventListener("keydown", function (event)
{
 switch (event.keyCode)
                {
                    case 38:
                    case 87:
                        if (snake.direction != "down")
                            snake.direction = "up";
                        break;
                    case 40:
                    case 88:
                        if (snake.direction != "up")
                            snake.direction = "down";
                        break;
                    case 37:
                    case 65:
                        if (snake.direction != "right")
                            snake.direction = "left";
                        break;
                    case 39:
                    case 68:
                        if (snake.direction != "left")
                            snake.direction = "right";
                        break;
...

Mit diesem Keylistener kann man zwar die Schlange bewegen, doch sobald ich richtig wild auf der Tastatur rumtippe (z.B. links, tippe schnell die Oben-Taste und gleich wieder die linke Taste), dann kollidiert die Schlange trotzdem mit sich selbst. Wie umgehe ich dieses Problem, dass sich meine Schlange trotz wilder Rumtipperei nicht mit sich selbst kollidiert?
 
Hi

Kannst du etwas genauer beschreiben, wie du dich bewegst, damit eine Kollision zustandekommt?
(weil mit links/oben/links kann ich mir irgendwie nicht vorstellen, wie das geht)

Und interessanter als der gezeigte Codeteil ist wohl die Stelle, wo du auf Kollisionen prüfst.
 
Zuletzt bearbeitet:
Anders gesagt:

Wenn ich die Schlange steuer, dann bewegt sie sich so wie sie es sollte.

Bewegt sie sich nach links und ich drücke die Taste Rechts, dann bewegt sie sich trotzdem weiter nach links.

Würde sie sich nach links bewegen, und ich würde gleichzeitig in dieser Reihenfolge die Tastenkombination Links, Hoch und Rechts drücken,
dann kollidiert sie mich sich selbst, obwohl sie sich nach links bewegt hat und in dieser Stellung sich niemals nach rechts bewegen darf.

Ist meine Erläuterung verständlich oder noch zu undeutlich?

Code:
...
    this.loose = function ()
                {
                    gameOver();
                    for (var j = 0; j < this.cube.length; j++)
                    {
                        this.cube[j].material.color.setStyle('#a01f12');
                        this.cube[j].material.specular.setStyle('#c92a1a');
                        this.cube[j].material.emissive.setStyle('#64150d');
                    }
                };
                this.collision = function ()
                {
                    for (var i = 1; i < this.cube.length; i++)
                    {
                        if (this.cube[0].position.x == this.cube[i].position.x && this.cube[0].position.z == this.cube[i].position.z)
                        {
                            //alert("Game Over"); //DummyVersion

                            this.loose();
                        }
                    }

                };
...
 
Links, Hoch und Rechts
So ist alles klar :)
(Oben hattest du nämlich links/hoch/links geschrieben)

Einfache Lösung:
Statt einer Richtungsvariable machst du zwei, ich nenn sie mal Sollrichtung und Istrichtung:

Die Tastendrucke verändern nur die Sollrichtung (muss auch keine Prüfung haben, ob es wohl
nicht die entgegengesetzte Richtung ist). Die Anpassung der cube[0]-Koordinaten
in der regelmäßigen Movefunktion verwendet die Istrichtung.

Und direkt vor der Anpassung machst du ein Istrichtung=Sollrichtung,
aber nur wenn es nicht die genau engegegesetzte Richtung ist
(das ist der zentrale Punkt: die Prüfung hier, nicht bei der Eingabe)
 
Tut mir leid, jetzt habe ich ein Verständnisproblem:

Wie soll ich die Soll- und Istrichtung einsetzen?

Ich habe im Snake-Objekt ein weiteres Attribut angegeben (movingDir) und habe ihr den gleichen Wert wie die Direction zugewiesen.
Funktioniert immer noch nicht.

Code:
                this.move = function ()
                {
                    for (var i = this.cube.length - 1; i > 0; i--)
                    {
                        this.cube[i].position.x = this.cube[i - 1].position.x;
                        this.cube[i].position.y = this.cube[i - 1].position.y;
                        this.cube[i].position.z = this.cube[i - 1].position.z;
                    }

                    if (this.movingDir == "right")
                    {
                        this.cube[0].position.x += this.distance;
                    }
                    else if (this.movingDir == "left")
                    {
                        this.cube[0].position.x -= this.distance;
                    }
                    else if (this.movingDir == "up")
                    {
                        this.cube[0].position.z -= this.distance;
                    }
                    else if (this.movingDir == "down")
                    {
                        this.cube[0].position.z += this.distance;
                    }
                };

...    

       document.body.addEventListener("keydown", function (event)
            {
                switch (event.keyCode)
                {
                    case 38:
                    case 87:
                            snake.movingDir = "up";
                            break;
                    case 40:
                    case 88:
                            snake.movingDir = "down";
                            break;
                    case 37:
                    case 65:
                            snake.movingDir = "left";
                            break;
                    case 39:
                    case 68:
                            snake.movingDir = "right";
                            break;
                    case 71:
                        // G
                        THREEx.FullScreen.request();
                        break;
                    case 72:
                        // H
                        if (camera.rotation.z <= 0.785 && camera.position.y == 50)
                        {
                            camera.rotation.z -= -0.01;
                        }
                        else if (camera.position.y == 25)
                        {
                            camera.rotation.y -= -0.01;
                        }
                        break;
                    case 75:
                        // K
                        // Um Y-Achse gegen den Uhrzeigersinn drehen
                        if (camera.rotation.z >= -0.785 && camera.position.y == 50)
                        {
                            camera.rotation.z -= +0.01;
                        }
                        else if (camera.position.y == 25)
                        {
                            camera.rotation.y -= +0.01;
                        }
                        break;
                    case 77:
                        // M
                        // Um X-Achse runter rotieren
                        break;
                    case 85:
                        // U   
                        //Um X-Achse hoch rotieren!
                        break;
                    case 86:
                        // V
                        changeCameraTrans(0, 50, 0);
                        changeCameraRot(-1.57, 0, 0);
                        break;
                    case 66:
                        // B

                        changeCameraRot(-0.9, 0, 0);
                        changeCameraTrans(0, 25, 25);
                        break;
                    default:
                }
               
                snake.direction = snake.movingDir;
            });
 
Zuletzt bearbeitet:
Also, du willst jetzt ein direction als Soll und movingDir als Ist.

1)
Dieser Code verwendet weiterhin direction,
aber sollte keine Prüfungen mehr machen:
Code:
document.body.addEventListener("keydown", function (event)
{
switch (event.keyCode)
{
	case 38:
	case 87:
		if (snake.direction != "down")
			snake.direction = "up";
		break;
	case 40:
	case 88:
		if (snake.direction != "up")
			snake.direction = "down";
		break;
	case 37:
	case 65:
		if (snake.direction != "right")
			snake.direction = "left";
		break;
	case 39:
	case 68:
		if (snake.direction != "left")
			snake.direction = "right";
		break;
Also ca. sowas:
Code:
document.body.addEventListener("keydown", function (event)
{
switch (event.keyCode)
{
	case 38:
	case 87:
		snake.direction = "up";
		break;
	case 40:
	case 88:
		snake.direction = "down";
		break;
	case 37:
	case 65:
		snake.direction = "left";
		break;
	case 39:
	case 68:
		snake.direction = "right";
		break;

2)
Diesen Code stellst du auf movingDir um:
Code:
if (this.direction == "right")
{
	this.cube[0].position.x += this.distance;
}
else if (this.direction == "left")
{
	this.cube[0].position.x -= this.distance;
}
else if (this.direction == "up")
{
	this.cube[0].position.z -= this.distance;
}
else if (this.direction == "down")
{
	this.cube[0].position.z += this.distance;
}
wird zu
Code:
if (this.movingDir == "right")
{
	this.cube[0].position.x += this.distance;
}
else if (this.movingDir == "left")
{
	this.cube[0].position.x -= this.distance;
}
else if (this.movingDir == "up")
{
	this.cube[0].position.z -= this.distance;
}
else if (this.movingDir == "down")
{
	this.cube[0].position.z += this.distance;
}

3)
Direkt vor dem Code von 2) kopierst du direction
zu movingDir, aber hier dann geprüft:
Code:
if ((this.direction == "down" && this.movingDir != "up")
	|| (this.direction == "up" && this.movingDir != "down")
	|| (this.direction == "left" && this.movingDir != "right")
	|| (this.direction == "right" && this.movingDir != "left"))
	this.movingDir = this.direction;

4)
Nicht vergessen, auch der movingDir ganz am Anfang
einen Wert geben (den selben wie direction)

---

Das Problem vorher war im Wesentlichen ja, dass die Prüfung,
ob die neu eingegebene Richtung gültig ist, die neue Eingabe
mit der vorigen Eingabe verglichen hat, statt mit der Schlange.
Jetzt wird mit der Richtung vergleichen, mit der die Schlange
als letztes eine Bewegung ausgeführt hat.

PS zum Code: Wenn die Richtungen stattt zB. "up" einfach Nummer
(0,1,2,3) wären, wären die ganzen Bedingungen deutlich einfacher
realisierbar. Aber so ists beim Lesen des Codes dafür viel besser
verständlich.
 
Zuletzt bearbeitet:
Die neue Steuerung funktioniert und die Schlange ist sogar geschmeidiger. Aber wenn ich trotzdem sehr schnell die Tasten links und oben drücke und gedrückt halte und dann auf rechts gehe, dann gibt es trotzdem eine Selbstkollision.

Kann man das Tastatur verhalten nicht prüfen, dass keine anderen Tasten gedrückt gehalten werden?

Nachtrag: Den document.body.addEventListener("keydown", function (event){});
habe ich in document.body.addEventListener("keypress", function (event){}); umgewandelt, um den Tastenzustand besser zu checken.

Das was ich vorhin angesprochen habe passiert, wenn man zwei Tasten in unterschiedliche Himmelsrichtungen gleichzeitig drückt.

Schlange geht nach links, ich drücke gleichzeitig die runter und rechts Tasten und schon gibt es eine Kollision.
 
Zuletzt bearbeitet:
Merk grad, dass es mir vorher die Formatierung zerhaut hat
Hast du den Schritt 3 wohl nicht überlesen, am Ende der Codebox?
 
Zurück