Draai een sprite in canvas

Ik gebruik canvas om enkele sprites weer te geven, en ik moet er een horizontaal spiegelen (zodat het naar links of rechts wijst). Ik zie echter geen methode om dat te doen met drawImage .

Hier is mijn relevante code:

this.idleSprite = new Image();
this.idleSprite.src = "/game/images/idleSprite.png";
this.idleSprite.frameWidth = 28;
this.idleSprite.frameHeight = 40;
this.idleSprite.frames = 12;
this.idleSprite.frameCount = 0;

this.draw = function() {
        if(this.state == "idle") {
            c.drawImage(this.idleSprite, this.idleSprite.frameWidth * this.idleSprite.frameCount, 0, this.idleSprite.frameWidth, this.idleSprite.frameHeight, this.xpos, this.ypos, this.idleSprite.frameWidth, this.idleSprite.frameHeight);
            if(this.idleSprite.frameCount < this.idleSprite.frames - 1) { this.idleSprite.frameCount++; } else { this.idleSprite.frameCount = 0; }
        } else if(this.state == "running") {
            c.drawImage(this.runningSprite, this.runningSprite.frameWidth * this.runningSprite.frameCount, 0, this.runningSprite.frameWidth, this.runningSprite.frameHeight, this.xpos, this.ypos, this.runningSprite.frameWidth, this.runningSprite.frameHeight);
            if(this.runningSprite.frameCount < this.runningSprite.frames - 1) { this.runningSprite.frameCount++; } else { this.runningSprite.frameCount = 0; }
        }
    }

Zoals je kunt zien, gebruik ik de methode drawImage om mijn sprites naar het canvas te tekenen. De enige manier om een ​​sprite om te draaien, die ik kan zien, is om het hele canvas te draaien/draaien, en dat is niet wat ik wil doen.

Is er een manier om dat te doen? Of moet ik een nieuwe sprite maken die de andere kant op kijkt en die gebruiken?

20

3 antwoord

Terwijl Gaurav de technische manier heeft getoond om een ​​sprite in canvas om te draaien ...

Doe dit niet voor je game.

Maak in plaats daarvan een tweede afbeelding (of maak je huidige afbeelding groter), dat is een omgedraaide versie van de spite-sheet. Het verschil in prestaties tussen 'de context kantelen en een afbeelding tekenen' of 'alleen maar een afbeelding tekenen' kan enorm zijn. In Opera en Safari resulteert het omdraaien van het canvas in een tekening die tien keer langzamer is en in Chrome is het tweemaal zo traag. Zie deze jsPerf voor een voorbeeld.

Het vooraf berekenen van je gespiegelde sprites zal altijd sneller zijn, en bij het spelen van games doet canvas performance er echt toe.

33
toegevoegd
Bedankt. Wat ik uiteindelijk deed was het toevoegen van een andere sprite aan mijn bestaande (eronder) met mijn karakter de andere kant op en een code toegevoegd om die set sprites te gebruiken, afhankelijk van de richting. Vind dit leuk: i.imgur.com/uIPvF.png
toegevoegd de auteur James Dawson, de bron
Ziet er goed uit! Hoewel ik de nieuwe rij opnieuw zou rangschikken: zet de omgedraaide versie van elk verticaal op een rij, dus het enige dat je moet veranderen bij het omdraaien is de y-coördinaat.
toegevoegd de auteur Simon Sarris, de bron
Jeff, je noemt een goed punt dat opslaan en herstellen niet nodig zijn, maar je resultaat was een toevalstreffer, zie de resultaten nu. Mogelijk bent u aan de test begonnen voordat de browser klaar was met het laden van de pagina of Java (gebruikt in de timer). Ik zou zeggen dat de test niet accuraat is op /4 omdat het werk dat nodig is om te draaien ook het werk moet omvatten om de transformatie terug te brengen naar de normale status. Dit betekent minimaal een tweede aanroep van ctx.scale (-1,1) . Hier is een "eerlijke" test en het bladeren gaat langzamer in elke geteste browser en elk mobiel apparaat, soms heel erg: jsperf.com/ctx-flip-performance/5
toegevoegd de auteur Simon Sarris, de bron
Woah! Je hebt net iets echt belangrijks laten zien. De instelfunctie van Jsperf is verbroken en het canvas wordt niet opgeruimd! Zie jsperf.com/ctx-flip-performance/10 voor wat er gebeurt als ik expliciet duidelijk binnen de test en zie jsfiddle.net/sX2jT voor wat er echt gebeurt. schaal vermenigvuldigt zich altijd, het is een bug met jsperf die we zien :(
toegevoegd de auteur Simon Sarris, de bron
Gaurav's antwoord is eigenlijk alleen maar prestatie duur vanwege de ctx.save/restore. Als je simpelweg ctx.scale (...) elke keer oproept, trekt de flipped-versie hilarisch sneller: jsperf.com/ctx-flip-performance/3 . (het is zelfs sneller als je ctx.scale (-1) voor de omgedraaide callt en niets voor de niet-omgedraaide case: jsperf.com/ctx-flip-performance/4 ).
toegevoegd de auteur Jeff Gates, de bron
Ik had gedacht dat .scale() de transformatieschaal instelde in tegenstelling tot het te vermenigvuldigen. De vermenigvuldiging is wat wordt geïmpliceerd in de docs w3.org ( dev. w3.org/html5/2dcontext/#dom-context-2d-scale ), waardoor test/4 inderdaad ongeldig zou worden. (Het gebruikt de term 'toevoegen' die een beetje ambigu is). Dat is echter niet wat het lijkt te doen, althans bij Chrome: jsperf.com/ctx- flip-performance/8 .
toegevoegd de auteur Jeff Gates, de bron

U kunt de context van de canvastekening transformeren zonder het hele canvas om te draaien.

c.save();
c.scale(-1, 1);

zal de context weerspiegelen. Teken dan je afbeelding

c.restore();

and you can draw normally again. For more information, see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Transformations

11
toegevoegd
Dank je! Maar dankzij Simon's antwoord, zal ik zijn techniek gebruiken. Ik zal de jouwe markeren als het geaccepteerde antwoord, omdat het mijn vraag beantwoordt :)
toegevoegd de auteur James Dawson, de bron

Use this to flip your sprite sheet http://flipapicture.com/

3
toegevoegd
Helaas ondersteunt dit geen PNG's :(
toegevoegd de auteur Scott, de bron