Nun, dass @balexandre einige Punkte zu Ihrem Code schön erklärt hat, können wir untersuchen, wie wir die Kollision berechnen können.
Stellen 2 Bereiche einander überlappen (Bereich a teilweise überlappt Bereich b)
[100 .|.. 300]
[200 ..|. 400]
Der Teil von überlappenden ist | zu | -> 200 bis 300, so dass die Größe der Überlappung 100
Wenn Sie die Zahlen betrachten, beachten Sie, dass die Überlappung wie zu sehen war,
- Nehmen Sie die kleinere Zahl von der rechten Seite -> 300
- nehmen sie die greate Nummer der linken Seite -> 200
- sie voneinander subtrahieren -> 300 - 200 = 100.
Werfen wir einen Blick auf zwei anderen Situationen nehmen. (Bereich b vollständig im Bereich ein)
[50 ... 150]
[75...125]
So sind die Werte, die wir haben, sind: Math.min (150,125) //125
für den Endwert und Math.max (50,75) // 75
für den Startwert, was zu einem Wert von 125 bis 75 = 50 für die überlappen
nehmen wir ein das letzte Beispiel aussehen (Bereich ein nicht im Bereich b)
[50 ... 150]
[200 ... 300]
die obige Formel ergibt das Ergebnis Math.min (150 , 300) - Math.max (50,200) // -50
, die absolutes' Wert der Spalt zwischen den zwei Bereichen, dann 50
Jetzt können wir eine letzte Bedingung hinzufügen, wie Sie die Kollision berechnen wollen, nur Werte > 0
sind von Interesse für uns. Vor diesem Hintergrund können wir es in einen Zustand versetzt.
Math.min ((Brick["Right"],Ball["Right"]) - Math.max (Brick["Left"], Ball["Left"]) > 0)
Welche true
ergeben, wenn die Überlappung Elemente und false
wenn sie es nicht tun.
Angewandt auf Ihren Code, könnten wir die Kollision die folgende Art und Weise berechnen
bricksCollision: function() {
for (var i = 0; i < $bricks.length; i++) {
var $brick = $($bricks[i]);
var offset = $brick.offset();
var brickBounds = [offset.left - field.l]; //brick left pos
brickBounds[1] = brickBounds[0] + 40 //bricks right pos -> left pos + .bricks.width;
var ballBounds = [ball.l]; //balls left pos
ballBounds[1] = ballBounds[0] + 20 //balls right pos -> left pos + #ball.width;
if (ball.t <= (offset.top + 20) && (Math.min(brickBounds[1], ballBounds[1]) - Math.max(brickBounds[0], ballBounds[0])) > 0) {
$bricks[i].style.opacity = 0; //Make the brick opaque so it is not visible anymore
$bricks.splice(i, 1) //remove the brick from the array -> splice on the array, not the element
return true;
}
}
}
Damit konnten wir true zurück in die Move-Funktion, wenn der Ball mit einem Ziegelstein kollidiert.
Aber hey, wir wollen, dass es in die richtige Richtung abprallen, so dass wir ein anderes Problem. Also eher dann einen Booleschen Wert zurückgibt, ob der Brick kollidiert oder nicht, könnten wir eine neue Richtung, in der Rückkehr wird der Ball bewegen sollte.
Um nur die x oder y Teil der Richtung leicht zu ändern, sollten wir so etwas wie ein Vektor verwendet werden.
so tun, wir 2 Bits eines Integer, wo die Bit b0 Aufenthalte für die x-Richtung und die Bit b1 für die y-Richtung benutzen konnten. So dass.
Dec Bin Direction
0 -> 00 -> Down Left
^ -> Left
^ -> Down
1 -> 01 -> Down Right
^ -> Right
^ -> Down
2 -> 10 -> Up Left
^ -> Left
^ -> Up
3 -> 11 -> Up Right
^ -> Right
^ -> Up
Aber in der Lage sein, nur einen Teil der Richtung zu ändern, müssen wir die alte Richtung auf die Kollisionsfunktion, und bitweise &
und |
bzw. sie auszuschalten oder auf
auch verwenden, um übergeben Wir müssen berechnen, von welcher Seite der Ball kollidiert. Glücklicherweise haben wir eine Überlappungsberechnung von vorher, die bereits alle Werte verwendet, die wir brauchen, um die Kollisionsrichtung zu berechnen.
Wenn es darum geht, frome die
- rechts
- Brick [ "Right"] - Ball [ "Left"] hat den gleichen Wert wie die Überlappung sein.
- links
- Ball [ "Rechts"] - Brick [ "Left"] hat den gleichen Wert wie die Überlappung sein.
Wenn keiner von ihnen wahr ist, hat es entweder kommen aus dem
- Boden
- wenn Ball [ "Top"] mehr als (Brick [ "Top" ist ] plus die Hälfte der Brick [ "Höhe"])
oder auch von oben.
Um den Bereich zu reduzieren, wenn die Bedingung, für die Kollision von der Seite, true ausgewertet wir eine weitere Bedingung hinzu, dass die Überlappung als zB ... && overlap < 2
So weniger sein muss, wenn es mit dem Rand kollidiert es doesn nicht immer zur Seite springen.
So genug das Sprechen, im Code könnte dies wie etwas aussehen.
bricksCollision: function (direction) {
var newDirection = direction
var ballBounds = [ball.l]; //balls left pos
ballBounds[1] = ballBounds[0] + 20 //balls right pos -> left pos + #ball.width;
for (var i = 0; i < $bricks.length; i++) {
var $brick = $($bricks[i]);
var offset = $brick.offset();
var brickBounds = [offset.left - field.l]; //brick left pos
brickBounds[1] = brickBounds[0] + 40 //bricks right pos -> left pos + .bricks.width;
var overlap = Math.min(brickBounds[1], ballBounds[1]) - Math.max(brickBounds[0], ballBounds[0]);
if (ball.t <= ((offset.top - field.t) + 20) && overlap > 0) {
$bricks[i].style.opacity = 0; //Make the brick opaque so it is not visible anymore
$bricks.splice(i, 1) //remove the brick from the array -> splice on the array, not the element
if (ballBounds[1] - brickBounds[0] == overlap && overlap < 2) { //ball comes from the left side
newDirection &= ~(1); //Turn the right bit off -> set x direction to left
} else if (brickBounds[1] - ballBounds[0] == overlap && overlap < 2) { //ball comes from the right side
newDirection |= 1; // Turn the right bit on -> set x direction to right;
} else {
if (ball.t > (offset.top + (20/2))) //Ball comes from downwards
newDirection &= ~(2) // Turn the left bit off -> set y direction to down;
else //Ball comes from upwards
newDirection |= 2; // Turn the left bit on -> set y direction to up;
}
//console.log("Coming from: %s Going to: %s", field.directionsLkp[direction], field.directionsLkp[newDirection], direction)
return newDirection;
}
}
return direction;
}
Um das zu umgehen, sollten wir auch die moveXX
Funktionen ändern, die neue Richtung zu verwenden, zurückgegeben.
Aber wenn wir trotzdem die neue Richtung von der Kollisionsfunktion erhalten werden, könnten wir die vollständige Kollisionserkennung auf die Funktion, bewegen unsere Bewegungsfunktionen zu vereinfachen. Aber vorher sollten wir einen Blick auf die Bewegung Funktionen haben und eine Lookup-Objekt zu field
hinzufügen, die die Zahlen für die Richtung hält, um die Lesbarkeit zu gewährleisten.
var field = {
directions: {
uR : 3, // 11
dR : 1, // 01
dL : 0, // 00
uL : 2 // 10
},
directionsLkp: [
"dL","dR","uL","uR"
],
...
}
Nun sind die Bewegungsfunktionen dann so,
ballCondact: function() {
var moves = [moveDl,moveDr,moveUl,moveUr]
var timeout = 5;
function moveUr() {
var timer = setInterval(function() {
$ball.css({
top: (ball.t--) + "px",
left: (ball.l++) + "px"
})
var newDirection = game.bricksCollision(field.directions.uR) //get the new direction from the collision function
if (newDirection !== field.directions.uR) {
clearInterval(timer);
moves[newDirection](); //move in the new direction
}
}, timeout);
}
...
}
wie folgt aussehen könnte, ändert sich die Move-Funktion einfach die Richtung, wenn die Kollisionsfunktion eine Richtung gibt, die von der aktuellen unterscheidet.
Jetzt können wir beginnen, die Wandkollisionen auf die Kollisionsfunktion zu verschieben, um dies zu tun, könnten wir am Anfang einen weiteren Check hinzufügen.
bricksCollision: function (direction) {
...
if (ball.t <= field.t)
newDirection &= ~(2); //Ball is at top, move down
else if (ball.l <= 0) //Ball is at the left, move right
newDirection |= 1;
else if (ball.t >= field.b - ball.height) //Ball is at the bottom, move up
newDirection |= 2;
else if (ball.l > field.width - ball.width) //Ball is at the right, move left
newDirection &= ~(1);
if (direction !== newDirection)
return newDirection
...
}
Hinweis, verließ ich für die Plattform, um die Kollisionsprüfung heraus, wie die Idee sollte klar sein =)
Hier ist eine Fiddle
Nur eine Notiz, ist JavaScript nicht erzwingen eine '$ varName'-Konvention wie einige [andere Sprachen] (http://www.php.net). Sie können Ihre Bricks Array 'Bricks' anstelle von' $ Bricks' aufrufen. –
Wenn ich dich richtig verstehe, vergleichst du nur Top-Werte und Links-Werte. Dies bedeutet, dass die beiden Objekte genau die gleichen Werte haben müssen. Ich nehme an, du würdest beim Vergleich mindestens die Breite berücksichtigen müssen, wahrscheinlich auch die Höhe. – bestprogrammerintheworld
Das Problem ist, dass ich die oberste Position meiner Elemente im Array $ bricks nicht erkennen kann. Ich habe versucht durch jQuery-Funktion ** $ Bricks [i] .offset(). Top ** aber Konsole zeigt ** Uncaught TypeError: Objekt 0 hat keine Methode 'Offset' ** – kuzyoy