Jump to content

How to render tiles only when needed


PhasedEvolution
 Share

Recommended Posts

Hello. I am using phaser and its isometric plugin. I have generated a tilemap using a for loop in order to render a single tile sprite multiple times. However when the map is too big the performace gets affected dramatically. I would like to know how can I render the tiles only when the camera that follows my character moves and goes another areas. Can someone explain the process of pooling? What commands should I use? Do I need to set a rect.world bound or something similar that matches my camera and use outOfBounds.kill? I have tryed lots and nothing seems to work. Thank you

 

Link to comment
Share on other sites

Pooling is useful if you keep creating/killing the same Sprites/Objects. You don't want to do 'new Object' while your game is running, because that'll slow things down.
You don't want to kill (remove) an object while running, because that may trigger garbage collection, and that'll really slow things down. The 'trick' is just to prespawn everything, and get an instance from that array (see example).

That is not a solution for your performance problem though. You indeed need to render only your viewport. So figure out which tiles are in your view, and render them to a RenderTexture/TileMap/BitmapData (whatever). There are no shortcuts here. Basically you're implementing a camera yourself.

 

Link to comment
Share on other sites

1 hour ago, Milton said:

Pooling is useful if you keep creating/killing the same Sprites/Objects. You don't want to do 'new Object' while your game is running, because that'll slow things down.
You don't want to kill (remove) an object while running, because that may trigger garbage collection, and that'll really slow things down. The 'trick' is just to prespawn everything, and get an instance from that array (see example).

That is not a solution for your performance problem though. You indeed need to render only your viewport. So figure out which tiles are in your view, and render them to a RenderTexture/TileMap/BitmapData (whatever). There are no shortcuts here. Basically you're implementing a camera yourself.

 

Thank you once again Milton :) I will try it. By any case do you know of a similar case / post where the matter is also rendering only the viewport?

 

Link to comment
Share on other sites

There are many, google 'draw tiles in view' or something similar.
But it is not very hard. Just divide your view width/height by your tile width/height so you know how many tiles you need.
Use your player position as offset.

So let's say you have a view of 320 x 480, and tiles 32 x 32. You would need at least 10 x 15 tiles (probably 11 x 16).
If the player is at (0, 0) (assuming center of the screen, top left anchor, and no Z coordinate) you would need to draw from 8 tiles above you, and 5 tiles to the left.
If (0, 0) is in the middle of the map, and the map is 100 by a 100 tiles, you should loop from map[45, 42] to map[55, 58] (approximately).
When the player is at (100, 100) you need a tile offset of 100 / 32 is 3 tiles, etc...

This example doesn't really take Isometric into account, but the flow is similar. You will have to convert 2d to Iso coordinates.

Link to comment
Share on other sites

4 hours ago, Milton said:

There are many, google 'draw tiles in view' or something similar.
But it is not very hard. Just divide your view width/height by your tile width/height so you know how many tiles you need.
Use your player position as offset.

So let's say you have a view of 320 x 480, and tiles 32 x 32. You would need at least 10 x 15 tiles (probably 11 x 16).
If the player is at (0, 0) (assuming center of the screen, top left anchor, and no Z coordinate) you would need to draw from 8 tiles above you, and 5 tiles to the left.
If (0, 0) is in the middle of the map, and the map is 100 by a 100 tiles, you should loop from map[45, 42] to map[55, 58] (approximately).
When the player is at (100, 100) you need a tile offset of 100 / 32 is 3 tiles, etc...

This example doesn't really take Isometric into account, but the flow is similar. You will have to convert 2d to Iso coordinates.

I think I understood the ideia. Will try it. What is the difference between doing this and enabling autoCull in a sprite. Won't that disable the render of all those sprites outside the Phaser.camera view?

Link to comment
Share on other sites

Rendering Sprites is the problem. You should only render 1 object. If you have several layers it's quite possible to have 500 tiles a frame. The only way to handle this is to make sure the GPU makes as little calls as possible. You can do this by either pre-rendering all your sprites to a single texture (bitmap), or uploading all your Tiles to the GPU, and then it doesn't matter how many tiles you display, because the GPU can do this in 1 draw. So you either use RenderTexture/BitmapData, or TileMap, respectively.
If you're just going with drawing 500 sprites, it's going to be slow.

Link to comment
Share on other sites

20 hours ago, Milton said:

Rendering Sprites is the problem. You should only render 1 object. If you have several layers it's quite possible to have 500 tiles a frame. The only way to handle this is to make sure the GPU makes as little calls as possible. You can do this by either pre-rendering all your sprites to a single texture (bitmap), or uploading all your Tiles to the GPU, and then it doesn't matter how many tiles you display, because the GPU can do this in 1 draw. So you either use RenderTexture/BitmapData, or TileMap, respectively.
If you're just going with drawing 500 sprites, it's going to be slow.

