Recently I've been trying to develop a 2D Terraria style game using SFML and c++. Everything has been working perfectly expect for the random terrain generation. Currently, I have a for loop that assigns the position and texture to an array of sprites (ex:int grass[150]) which are then drawn to the screen using a for loop. The terrain generates and looks okay but, the multiple arrays of sprites are being drawn to the screen every time my program loops. This is causing some serious performance issues, because currently around 1400 sprites (only a fraction of number of the amount I want when the game is finished) are being drawn every time my program loops.
最近我一直在尝试使用SFML和c ++开发2D Terraria风格的游戏。一切都在为随机地形生成完全期待。目前,我有一个for循环,它将位置和纹理分配给一个精灵数组(例如:int grass [150]),然后使用for循环将其绘制到屏幕上。地形生成并且看起来没问题但是,每次我的程序循环时,都会将多个精灵数组绘制到屏幕上。这导致了一些严重的性能问题,因为每当我的程序循环时,目前大约有1400个精灵(只有游戏结束时我想要的数量的一小部分)。
So, my question to you is how do I make my terrain generate efficiently? Is there a way to only clear a portion of the sprites on the screen at a time or only clear sprite when it is modified? Is there a better way to create terrain other than using multiple arrays of sprites?
所以,我的问题是如何有效地生成地形?有没有办法一次只清除屏幕上的一部分精灵,或者仅在修改时清除精灵?除了使用多个sprite数组之外,还有更好的方法来创建地形吗?
2 个解决方案
#1
1
I think there's a few confusions in your question, but here are some points you should look into :
我认为你的问题有一些混淆,但这里有一些你应该研究的观点:
-
As others pointed out, only draw the terrain tiles that are actually on screen. You do not need to draw the whole world at each frame.
正如其他人指出的那样,只绘制实际在屏幕上的地形图块。你不需要在每一帧画出整个世界。
-
If you world dosen't change (or doesn't change much except by player's action), you could try to render it once and for all and cache this rendering into a texture that you would display (with the good offset corresponding to the in-game position of the player). No more looping through tiles and arrays. Take a look at
RenderTexture
. Of course if your player can dig or do whatever changes the world, you can't use this texture forever, but it may be a good idea to do it after every change, as changes don't happen so often compared to rendering, so I guess you could still benefit from this.如果世界不会改变(或者除了玩家的动作之外没有太大变化),你可以尝试一劳永逸地渲染它并将这个渲染缓存到你将要显示的纹理中(具有与in相对应的良好偏移) - 玩家的游戏位置)。不再循环遍历切片和数组。看看RenderTexture。当然,如果你的玩家可以挖掘或做任何改变世界的事情,你就不能永远使用这个纹理,但是在每次改变之后做这件事可能是个好主意,因为与渲染相比,改变不会经常发生,所以我想你仍然可以从中受益。
-
You mentionned an array of sprites. I hope you don't have an instance of a
sf::Sprite
for every single grass tile, every single rock tile etc. ? In case you do, only have one sprite of each tile, and use it to draw every tiles of its type just by changing its coordinates and drawing it to your render target. But I may have misunderstood your question.你提到了一系列的精灵。我希望你没有每个草砖,每块岩石等的sf :: Sprite实例?如果你这样做,每个瓷砖只有一个精灵,只需改变其坐标并将其绘制到渲染目标,就可以用它来绘制每种瓷砖。但我可能误解了你的问题。
#2
3
Try drawing less tiles, there's no need to draw every tile in the world as the majority of them aren't visible.
尝试绘制更少的瓷砖,不需要绘制世界上的每个瓷砖,因为大多数瓷砖都不可见。
Draw only the amount of tiles that can be visible on the screen at one time plus a bit more, for example if the screen can only fit 7x4 tiles draw around 9x6.
只绘制一次可以在屏幕上看到的瓷砖数量加一点,例如,如果屏幕只能适合7x4瓷砖绘制9x6左右。
That will help reduce the time spent trying to draw non-visible tiles.
这将有助于减少尝试绘制不可见的瓷砖所花费的时间。
#1
1
I think there's a few confusions in your question, but here are some points you should look into :
我认为你的问题有一些混淆,但这里有一些你应该研究的观点:
-
As others pointed out, only draw the terrain tiles that are actually on screen. You do not need to draw the whole world at each frame.
正如其他人指出的那样,只绘制实际在屏幕上的地形图块。你不需要在每一帧画出整个世界。
-
If you world dosen't change (or doesn't change much except by player's action), you could try to render it once and for all and cache this rendering into a texture that you would display (with the good offset corresponding to the in-game position of the player). No more looping through tiles and arrays. Take a look at
RenderTexture
. Of course if your player can dig or do whatever changes the world, you can't use this texture forever, but it may be a good idea to do it after every change, as changes don't happen so often compared to rendering, so I guess you could still benefit from this.如果世界不会改变(或者除了玩家的动作之外没有太大变化),你可以尝试一劳永逸地渲染它并将这个渲染缓存到你将要显示的纹理中(具有与in相对应的良好偏移) - 玩家的游戏位置)。不再循环遍历切片和数组。看看RenderTexture。当然,如果你的玩家可以挖掘或做任何改变世界的事情,你就不能永远使用这个纹理,但是在每次改变之后做这件事可能是个好主意,因为与渲染相比,改变不会经常发生,所以我想你仍然可以从中受益。
-
You mentionned an array of sprites. I hope you don't have an instance of a
sf::Sprite
for every single grass tile, every single rock tile etc. ? In case you do, only have one sprite of each tile, and use it to draw every tiles of its type just by changing its coordinates and drawing it to your render target. But I may have misunderstood your question.你提到了一系列的精灵。我希望你没有每个草砖,每块岩石等的sf :: Sprite实例?如果你这样做,每个瓷砖只有一个精灵,只需改变其坐标并将其绘制到渲染目标,就可以用它来绘制每种瓷砖。但我可能误解了你的问题。
#2
3
Try drawing less tiles, there's no need to draw every tile in the world as the majority of them aren't visible.
尝试绘制更少的瓷砖,不需要绘制世界上的每个瓷砖,因为大多数瓷砖都不可见。
Draw only the amount of tiles that can be visible on the screen at one time plus a bit more, for example if the screen can only fit 7x4 tiles draw around 9x6.
只绘制一次可以在屏幕上看到的瓷砖数量加一点,例如,如果屏幕只能适合7x4瓷砖绘制9x6左右。
That will help reduce the time spent trying to draw non-visible tiles.
这将有助于减少尝试绘制不可见的瓷砖所花费的时间。