-=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- (c) WidthPadding Industries 1987 0|698|0 -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=-
Socoder -> Cobra -> poor performing tile map render

Posted : Tuesday, 12 July 2011, 14:12
I thought I would tidy up and optimise my tile map render code a little but i got some weird effect.

The newer code is about 20 fps slower than the old, and deathly slow when debugmode=1.

can someone explain why because i certainly cant?

this is the original code

and this is the newer, as i thought better code

Posted : Tuesday, 12 July 2011, 14:24
one problem is it is drawing the debug text every cell.

removed that and it was closer but still slower by about 9-10 milliseconds
Posted : Tuesday, 12 July 2011, 14:43
I don't know of any intricacies Cobra has in this kind of thing, as I don't use it myself, but I don't see anything glaringly obviously wrong here. The only thing I can thing is all those nested for loops, but those seem rather necessary.

Have you tried putting a timer on every stage of the code to see which bits are slowest, rather than just timing the whole thing?

A mushroom a day keeps the doctor away...

Keep It Simple, Shroom!
Posted : Tuesday, 12 July 2011, 14:47
Obvious shortcut..

Find your 4 screen limits..
Left, Right, Top, Bottom..
Then instead of doing 0-1024x0-1024, do only (left of screen to right of screen)x(top of screen to bottom of screen)

|edit| do an extra 1 block either side, too, to account for scrolling! |edit|

''Load, Next List!''
Posted : Wednesday, 13 July 2011, 09:55
oh i get you, no need to render unseen tiles.

and it will be 8 screen limits as you can walk diagonally, im sure I can come up with a formula to make it do a radius of 1.5 screens

then work it for the most optimal.

strangely the nested loops one is quicker?!?!???!!!??!?!
Posted : Wednesday, 13 July 2011, 11:19
The simple problem is that you are performing too much drawing. You are iterating over the whole screen, multiple times, performing lots of calls.

So my first suggestion is to use a hardware accelerated graphics library, either with Cobra or something else. A 10 year old graphics card can trivially draw 1000 2D images to the screen, so there is no reason why all these calls should be slowing you down.

But if that is not attractive, here is an alternative 'dirty rectangle' approach. You split the screen into a series of off-screen buffers or images. This means the screen is made up of 4, 16, or more 'big tiles'.

You render your world map to these big tiles, and then render the big tiles to the screen. The advantage is that if the contents of a big tile has not changed, then you don't draw to redraw it. If it's contents does change, then your only redrawing a quarter (or less) of the screen.

Now lets say you scroll the world to the left, how is that handled? First move all big tiles to the left, and now you've correctly scrolled about 80% of the map. You then add new big tiles on to the right hand side, and redraw the new section of the world to those new big tiles.

Any big tile that are no longer visible can be removed. You could also cache these, and re-use them later for your new tiles that scroll on to the screen.

If a tile is animated then you will have to clear a section of the big-tiles, and redraw that whole section. What size should be based on if the tile overlaps other tiles, and if it's surrounding tiles overlap more tiles. All of the tiles affected will need to be cleared, and then redrawn.

If a tile does not overlap a surrounding tile, then it only needs to clear and redraw it's self.

Other game elements, like characters and background, can just be rendered before and after the big tiles are drawn to the screen. They don't need to be rendered to the big-tiles.

That technique should reduce the number of drawing calls from around 1000 to just 4 or 16 (depending on how many big tiles you have). That should make it _much_ faster, but incorrect code could reduce in sections not updating correctly.
Posted : Thursday, 14 July 2011, 07:18
That sounds like a perfect solution. I guess I had thought of a reasonably efficient way to do it and stuck with it.

if I understand you correctly you should:

  • render the 4 layers of the map to image buffers
  • render parts of these to the screen so it fits
  • update them on map changes, like tile changes etc

    If I'm to redesign my map engine, for probably the three hundredth time, I would like to get the theory down first, is there any recommended reading somewhere?

    Stuff I have found on the internet points to the same way I do it now
  • Posted : Thursday, 14 July 2011, 07:31
    I just went over my code this is how it works

    the game engine tracks where the player is.

    it then calls the map drawing function with parameters, x,y where to draw it, width and height, it will then draw the part of the map that's visible.

    Posted : Thursday, 14 July 2011, 10:03
    I'm struggling to find any decent theory on this subject. What I can find is code for other languages that do it the same way I do.

    im looking through amazon right now for some physical works but still bobbins
    Posted : Thursday, 14 July 2011, 10:04
    It would take some changes, but using Sprites instead of Images would solve most of this for you.

    Just create an initial (w / sprite_width) * (h / sprite_height) set of sprites, plus one extra row and column for scrolling the screen, and just simply use PositionSprite and SpriteFrame.

    blog | work | code | more code
    Posted : Thursday, 14 July 2011, 10:15
    I tried that before and it was slower. I have learnt a lot since then though

    I think I will leave the renderer as it is for now. Its not slow but if its not done correctly it will annoy me.

    Hoboben, do you know a way to disable vsync for cobra2d?
    Posted : Thursday, 14 July 2011, 10:25
    Fairly certain you can just use VSync(0)

    It says it's Cobra3D in the docs, but I've used it with Cobra2D before.

    blog | work | code | more code