Well I opted for a bitmap. I think I am not working with BitMapaData the correct way... because I always get a black screen.
Here is my code for generating the "tiled map":
 

var bmd = game.add.bitmapData(32*20,32*20); 

spawnBasicTiles: function (half_tile_width,half_tile_height,size_x,size_y) {  
        var tile;
        for (var xx = 0; xx < size_x; xx += half_tile_width) {
            for (var yy = 0; yy < size_y; yy += half_tile_height) {
                tile = game.add.isoSprite(xx,yy,bmd);
            }
        }
 }

 this.spawnBasicTiles(basic_half_tile_width,basic_half_tile_height,size_x,size_y);

The code used to work when I just spawned the tiles individually ( and had that horrible performance problem... ). Can you please tell me what I am doing wrong? Am I supposed to push every tile to an array or something? Kinda stuck in this... Thank you once again

Link to comment
Share on other sites

O my lord. I'm out of my depth now. I don't actually use Phaser, so this is guesswork.

Looking at the API, Phaser wants a 'bmd.draw(isoSprite, xx, yy, width, height)'.
Do that in the for loops, and add bmd to the DisplayList.

'tile =' does nothing. You're creating a Bitmap (an empty Canvas), so paste your Sprites onto it, and display the Bitmap.
If you want, create a chat option somewhere, and maybe I can help you out.

Link to comment
Share on other sites

On 03/09/2016 at 3:30 PM, Milton said:

O my lord. I'm out of my depth now. I don't actually use Phaser, so this is guesswork.

Looking at the API, Phaser wants a 'bmd.draw(isoSprite, xx, yy, width, height)'.
Do that in the for loops, and add bmd to the DisplayList.

'tile =' does nothing. You're creating a Bitmap (an empty Canvas), so paste your Sprites onto it, and display the Bitmap.
If you want, create a chat option somewhere, and maybe I can help you out.

I was able to generate a huge map. I think a understood the concept. Now it spends more time just sending the information to the GPU before displaying it right? Instead of generating a single sprite lots of times it generates  a "container" of sprites at once. Even when I create huge maps I get 60 fps. Do you think I still have to implement a way of only displaying only what the viewport contains or is that not needed anymore?That still makes me a little bit confused. Anyway, I have to thank you a lot for the help until now. :) Thanks

Link to comment
Share on other sites

This is interesting, since you have chosen the slowest solution. TileMap would be fastest, then RenderTexture.
Never bother with optimization as long as you don't need it. Do some tests on slow devices, and only then...

It would be interesting to see a demo of the isometric plugin with a big map that actually performs at 60fps. This question keeps coming back, and no one seems to have done anything about it.

Link to comment
Share on other sites

1 hour ago, Milton said:

This is interesting, since you have chosen the slowest solution. TileMap would be fastest, then RenderTexture.
Never bother with optimization as long as you don't need it. Do some tests on slow devices, and only then...

It would be interesting to see a demo of the isometric plugin with a big map that actually performs at 60fps. This question keeps coming back, and no one seems to have done anything about it.

Yeah,It is good enough for me at least for now... I hope you don't mind my curiosity, but have you made any games of these type, not phaser only but with any game engine? 

Link to comment
Share on other sites

A long time ago in a galaxy far, far away....
That means C64/Amiga days.
Back then, 'real' 3D was not an option. Now I would just use Three.js to do Isometric. You'll find out what a headache depth-sorting is if you fake it with 2D.


I don't really use engines, just the hardware abstraction most frameworks offer. Phaser is excellent, but too integrated (tightly coupled) for my liking (I believe Lazer fixes that). And then, these days I prefer Haxe/OpenFL, which is very similar to Phaser, but also does native desktop/mobile.

Link to comment
Share on other sites

1 hour ago, Milton said:

A long time ago in a galaxy far, far away....
That means C64/Amiga days.
Back then, 'real' 3D was not an option. Now I would just use Three.js to do Isometric. You'll find out what a headache depth-sorting is if you fake it with 2D.


I don't really use engines, just the hardware abstraction most frameworks offer. Phaser is excellent, but too integrated (tightly coupled) for my liking (I believe Lazer fixes that). And then, these days I prefer Haxe/OpenFL, which is very similar to Phaser, but also does native desktop/mobile.

Wow ... That is simply and honestly really awesome... Do you think that using three.js for isometric brings advantages in relation of using phaser along with its isometric plugin then?

Link to comment
Share on other sites

11 hours ago, Milton said:

O, no doubt about it. Look at this thread for example.

Well I saw the possibilites and got really amazed. I searched for other game engines like unity. I just wanted to discover the possibilites. I am quite new to this and have a lot to learn. For now I will mantain to phaser and I think I will later search in a more profound way for other game engines.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...