I'm working on a game that allows players to click on a card and drag it across the screen in any random direction. There are a total of 64 100x80 overlapping cards on a 800x800 canvas at any one time and each one is a procedural draw. As some of you probably suspect, canvas doesn't like redrawing that entire canvas for every move. To work around this, I'm utilizing a buffer canvas to draw the card and then attempting to paint that buffer canvas to the main canvas using drawImage(). To ensure there is no drawing buildup, I clear the region of the canvas associated with where I plan to drawImage() using a clearRect().
The problem I'm experiencing is that because the (x,y) coordinates used for the clearRect() and drawImage() are coming from the location of the mouse, if the user moves too fast, the coordinates will differ from the time drawImage() was last executed to the time clearRect() is called during the next draw sequence. The result is residual draw from the last sequence - proportionate to how fast the card is being dragged.
I tried maintaining the (x,y) coordinates from the drawImage() and using those (instead of the current mouse location) for the clearRect() in the next sequence. However, now instead of residual draw being shown, residual we have residual clear (erase).
Thoughts on how I can address this?
NOTE: My animation rate is handled using RequestAnimationFrame and not SetInterval().
Assuming your canvas is static during the drag drop operation, a pretty easy way to get a good increase in performance would be to just cache the rendering.
In other words, when a drag drop operation begins, save the current canvas into another one. Stop all rendering except for the one involved with dragging the card. Now, whenever you need to repaint, simply repaint from your copy-canvas. Since you're basically just copying from one to another, it should be pretty fast.
On each processing cycle, you would take the current position of the dragged card, fill that with data from the copy, then redraw the dragged card in the new position.
Other approaches you could try would be to use some kind of a placeholder for the drag. For example, consider using a same-sized DIV which you display while dragging. This should have the benefit of not requiring to touch the canvas while dragging and thus also run a better performance for it.
Related
I have a pygame screen with multiple tree like objects which grows with each update. I also have to draw random circle which appear and disappear with each update.
I am not able to make the circles alone to disappear. If I try to redraw I loose the slowly incrementing tree structure also. Any help
Using sprite groups (http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group) you can put all the tree like objects into a sprite group designated for trees. Then at the end of the game loop you could blit the background onto the screen and call "tree_group.draw(screen)" to draw all your tree sprites wherever they may be on the screen. With that in place, you can simply draw a random circle wherever you'd like without worrying about taking corrective measures and trying to fix where the circle was drawn previously. Using sprite groups makes updating in game loops a breeze as well. Just call "tree_group.update(args)" and every object in the group will update with the arguments passed in.
I have created a dot matrix slider on a canvas element (much like the sort you get in the stock exchange). Currently I have each letter laid out as an individual matrix and then, through a succession of loops I have these letter converted into one large matrix.
I then go through and draw this matrix column by column up to a maximum amount of columns. The matrix then gets redrawn every X milliseconds, offsetting the viewable area of the matrix by one each iteration until it eventually loops. The large matrix doesn't get redrawn every time.
My issue is that the animation doesn't seem smooth at lower redraw intervals - it jumps about. I've checked the frame rate and it seems fine but occasionally it jumps and I can't work out why!
The function with the settings is right at the bottom of the JSFiddle.
dotMatrix({
animationDelay: 1000,
canvasSelector: '#dot-matrix',
dotRadius: 2,
loop: true
});
Here are some steps you could do:
Prerender each char to an off-screen canvas in a solid color on transparent background. This canvas will be used as a sprite-sheet later. Drawing a rounded rectangle is a relative expensive operation especially when you need x number of it per char.
Set up a gradient for the colors and store that too in an off-screen canvas (by now we can see memory-caching is coming to the rescue..).
Every time you update use requestAnimationFrame instead of setInterval. The latter is not able to synchronize to monitor update. Scroll delay can be calculated using the number of frames elapsed as well as the time since last update (see rAF doc for details).
For each update clear, then "blit" the letter from the sprite-sheet canvas to main canvas. When all are blitted change composite mode to source-atop and blit the gradient canvas on top, and reset composite mode to source-over (don't use save/restore - they are expensive).
In the last step you could also use composite mode copy instead of clearing canvas and using source-over, as that will remove any previous existing pixels for the area you draw to.
Hope this gives you some inputs to improve the performance.
I'm writing a painting application with canvas in HTML5.
I've finished my pencil painting with touching and drawing.
And now i'm trying to make a rectangle. For all the topic i've read, i will have to store all of my finished shape in an array, but if i do that, i will also have to store all the point with normal drawing so that i could draw a rectangle like windows painting.
Please give me another solution to draw rectangle like windows, which old rectangle will be dissappeared and new one will replace before i make a "mouse up".
thanks in advance :)
You will either need to save the previous drawings or use 2 canvases.
If you want to save the previous drawings...
In mousedown:
Save the mouse position (startX/startY).
Set a flag indicating that a drag has started (isDown=true)
In mousemove:
if isDown==false, don't do anything (return)
otherwise, clear the canvas
redraw all your previous drawings (from your saved points array, etc)
draw the current rect from the start to mouse position -- context.strokeRect(startX,startY,mouseX-startX,mouseY-startY)
In mouseup:
clear the drag flag (isDown=false)
If you want to use 2 canvases...
As an alternative to storing every previous drawing, you can use 2 canvases. One canvas is used to draw the current rectangle and a second canvas to keep all the previously draw items Here's an example using 2 canvases so you don't have to store previous drawings: jsfiddle.net/m1erickson/V9J5J/
I'm working on a small game in Flash (AS3) that generates levels using small tiles.
The location,width,height and other properties of the tile are stored in an array upon generation. Each tile is added to the same container movieclip. When all tiles have been generated, the container movieclip is converted to a bitmap, all tiles are removed from the stage, and the original container is removed from the stage and then deleted. The bitmap is the only remaining "graphic" on the stage, aside from the player.
This yields far better performance than allowing all 60,000+ tiles to be rendered individually during gameplay; however, the framerate still reduces as the number of tiles is increased. This makes no sense, as all the tiles are added to a single bitmap that is always the same size, regardless of the amount of tiles.
With 20,000 tiles during generation, the game runs at the full FPS, but with 60,000 it runs relatively choppy, probably around 4-5 FPS.
I've removed collision detection and any/every script that runs through the tile array to rule out the possibility that some other CPU intensive part of the script is lagging the framerate.
Any idea why, despite the fact that all tiles have been removed from the stage and their container is deleted, the game is still running slow even though the background bitmap contains the same amount of data regardless of the number of tiles generated?
Here is the last part of the level generation algorithm which converts the container movieclip to a bitmap and then removes all the tiles:
var temp_bitmap_data:BitmapData = new BitmapData(this.stage_background_mc.width,this.stage_background_mc.height);
temp_bitmap_data.draw(this.stage_background_mc);
this.stage_background_bitmap = new Bitmap(temp_bitmap_data);
main_class.main.stage.addChild(this.stage_background_bitmap);
for (var block in blocks_array)
{
//every block in blocks_array has a child that is the actual graphic of the tile
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
if (blocks_array[block]["type"] == "bg_block")
{
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
blocks_array[block]["block"] = null;
}
if (blocks_array[block]["type"] == "path_block")
{
//path_blocks have a second child in addition to the first one that's already been removed. the second child is the only other child
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
}
}
this.stage_background_mc = null;
[Edit]
Here is a picture of the game to give you a better idea of what's going on:
[Update:]
Even removing the final created bitmap from the stage, ending up with only 1 child on stage, and setting that removed bitmap to null doesn't improve the speed.
A couple of thoughts.
First, you're sorta half taking advantage of AS3's quick work with blitting. You've got the right idea about having only one single Bitmap on the stage, but the steps before (adding DisplayObjects to a MovieClip and the doing draw on that MovieClip) isn't the fastest process. For one thing, BitmapData.draw is slower than BitmapData.copyPixels (here is a post on that). One of the best ways to get speed is to pre-blit all of your graphics, and store them as BitmapData. Then, keep Object references (containing position, etc) for each graphic. In your render loop, run through each object, and use copyPixels to copy the graphic's pixel information to the appropriate positon in your single, on-stage Bitmap. This way, all slow BitmapData.draw commands have happened upfront, and now you are just pushing pixels, which Flash is really fast at.
That process isn't without its downsides, however. For instance, you can't do easy transforms with it. You'd have to pre-blit all frames of a rotation, for instance, in order to rotate the individual graphic (since you can't rotate a BitmapData, and you aren't using draw on a DisplayObject). Still, it is mighty fast if you can live with the limitations.
Here is a post that serves as a tutorial of the process I explained above. It is old, but informative none-the-less.
Finally, 60,000 is a very large number. Flash isn't exactly a "speed demon." No matter how optimized, eventually you'll hit a limit. Just something to keep in mind.
Oh, and this additional post gives some great tips on performance in Flash.
I'm trying to find a clean way to "move the camera" of a canvas element.
This for my prototype game (side scroller). I'd love to think there's a better solution than moving the whole set of nodes to simulate a "camera" moving around.
Am almost certain to have read a simple how-to (using offsets?) but the fact I don't find anything like that starts to raise doubts... have I imagined reading that!?
Thanks to help me clarify...
J
Presumably you redraw your whole game scene 30 times a second (more or less)
You need to redraw your whole game scene but first translate the Canvas context by some offset.
context.translate(x,y) is precisely what you want. You'll want to read up on the use of that as well as the save() and restore() methods.
When you translate the context, everything drawn afterwards is shifted by that amount.
So you constantly draw something (maybe an enemy) at 50,50 using drawImage(badguy,50,50). Then the player moves, which changes the x of translate to -1 (because the player is moving to the right) instead of 0. You still draw the enemy sprite with the command drawImage(badguy,50,50), but when you draw it the enemy shows up as if it were at 49,50 because of the context.translate(-1,0) command shifting everything before its drawn.
Of course when you get into performance you'll want to be making sure that you are only ever drawing things that can actually be seen on the screen! If your are far down the level with context.translate(-2000,0), you dont want to be drawing objects at 50,50 anymore, only ones that intersect the viewable area.