I am in the middle of process of making a HTML5 game. Now I have a problem related to performance.
I have some irregular Shapes. So detecting if {x,y} is in the Shape or not using a custom function is near impossible(At least as I think).
There are two big Shapes, so I need to call Shape.intersects({x,y}) twice for multiple times per second to detect if current {x,y} is in the shape or not.
{x,y} are variable and are not touch/mouse events. So I can not use onmousemove,etc events.
Each twice call of Shape.intersects({x,y}) on Nexus 5 has a ~45ms overhead. ~45ms each 100ms! This make some hiccups in game experience.
The most straight solution is to make Shape.intersects({x,y}) non-blocking. But how? or do anyone have any idea around this problem?
I am using Kinetic v5.0.1
RESULT:
.intersects will re-generate the Shape in memory, this is why it is very costly. According the to the #MarkE answer below, using native canvas function context.isPointInPath(x, y) would be very efficient. But:
Note that this will only work for the last path (after using beginPath()). If you need to iterate several paths (ie. shapes) you need to re-construct the paths (no need to stroke or fill though). This is perhaps a reason why some don't use it.
Source: https://stackoverflow.com/a/17268669/172163
In my shapes, I had solid colors. Also there are multiple shapes dynamically generated. so I ended up with context.getImageData(x, y, 1, 1) to get the color of specific pixel, and if it is the color of my Shapes are not. It is more efficient than .intersects(). It costs only ~3ms.
Why intersects gives you a performance hit (pun intended!)
Internally, KineticJS uses context.getImageData to do hit-tests in the intersects method.
getImageData provides pixel-perfect hit testing but it's slow on mobile devices (as you've discovered).
To answer your question:
No, you cannot run KineticJS's internal methods on a background worker thread.
But...
If you really need to squeeze performance out of hit-testing, you can write your own custom hit-test.
One possibility for such a custom hit test would be to maintain 2 offscreen html5 canvas elements that mirror your 2 irregular shapes.
That way you can use canvas's context.isPointInPath(x,y) to do your hit-testing.
The importance is that isPointInPath uses GPU acceleration and is therefore quite fast.
If you feel ambitious you could even create an asynchronous background worker thread to execute isPointInPath while your UI thread continues.
You mention the Nexus5. You can spawn a background worker thread with Android's AsyncTask.
Your background task can return the results of your hit-test using it's onPostExecute(Result) callback which invokes on the UI thread.
http://developer.android.com/reference/android/os/AsyncTask.html
Good luck with your project!
Related
We are developing a web-based game. The map has a fixed size and is procedually generated.
At the moment, all these polygons are stored in one array and checked whether they should be drawn or not. This requires a lot of performance. Which is the best rendering / buffering solution for big maps?
What I've tried:
Quadtrees. Problem: Performance still not as great because there are so many polygons.
Drawing sections of the map to offscreen-canvases. A test run: http://norizon.ch/repo/buffered-map-rendering/ Problem: The browser crashes when trying to buffer that much data and such big images (maybe 2000x2000) still seem to perform badly on a canvas.
(posting comments as an answer for convenience)
One idea could be, when the user is translating the map, to re-use the part that will still be in view, and to draw only the stripe(s) that are no longer corrects.
I believe (do you confirm ?) that the most costly operation is the drawing, not to find which polygon to draw.
If so, you should use your QuadTree to find the polygons that are within the strips. Notice that, given Javascript's overhead, a simple 2D bucket that contains the polygons that are within a given (x,y) tile might be faster to use (if the cost of the quadtree is too high).
Now i have a doubt about the precise way you should do that, i'm afraid you'll have to experiment / benchmark, and maybe choose a prefered browser.
Problems :
• Copying a canvas on itself can be very slow depending on devices/Browsers. (might require to do 2 copy, in fact)
• Using an offscreen canvas can be very slow depending on devices/Browsers. (might not use hardware acceleration when off-screen).
If you are drawing things on top of the map, you can either use a secondary canvas on top of the map canvas, or you'll be forced to use an off-screen canvas that you'll copy on each frame.
I have tried a lot of things and this solution turned out to be the best for us.
Because our map has a fixed size, it is calculated server-side.
One big image atlas with all the required tiles will be loaded at the beginning of the game. For each image on the atlas, a seperate canvas is created. The client loads the whole map data into one two-dimensional array. The values determine, which tile has to be loaded. Maybe it would be even better if the map was drawn on a seperate canvas, so that only the stripes have to be painted. But the performance is really good, so we won't change that.
Three conclusions:
Images are fast. GetImageData is not!
JavaScript has not yet great support for multi threading, so we don't calculate the map client-side in game-time.
Quadtrees are fast. Arrays are faster.
I want to build a simple modelviewer. In fact that most 3D Engines for javascript/canvas out there are way too complex for my purpose I'd prefer building a small one on my own. By writing a z-buffer I'd like to check wether canvas API should draw a pixel over the existing image. At the moment I am using the method fill() to draw triangles. I do so because I'd like to avoid writing my own anti-aliasing stuff. Are there any callbacks or is there any other way I can implement my check into the native script?
In fact that's going to be in Adobe AIR, are there any native ressources I could use to speed up(molehill/Stage3D WebGL? Dunno). Or are there any ways in combination of Flash? Actually I'd prefer Javascript but if there are native solutions I'd also like to check them as long as I can implemenet them into my HTML mock-up.
EDIT: A more simply question: Is it possible to implement a check for each pixel the canvas API should draw to abort drawing the pixel if it doesn't fit some conditions? I don't think that the chance is high that the question becomes affirmed but its really woth it.
I'm making a game in canvas where most of my drawings so far are solid shapes and arcs. But I want to add effects like blur and shadow to create glow and trail effects.
My question is, is there a a nice way, without external libraries, to cache the glowing element (player, enemy, etc) and is it worth it to do that instead of recreating the effects each time? Same goes for rotations. If I have about 40 different angles I draw repeatedly as a player rotates their ship, should I just cache those calculations?
I'm currently rotating the arc endings using manual transforms, instead of rotating the context since I don't yet know if that is more or less efficient than rotating the canvas repeatedly for the many onscreen elements and their different angles
Blur and shadow effects are not included in the main canvas library but you may create your own library or you can use external canvas libraries like easel.js but there are tons of different libraries related to HTML5 <canvas>. You may choose which is best suited for you.
As the matter of the blur effect you may use Mario Klingeman stackblur javascript implementation: http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html. It's easy to use and super fast.
For glowing effect a nice way for random texture generation would be the simplex noise algorithm already implemented in javascript: https://gist.github.com/304522 or the original one here: http://mrl.nyu.edu/~perlin/noise/
For the last question i advise you for a better performance to use the context save and restore functionality. It's much faster.
Is there a quick and efficient way to move lots of objects in canvas? Basically if there are around 1000 objects and I want to move all of them at once to emulate scrolling, it is very slow to redraw every single object by calling drawImage() 1000+ times.
Is there anyway to optimize this? I have an example link of the problem (and that's only with 100 objects): http://craftyjs.com/isometric/
Since canvas doesn't provide fast low level bitmap copying it's hard to do stuff in multiple layers and scroll for example the whole background at once and then only render the edges.
So what can you do? In short, nothing. Especially not when scrolling, sure you can do tricks with multiple canvases when you have a more or less static background but for moving objects there are hardly any performance improving tricks.
So, you've go to wait for Hardware Acceleration shipping in all majors browsers, I know this sounds ridiculous but I'm too waiting for that :/
The problem is that the canvas was never designed for game stuff. It was designed as, well, basically some kind of on the fly drawing thing, guess the designers had Photoshop clones in mind, but definitely not games, let alone the fact that there's no fast clear operation proves that, there's not even optimization in place when clearing the whole canvas with the same color.
If the images are already composited, not moving relative to one another, and defined by a rectangular region, then using canvas.drawImage() with a canvas as the first parameter and drawing to a sub-region should be significantly faster than re-drawing all the objects.
You could also just layer multiple canvases and slide the top canvas with the objects in HTML to scroll them.
Edit: Having really looked at your example, it seems to me that it should be implemented similar to Google Maps: create tiles of canvases and slide them left/right on the HTML page; once a canvas has been slid off the screen entirely (for example, off the left edge), move it to the other side (to the right edge) and re-use it for drawing. With this you will only need to re-draw whatever objects overlap the canvases that are moving on the edges.
You can draw all objects on a second, off-screen canvas and then only blit the whole canvas (drawImage() accepts canvas element).
However, if you're targeting desktop browsers, then this shouldn't be necessary. I've implemented tile engine (source) that simply redraws whole scene and naive implementation turned out to be pretty fast.
What I did to solve this problem was I had 10 squares on my screen and I wanted to animate them on a white background. So I drew a white rectangle over the canvas to clear the canvas so the animation would work. Does that make sense?
#Ivo By the way I read on http://www.w3.org/TR/html5/the-canvas-element.html that canvas was made for applications like games because it was a solution to get rid of the dependency on a external engine. Canvas is built in so it's kind of like a flash player built into your browser powered by JavaScript. I think it's fascinating.
You can use tiled rendering.
http://www.gamesfrommars.fr/demojsv2/ (better viewed with Chrome)
Hi I'm painting an image onto a canvas (html5) and I want to reduce the number of fillRect calls I'm making in the hope of making the process more efficient.
Note: I'm calling canvas.fillRect to paint individual pixels and pixels can be 1x1 or other size rectangle depending on resolution I'm painting in (So I know that they are not called pixels but my image vocab is limited).
What I would like to do is find and merge individual pixels if they are the same colour. This will reduce the number of calls to fillRect and hopefully be faster than what I currently have.
So lets say I have a bit map like this:
[fff, fff, fff]
[f00, f00, f00]
[00f, 00f, 00f]
Instead of making 9 calls to fillRect I would like to make 3.
So my questions are:
1) What is this process called (so I can do some more intelligent research, as googling 'merging pixels', 'merging rectangles', etc, yields no useful results).
2) Anyone aware of any open source library that implements this (does not have to be javascript)
3) Does anyone think that adding this pre-processing step will actually make the code slower in JS?
Thanks All
Guido Tapia
I would agree with #Jakub that doing this kind of analysis in Javascript is likely to take a lot longer than the time you save by filling fewer rectangles (usually a very fast operation for a graphics card). That is unless you have to paint the same set of rectangles many thousands of times.
As for what it's called, the closest thing I can come up with is run-length encoding, which admittedly is one-dimensional rather than two.