2013-05-28 3 views
6

Ich arbeite an einem Javascript-Spiel, das die Gravitationskräfte simuliert. Es verwendet das HTML5-Canvas-Element, um 2D-Ellipsen für Planeten zu zeichnen. Ich teste mein Spiel in Google Chrome. Hier ist ein Link zum Spiel: http://gravitygame.hostingsiteforfree.com/index.php?page=playHTMLWarum würde der canvas2d-Kontext keine Ellipsen mehr füllen?

Bis zum 24. Mai funktionierte es gut. Nachdem Chrome jedoch von 26.0.1410.64 auf 27.0.1453.94 aktualisiert wurde, werden die gefüllten Ellipsen manchmal nicht gezeichnet. Es passiert nicht jedes Mal, wenn ich mein Spiel lade, und ich habe es nie kaputt gemacht, während ich lokal lief.

Hier ist ein Screenshot des Spiels arbeiten: enter image description here

Und hier ist ein Screenshot, dass es nicht das Füllen der Ellipsen zeigt: enter image description here

Ich kann nicht sagen, was passiert. Ich werde den Teil der Schleife einschließen, der alle Planeten zeichnet. Ich habe es für die Lesbarkeit geändert.

var i = bodies.length; 
    while(i--){ 
    var I = bodies[i]; 
    var planetRad = (I.width/2)*_scale; 
    if(_showTrails){ 
     //draw the planet's trail 
    } 
    if(//the planet is completely off the screen){ 
     //draw a red planet on the edge of the screen 
     ctx.beginPath(); 
     ctx.arc(nX, nY, 2.5, 0, TWOPI); 
     ctx.fillStyle = offScreenColor; 
     ctx.fill(); 
     ctx.strokeStyle = offScreenOutline; 
     ctx.stroke(); 
    } 
    else{ 
     //draw planet 
     ctx.beginPath(); 
     ctx.arc(nX, nY, (I.width/2)*_scale, 0, TWOPI); 
     ctx.closePath(); 
     ctx.fillStyle = I.bodyColor; 
     ctx.fill();  
    } 
    if(_showMotionVector){ 
     //draw a line from the center of a planet showing the direction and speed it's travelling 
     ctx.strokeStyle = motionColor; 
     ctx.beginPath(); 
     ctx.moveTo(I.getScX(), I.getScY()); 
     ctx.lineTo(I.motion.x * _scale * 12 + I.getScX(), I.motion.y * _scale * 12 + I.getScY()); 
     ctx.stroke(); 
    } 
} 

Warum würde es plötzlich gelegentlich brechen?

+0

Ich stieß auf ein ähnliches Problem mit IE, also hier ist ein Versuch. Ist es behoben, wenn Sie ctx.closePath() hinzufügen; nach dem ersten Bogen in Ihrem Beispiel Code? – markE

+0

Das hat nicht funktioniert. Ab und zu bin ich immer noch in der Lage, es zu laden, und die Planeten tauchen nicht auf. – Justin

+0

Kann nicht in Chrome oder Canary (+ andere Browser) reproduziert werden (in FF-Panning funktionierte nicht für mich btw). Wie triggern Sie die Animationsschleife? – K3N

Antwort

5

Ich habe mir Ihren Online-Code angesehen und festgestellt, dass Sie setInterval für die Animationsschleife verwenden.

Dies ist wahrscheinlich der Grund, als ob der Code nicht in der Lage ist, den Aufruf der Berechnungen usw. zu beenden. Sie riskieren das Stapeln von Aufrufen - für einen Kontext bedeutet das, dass Pfade sich gegenseitig zurücksetzen können.

Versuchen Sie zuerst setInterval durch setTimeout zu ersetzen. Sie werden natürlich müssen sie aus dem Code wieder triggern - noch besser, am Ende dieser Funktion mit einem setTimeout alles in Funktion setzen, dh .:

function animate() { 
    //... calcs and redraws which you have in setInterval 
    setTimeout(animate, 0); 
} 
animate(); 

Ich benutze 0 für Timeout hier für diesen Prüfung. setTimeout/setInterval wird in keinem Fall mit der Bildschirmaktualisierungsrate synchronisiert.

Wenn das funktioniert, dann kennen Sie den Grund. Der nächste Schritt wäre, es durch requestAnimationFrame zu ersetzen, aber lassen Sie mich wissen, wie es geht.

In einem Versuch, das Problem zu veranschaulichen wir an dieser Abbildung aussehen:

Working interval

Jeder Block stellen eine Funktion innerhalb der Schleife, und eine Schleife ist eine Farbe. Denken Sie daran, dass setInterval Anrufe feste Intervalle während setTimeout Aufrufe relativ an, wenn es heißt. In diesem Beispiel funktionieren die Funktionen innerhalb des Zeitbudgets, so dass alles gut geht.

In der nächsten Abbildung:

Stacking interval

die Ausgaben außerhalb des Haushalts ist so setInterval erneut aufgerufen wird und reiht nächsten Aufruf der zweiten Schleife, bevor der erste beendet ist. Wenn die Warteschlange zwischen den Aufrufen verarbeitet wird, riskieren Sie, dass zwei Funktionen gleichzeitig am Kontext arbeiten (oder in einer anderen Reihenfolge als erwartet).

Javascript ist natürlich single-threaded, so dass sie nicht zur gleichen Zeit ausgeführt werden, aber man wird auf warten gehalten - wenn der erste Block für die nächste Warteschlange aufgerufen wird, bevor der letzte Block aufgerufen werden muss, dann der erste Block ändert den Kontext und ändert möglicherweise sogar den Pfad, bevor der letzte Aufruf des vorherigen Aufrufs aufgerufen wird. Im Laufe der Zeit wird die Verzögerung zunehmen und potenziell (wenn nicht einige zusätzliche verfügbare Verarbeitungsressourcen die Warteschlange ab und zu auflösen - auf einem ausgelasteten System wird dies weniger wahrscheinlich passieren), werden sie immer schlimmer, je mehr Stapelung auftritt.

Dh, in diesem Fall könnten Sie Zeilen zum Kontext mit beginPath() hinzugefügt haben, bevor arc gefüllt wurde.

(Hoffnung, die einen Sinn ...)

setTimeout Verwendung verhindert dies, da es nicht ausgeführt werden, bevor alle Anrufe in der Animationsschleife zurückgekehrt ist. Die bessere Option ist, requestAnimationFrame zu verwenden, da dies synchron mit der Bildschirmaktualisierungsrate auch wenn möglich aufrufen wird. Es ist niedriger und damit auch effizienter.

Ein anderer Weg (kein Wortspiel beabsichtigt) ist, Web-workers zu verwenden, um die Berechnungen durchzuführen. Dies wird multi-threaded sein und kann die Gesamtleistung erhöhen, da ein Web-Arbeiter den UI-Thread nicht beeinflusst.

+0

Mein erster Test von setTimeout() scheint zu funktionieren. Ich muss es auf einigen Computern ausprobieren, bevor ich überzeugt bin. Ich werde Sie die Ergebnisse wissen lassen. – Justin

+1

Sieht soweit gut aus. Ich musste die Änderung, die Sie in Ihrem ersten Kommentar erwähnt haben, zusätzlich zum Wechsel von setInterval zu setTimeout vornehmen. – Justin

Verwandte Themen