📜 ⬆️ ⬇️

Fifteen on LibCanvas

Recently on Habré there was an article about tags on Canvas .
Excellent article, I am sure, beginners will find a lot of useful things in it. Unfortunately, in the comments spoke about a little over-consumption of the processor.
This is not from a lack of technology, but from insufficient experience and convenient tools.
In this topic I will tell you how, with the help of LibCanvas , to make this game completely undemanding on the processor and looking great.

In the game, by reference, it was enough to fix just one caveat - remove the unnecessary redrawing of each frame and call it only when the canvas changes.
But we will go further - we introduce the animation of the movement of chips. During the animation, when redrawing the entire canvas, we will have the same problem — an unnecessarily loaded processor, so we’ll think about what we can do.




')

Dirty rectangles


It is easy to see that the image changes infrequently. It is necessary to use this and, instead of redrawing the entire canvas, we erase the old location of the tag with the help of clearRect and draw a new one.

It is enough for us to sketch the old cell and clear the new one (in fact, it would be possible to constantly keep the previous place of drawing the chips, but this is not so critical).

var Tile = atom.Class({ [...] redraw: function () { this.libcanvas.ctx .clearRect( this.lastPositionRectangle ) .clearRect( this.field.emptyRectangle ); this.draw() }, [...] }) 


So now we have the code to redraw the chips. Suppose earlier our application redraws every frame. The code for moving the chips looked like this:

 var Tile = atom.Class({ [...] move: function (point) { //  , ,    ,     this.field.blocked = true; this.animate({ time: 150, props: { x: point.x, y: point.y }, onFinish: function () { //   this.field.blocked = false; }, fn: 'sine-out' }); }, [...] }) 


We disable the automatic redrawing of each frame and add the code that causes each chip to redraw itself when moving:
 var Tile = atom.Class({ [...] move: function (point) { //  , ,    ,     this.field.blocked = true; this.animate({ time: 150, props: { x: point.x, y: point.y }, onProccess: this.redraw.bind(this), onFinish: function () { //   this.field.blocked = false; this.redraw(); }, fn: 'sine-out' }); }, [...] }) 


Now each step will cause a redraw of the canvas. In principle, this is quite enough for a completely smooth animation and almost free software, but let's go further.

Buffering


If you inspect the application in the Javascript console, you will notice that the most significant part is the redrawing of the canvas, in which such heavy functions as gradient rendering are called.

For your application, you can roughly assume that (program) == 'System Idleness'

Fix this annoying misunderstanding by pre-drawing chips into the buffer. Create a new hidden canvas, draw a chip into it and then draw the canvas itself instead of calling a heap of heavy functions. I use the plugin atom.Class.Mutators.Generators for this - a simple way to generate an object once and then take it from the cache.
Suppose we used to have the following code, which draws the chip:
 var Tile = atom.Class({ [...] draw: function () { this.callHardDrawFunctions( this.libcanvas.ctx ); } [...] }) 


Change it to the following code:
 var Tile = atom.Class({ [...] Generators: { buffer: function () { var buffer = LibCanvas.buffer( this.shape, true ); this.callHardDrawFunctions( buffer.ctx ); return buffer; } }, draw: function () { this.libcanvas.ctx.drawImage({ image: this.buffer, draw : this.shape }); } [...] }) 


Yes, it has become a little less elegant, but, on the other hand, we have reached the goal, drawing our spots is very fast and completely undemanding of resources:


Before the introduction of the buffer


After the introduction of the buffer

Conclusion


Program and enjoy the result )

Source: https://habr.com/ru/post/118567/


All Articles