Problem mit Spritebewegung
af2111
- css
- javascript
0 Rolf B
Hallo,
ich möchte für ein Spiel eine Figur Münzen einsammeln lassen. Die Figur lässt sich mit den Pfeiltasten steuern, und genau bei der Steuerung liegt das Problem. Ich kriege es einfach nicht hin, die Figur so zu bewegen, dass die dynamisch erstellte Position der Münzen noch gespeichert wird. Leider gibt mir auch die Console keine Fehlermeldung. Hier ist der Code:
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Sammle die Münzen</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="SpielMitMünzen.css" />
<script src="Jquery/jquery-3.3.1.js"></script>
</head>
<body>
<div class="playground">
<img class="sprite" src="Player.png">
</div>
</body>
</html>
JS:
let coins = [];
let sprite = $(".sprite");
let spritePosX = sprite.css("left");
let spritePosY = sprite.css("top");
let playground = $(".playground");
let i = 0;
while (i <= 20) {
let img = $("<img class=\"coinimg\" src=\"Coin.png\">");
coins.push[img];
img.attr("id", "coin" + i);
let min = 0;
let max = 300;
let positionCoinX = (Math.random() * (max - min) + min) + "px";
let MinY = 0;
let MaxY = 200;
let positionCoinY = (Math.random() * (MaxY - MinY) + MinY) + "px";
img.css({
left: positionCoinX,
top: positionCoinY
});
playground.prepend(img);
i++;
function coordinates() {
return [positionCoinX, positionCoinY, spritePosX, spritePosY];
}
}
let coords = coordinates();
console.log(coords);
$(document).keydown(function (event) {
switch (event.key) {
case "ArrowUp":
coords[3] -= 10;
sprite.animate({
top: coords[3]
}, 25);
if (coords[0] && coords[1] === coords[2] && coords[3]) {
alert("berührt");
}
break;
case "ArrowLeft":
coords[2] -= 10;
sprite.animate({
left: coords[2]
}, 25);
if (coords[0] && coords[1] === coords[2] && coords[3]) {
alert("berührt");
}
break;
case "ArrowRight":
coords[2] = parseInt(coords[2]);
coords[2] += 10;
coords[2] + "px";
sprite.animate({
left: coords[2]
}, 25);
if (coords[0] && coords[1] === coords[2] && coords[3]) {
alert("berührt");
}
break;
case "ArrowDown":
coords[3] = parseInt(coords[3]);
console.log(coords[3]);
coords[3] += 10;
sprite.animate({
top: coords[3]
}, 25);
if (coords[0] && coords[1] === coords[2] && coords[4]) {
alert("berührt");
}
break;
}
});
});
Hat jemand eine Idee, wie die Steuerung funktionieren köntte?
Hallo af2111,
da ist einiges im Argen.
Eine Münze dürfte ein Kreis sein, hat also einen Mittelpunkt und einen Radius $$r_M$$. Wenn dein Sprite ein Quadrat ist, kannst Du ihm einen Kreis einbeschreiben, der ebenfalls Mittelpunkt und Radius $$r_S$$ hat. Für einen Kollisionstest berechnest Du den Abstand der Mittelpunkte (siehe Pythagoras). Ist der kleiner als $$r_M+r_S$$, liegt eine Kollision vor bzw. das Sprite hat die Münze berührt. Wenn Sprite und Münze gleich groß sind, kannst Du Dir die Mittelpunktberechnung sogar schenken und einfach die Abstände von (spriteX,spriteY) und (coinX,coinY) - für alle Coins - berechnen.
Ist dein Sprite kein Quadrat, oder ist seine Form einem Kreis sehr unähnlich, musst Du entweder Ungenauigkeiten bei der Kollisionsberechnung hinnehmen oder Dir einen Algorithmus überlegen, wie Du eine Überlappung von Sprite und Münze berechnen kannst.
Rolf
Hi,
Eine Münze dürfte ein Kreis sein, hat also einen Mittelpunkt und einen Radius $$r_M$$. Wenn dein Sprite ein Quadrat ist, kannst Du ihm einen Kreis einbeschreiben, der ebenfalls Mittelpunkt und Radius $$r_S$$ hat. Für einen Kollisionstest berechnest Du den Abstand der Mittelpunkte (siehe Pythagoras). Ist der kleiner als $$r_M+r_S$$, liegt eine Kollision vor bzw. das Sprite hat die Münze berührt.
Die Ecke des Quadrats ist vom Mittelpunkt aber weiter entfernt als der Radius des einbeschriebenen Kreises. Die Ecke kollidiert mit dem Kreis deutlich früher - wenn der Kreismittelpunkt auf der Verlängerung der Diagonale des Quadrats liegt etwa 1,4 mal früher ( sqrt(2) ).
cu,
Andreas a/k/a MudGuard
Hallo Andreas,
die Reduktion des Sprites auf einen Kreis ist natürlich eine vereinfachende Approximation, die die Programmierung erleichtert und die Laufzeit reduziert.
Die Prüfung, ob ein Kreis ein Quadrat berührt, muss anders programmiert werden. Aus der Hüfte geschossen würde ich sagen, das geht so:
Sei $$(x_K,y_K)$$ der Mittelpunkt eines Kreises mit Radius r.
Sei Q ein Quadrat mit diagonal gegenüberliegenden Eckpunkten $$(x_1,y_1), (x_2, y_2)$$ und durch passende Sortierung sei $$x_1<=x_2$$ und $$y1<=y2$$. Dann muss man folgende Fälle unterscheiden:
$$x_K+r \lt x_1 \vee x_K-r \gt x_2$$ ⇒ Keine Kollision (Kreis weit genug links/rechts)
$$y_K+r \lt y_1 \vee y_K-r \gt y_2$$ ⇒ Keine Kollision (Kreis weit genug drüber/drunter)
$$x_K \le x_1 \land y_K \le y_1 \land ||(x_K,y_K),(x_1,y_1)|| > r$$ ⇒ Keine Kollision (Abstand zur linken obere Ecke)
$$x_K \ge x_2 \land y_K \le y_1 \land ||(x_K,y_K),(x_2,y_1)|| > r$$ ⇒ Keine Kollision (Abstand zur rechten obere Ecke)
$$x_K \le x_1 \land y_K \ge y_2 \land ||(x_K,y_K),(x_1,y_2)|| > r$$ ⇒ Keine Kollision (Abstand zur linken unteren Ecke)
$$x_K \ge x_2 \land y_K \ge y_2 \land ||(x_K,y_K),(x_2,y_2)|| > r$$ ⇒ Keine Kollision (Abstand zur rechten unteren Ecke)
SONST: Kollision.
Natürlich würde man für den Abstand nicht $$\sqrt{(x_K-x_1)^2+(y_K-y_1)^2} > r$$ testen, sondern $$(x_K-x_1)^2+(y_K-y_1)^2 > r^2$$, das geht schneller und man muss r² nur einmal berechnen.
Also: Viel mühsamer und langsamer als die Kollision zweier Kreise. Ob meine Approximation trägt, hängt von der Form des Sprites ab. Ob man einen Test Kreis vs Quadrat machen muss, ebenfalls. Effiziente Kollisionserkennung ohne Hardwareunterstützung ist eine Wissenschaft für sich.
Rolf
@@Rolf B
Natürlich würde man für den Abstand nicht $$\sqrt{(x_K-x_1)^2+(y_K-y_1)^2} > r$$ testen, sondern $$(x_K-x_1)^2+(y_K-y_1)^2 > r^2$$, das geht schneller und man muss r² nur einmal berechnen.
TIL (naja, vor ein paar Tagen): Math.hypot()
LLAP 🖖
Hallo Gunnar,
ich habe mal handgemachten Pythagoras (mit und ohne Wurzelziehen) und Math.hypot gegeneinander gestellt.
Math.hypot enthält einen Überlaufschutz. Der macht es extrem lahm.
https://jsfiddle.net/ymp8vdcj/1/ - Ergebnisse in der Console.
Rolf