I have many small, identical vector circles that move around the screen, but only appear for a defined period in defined areas. Currently, these circles are children of whatever parent object produces them, and each is given its own interframe handler for animation (move a few pixels, maybe change alpha). With hundreds on screen, this gets somewhat slow.
Would it be advisable to cache the circles as bitmaps? Would it be better to add them all to one array and have one interframe event handler run through the whole shebang, even if up to 90% aren't being animated in a specific frame?
Would it be faster to cache one circle as a bitmap and set all others to use the first shape's bitmapdata? Would it be even better to use a "CopyPixel" approach to erase and redraw ("blit") every circle at its new position every frame? I hear conflicting reports of the usefulness of CopyPixel on large mobile device canvases...
If the animation can be looped make a movie from the movie else try everything you can. Usually a CopyPixel approach is faster but I wouldn't expect much. I don't think it pays the bill either hence reduce the numbers of circles.
Related
I understand it's often faster to pre-render graphics to an off-screen canvas. Is this the case for a shape as simple as a circle? Would it make a significant difference for rendering 100 circles at a game-like framerate? 50 circles? 25?
To break this into two slightly different problems, there are two aspects to what you're asking:
1) is drawing a shape off-screen and putting it on-screen faster
2) is drawing a shape one time and copying it to 100 different places faster than drawing a shape 100 times
The answer to the first one is "it depends".
That's a technique known as "buffering" and it's not really about speed.
The goal of buffering an image is to remove jerkiness from it.
If you drew everything on-screen, then as you loop through all of your objects and draw them, they're updating in real-time.
In the NES-days, that was normal, because there wasn't much room in memory, or much power to do anything about it, and because programmers didn't know much better, with the limited instructions they had to work with.
But that's not really the way games do things, these days.
Typically, they call all of the draw updates for one frame, then they take that whole frame as a finished image, and paste that whole thing on the screen.
The GPU (and GL/DirectX) takes care of this, by default, in a process called "double-buffering".
It's a double-buffer, because there's room for the "in-progress" buffer used for the updates, as well as the buffer that holds the final image from the last frame, that's being read by the monitor.
At the end of the frame processing, the buffers will "swap". The newly full frame will be sent to the monitor and the old frame will be overwritten with the new image data from the other draw calls.
Now, in HTML5, there isn't really access to the frame-buffer, so we do it ourselves; make every draw call to an offscreen canvas. When all of the updates are finished (the image is stable), then copy and paste that whole image to the onscreen canvas.
There is a large speed-optimization in here, called "blitting", which basically copies over only the parts that have changed, and reuses the old image.
There's a lot more to it than that, and there are a lot of caveats, these days, because of all of the special-effects we add, but there it is.
The second part of your question has to do with a concept called "instancing".
Instancing is similar to blitting, but while blitting is about only redrawing what's changed, instancing is about drawing the exact same thing several times in different places.
Say you're painting a forest in Photoshop.
You've got two options:
Draw every tree from scratch.
Draw one tree, copy it, paste it all over the image.
The downside of the second one is that each "instance" of the image looks exactly the same.
If your "template" image changes colour or takes damage, then all instances of the image do, too.
Also, if you had 87 different tree variations for an 8000 tree forest, making instances of them all would still be very fast, but it would take more memory, because you now need to save 87x more images than when it was just one tree, to reference on every draw call.
The upside is that it's still much, much faster.
To answer your specific question about X circles, versus instancing 1 circle:
Yes, it's still going to be a lot faster.
What a "lot" means, though, will change based on a lot of different things, because now you're talking about browsers on PCs.
How strong is the PC?
How good is the videocard?
How large is the canvas in software-pixels (not CSS pixels)?
How large are the circles? Do they have alpha-blending?
Is this written in WebGL or software?
If software is the canvas compositing in hardware mode?
For a typical PC, you should still be able to hit 60fps in Chrome, drawing 20 circles, I think (depending on what you're doing to them... ...just drawing them onscreen, every frame is simple), so in this case, the instances are still a "lot" faster, but it's not going to matter, because you've already passed the performance-ceiling of Canvas.
I don't know that the same would be true on phones/tablets, or battery-powered laptops/netbooks, though.
Yes, transferring from an offscreen canvas is faster than even primitive drawings like an arc-circle.
That's because the GPU just copies the pixels from the offscreen canvas (not much CPU effort required)
I'm working on a kind of 2d platform ARPG in Flashpunk, and have run into somewhat of a conundrum.
Ranged weapons are no big deal. They are a flat image that I move and rotate to emulate the feel of throwing or firing a ranged weapon. Melee weapons are a bit more of a pain, as I want to use a sprite map for different weapon animations.
The problem I run into is that I have to manually adjust the hitbox for every frame of the melee weapon. I would like to use the Pixelmask function included with Flashpunk, but it does not seem to work with Spritemap. Is there a way to force it to work, or a way to convert the current frame of the Spritemap into an Image so I can apply a Pixelmask?
It's a bit hacky, but what you could do is create a Vector of images separate from the animation itself, with indices equal to that of the corresponding animation, and create the pixelmask from there. If that ends up being too slow (dynamically allocated memory being slower than reusing preallocated), you could load the images, create pixelmasks from them, and push the pixelmasks to a vector instead. From there, all you would need to do is switch to the correct pixelmask during the attack animation.
I am starting to get a grasp of the HTML canvas and I wanted to know if it is encouraged to use optimization techniques. In games for example, is it encouraged to use bounding boxes and only redraw the portion of the screen that needs redrawing, or do people just blindly redraw everything. I ask this b/c I am creating a new engine for canvas and imposing bounding boxes complicates things greatly (ie. the user no longer has the freedom to quickly draw things to the stage).
Absolutely, it's almost always better to draw only what has changed on the screen at any one time. Attempting to draw everything causes unnecessary rasterisation of the images being drawn into one output image, when it's not even going to change on the screen.
In a small game I made a year ago, I was drawing a 2D array of tiles on the screen and getting around 15 frames per second. When I changed it to draw only the tiles visible on the screen, it was an amazing improvement. It will improve in this circumstance too.
So created a Sprite to which I add other Sprites which are game tiles. Each tile is 60 x 60 px big. In result I've the Sprite with about 200 childs (those tiles).
When I try to startDrag() the container sprite the lag when moving it is very noticeable..
Is there a way like to join the tile Sprites so the container would have only 1 child Sprite instead of 200? Because it lags so much probably cause it needs to move (change the x and y) all those 200 tiles.. Am I correct?
In this case I can't use the cacheAsBitmap property, cause user can zoom in or zoom out the map..
Glycerine & Aurel do touch the crux of the real solutions. However I'd like to add.
You are correct by the way, when you said it has to manage so many sprite locations when you move the container around. CacheAsBitmap sure does does tackle this to great extent but the real solution is blitting. Try this link for that :
http://www.adobe.com/devnet/flash/articles/blitting_mc.html
It doesn't matter if a user zoom or something of that sort is required cause you can always switch between bitmap data & the original vector sprites. Your problem arises in moving.managing lotsa sprites, so just before doing that use optimizations, after that let them be back to their selves.
I've had the same issue before. Is it possible to 'join' them together - in a sense.
When you add your 200 sprites onto a screen - I assume you put them all into another parent sprite.
A this point - you will take a snapshot, or a screenshot - or a photographic replica (whatever you want to call it) of all the sprites and write the image (bitmapData) to a parent sprite. At this point. delete/remove/hide/nullify the original sprites and you'll be left with a sprite containing bitmap data.
One big image to move about and zooming and the like is no bother.
If you need code - ask. It's time consuming code so you tell me first then I'll write it :P
Hm, joining them would actually be quite hard... You would need to get the graphics, the code and all and put that into the parent...
I don't think that is the problem - you should do something else... In this case, I think that by "tiles" you mean that the parent would be a tile map, correct? So, you probably have a 2-dimensional array (array of arrays) with tile types - instead of parsing that array at initialization, creating A LOT of Sprites, try re-parsing it in each frame (it is faster), but add only the Sprites that are possible to see. That is - their X position (after adding the zoom and camera X) is greater than -sprite.width, where the height is also scaled by the zoom, and lesser than stage.width + sprite.width (again, width after zoom). Same goes for Y, only with the height attributes.
I'm creating a space game in actionscript/flex 3 (flash). The world is infinitely big, because there are no maps. For this to work I need to dynamically (programatically) render the background, which has to look like open space.
To make the world feel real and to make certain places look different than others, I must be able to add filters such as colour differences and maybe even a misty kind of transformation - these would then be randomly added and changed.
The player is able to "scroll" the "map" by flying to the sides of the screen, so that a certain part of the world is only visible at once but the player is able to go anywhere. The scrolling works by moving all objects except for the player in the opposite direction, making it look like it was the player that moved into that direction. The background also needs to be moved, but has to be different on the new discovered terrain (dynamically created).
Now my question is how I would do something like this, what kind of things do I need to use and how do I implement them? Performance also needs to be taken into account, as many more objects will be in the game.
You should only have views for objects that are within the visible area. You might want to use a quad tree for that.
The background should maybe be composed of a set of tiles, that you can repeat more or less randomly (do you really need a background, actually? wouldn't having some particles be enough?). Use the same technique here you use for the objects.
So in the end, you wind up having a model for objects and tiles or particles (that you would generate in the beginning). This way, you will only add a few floats (you can achieve additional performance, if you do not calculate positions of objects, that are FAR away. The quad tree should help you with that, but I think this shouldn't be necessary) If an object having a view leaves the stage, free the view, and use the quad tree to check, if new objects appear.
If you use a lot of objects/particles, consider using an object pool. If objects only move, and are not rotated/scaled, consider using DisplayObject::cacheAsBitmap.