[SOLVED] How to make drawing more efficient?

My problem is that my game is drawing a large game board of textured hexagons (50x67). Most of the time the board doesn’t change but it occasionally does.

So, following the directions of some posts I’ve made a sprite sheet of my hexagons and only change their textures when the board changes. This has reduced my draw calls down to 35, my GL Verts is 20622 and my frame rate has gone up to ~18fps.

This isn’t a problem for my game play but it is wasting resources (battery,CPU,GPU) so I was wondering if there is a way to improve this.

My guess would be something like creating a board image when it changes and then just blitting it instead of recreating it. Is there a way to do this in cocos2d-x? Layers perhaps?

Thanks for the help,
/Alan

Hi, try to use RenderTexture to render hexagons to texture. Display texture. After change redraw to texture again. With this you should have 60 fps :wink:

Hi dimon4eg,

Thanks, that’s exactly what I needed. I switched over to drawing into a texture and then init-ing a scene “board-surface” sprite with that texture and my FPS went up to 59.

/Alan

Cool! Now you can mark this as solved

@dimon4eg do you have code sample to show what you are describing here? much thanks!

Hi @kyle_bong2,

I’ve hobbled together a bit of my (experimental) code that I tried the procedure with. Thus you’ll have to fill this code out to get it to work properly but hopefully it will help you develop a working test faster.

There are three things you have to do:

  1. Create the RenderTexture and a sprite. You will draw to the RenderTexture and then add the RenderTexture to a sprite to position, scale etc. on the Scene.
  2. Draw your game-board-part sprites to the RenderTexture, this requires a begin (->beginWithClear(),etc) and end (->end()) calls surrounding the drawing of your sprites,
  3. Copying your RenderTexture to your sprite then position it etc. in your Scene.

You need to design your scene so that the sprites are grouped into groups where they tend to change (texture, position, opacity or other characteristic) at the same frequency as the other grouped items. For instance a game board that doesn’t change much can be drawn once into a texture (instead of every time the screen is re-rendered at your FPS rate). Then the texture only has to be copied (not redrawn) each frame.

NOTE: Looking at the sprite->visit() line and the documentation for Node::visit() it looks like you can create a Node:: tree starting with a Layer:: (a type of Node::), or something similar, and get it to render to the RenderTexture automatically rather than looping around through all your game-board sprites. i.e. do myLayer->visit() instead of sprite[0]->visit(), …, sprite[N]->visit().

So far I’ve got this working such that the per-frame redraw process is minimal but it still has a problem with what looks like a scaling issue (missing lines) which may be my setDesignResolutionSize/ResolutionPolicy … I just haven’t had time to figure this out yet.

Step1, Create the RenderTexture and enclosing Sprite:

    // Create a texture to hold the board.  We do this so we don't have to redraw the static board
    // every frame.
    _RenderedBoard = RenderTexture::create(_scrRect.size.width, _scrRect.size.height, Texture2D::PixelFormat::RGBA8888);
    // Also create a sprite so we can position the texture on the screen (and adjust it if need be).
    _BoardSprite=Sprite::create();
    _BoardSprite->setScaleY(-1.0); // To turn the rendered texture the right way up (it is normally upside-down)
    _BoardSprite->setPosition(_scrRect.origin);
    addChild(_BoardSprite,0);  // Add the Sprite representing the playing board to the Scene/Layer/etc.

Step2, Draw the playing board on the RenderTexture:

    // Now create our playing board texture...

    // Clear out texture to black
    _RenderedBoard->beginWithClear(0.0, 0.0, 0.0, 0.0);

    // Do all our drawing, of the board texture, with our other sprites 
    Sprite* sprite=Sprite::create();
    sprite->setSpriteFrame("name of sprite in sprite frame");
    sprite->setScale(_scale);
    // ... and set the location of the sprite on the texture.
    sprite->setVisible(true);
    sprite->setPosition(px, py);
    sprite->visit();  // This is the Node:: routine that visits the Node:: tree starting at 'sprite' in this case and draws each node.

    _RenderedBoard->end(); // This works with the beginWithClear() above and terminates the draw process.

Step3, Associate the RenderTexture(game board) with the sprite that positions it on the Scene:

    // Now we have to load the _BoardSprite with the already rendered background.
    _BoardSprite->initWithTexture(_RenderedBoard->getSprite()->getTexture());
    // Position the sprite on the scene...

Good luck, I hope this helps,
/Alan

1 Like