Performance trouble when rendering (2d)

Started by
10 comments, last by stevenmarky 13 years, 6 months ago
I've noticed in my small game that I get very low fps very quickly when multiple objects are on the screen.

The two objects that hogs performance are enemies and shots fired by either the player or the enemy.

After looping through a vector and moving all enemies I loop the vector again and renders each enemy.

Collapse
void renderEnemy(){
for (int i = 0;i<enemyVector.size();i++){
enemyVector.drawEnemy();
}
};

Collapse
void enemy::drawEnemy(){
const string playerFilename = "SmallMine.tif";
const int DROPS_X_FRAME_COUNT = 1;
const int DROPS_Y_FRAME_COUNT = 1;
VGCImage player = VGCDisplay::openImage(
playerFilename,
DROPS_X_FRAME_COUNT,
DROPS_Y_FRAME_COUNT
);
const VGCVector frameIndex = VGCVector(0, 0);
const VGCVector position = VGCVector(xPos, yPos);
const VGCAdjustment adjustment = VGCAdjustment(0.0, 0.0);
VGCDisplay::renderImage(player, frameIndex, position, adjustment);
VGCDisplay::closeImage(player);

};

As you can see drawEnemy gets called quite a lot which slows down my game but I'm not sure on how to avoid this function getting called so many times.

Advertisement
void enemy::drawEnemy(){const string playerFilename       = "SmallMine.tif";const int    DROPS_X_FRAME_COUNT = 1;const int    DROPS_Y_FRAME_COUNT = 1;VGCImage     player               = VGCDisplay::openImage(    playerFilename,    DROPS_X_FRAME_COUNT,    DROPS_Y_FRAME_COUNT);const VGCVector     frameIndex = VGCVector(0, 0);const VGCVector     position   = VGCVector(xPos, yPos);const VGCAdjustment adjustment = VGCAdjustment(0.0, 0.0);VGCDisplay::renderImage(player, frameIndex, position, adjustment);VGCDisplay::closeImage(player);};
What does VGCDisplay::openImage do? If it actually opens an image from disk then of course your code will be slow. You want to keep images in memory if they are used often.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

That is exactly what it does, and it is what I want to avoid. I got no clue on how to proceeed at the moment and how to keep the picture in the memory.
You need to load the image in a different function and keep a copy of the image in memory. How are you loading the image? What API are you using?
Quote:Original post by Psilobe
That is exactly what it does, and it is what I want to avoid. I got no clue on how to proceeed at the moment and how to keep the picture in the memory.


Simple enough: You want to move the openImage out of drawEnemy and store the VGCImage it returns somewhere where drawEnemy can use it.

For example, we could turn it into a member variable, and use enemy's constructor and deconstructor to open/close it. This isn't all that great on it's own, but it is at least better:

class enemy {    VGCImage player;public:    enemy();    ~enemy();    ...};enemy::enemy() {    const string playerFilename = "SmallMine.tif";    const int DROPS_X_FRAME_COUNT = 1;    const int DROPS_Y_FRAME_COUNT = 1;    player = VGCDisplay::openImage(        playerFilename,        DROPS_X_FRAME_COUNT,        DROPS_Y_FRAME_COUNT    );}enemy::~enemy() {    VGCDisplay::closeImage(player)}void enemy::drawEnemy() {    const VGCVector frameIndex = VGCVector(0, 0);    const VGCVector position = VGCVector(xPos, yPos);    const VGCAdjustment adjustment = VGCAdjustment(0.0, 0.0);    VGCDisplay::renderImage(player, frameIndex, position, adjustment);}


A more efficient way would be to only load the image once for the entire program, rather than once per enemy. There are many different ways to do this:

- (ab)use the static keyword
- Have something else load the image, and then tell the enemies what to use by passing it a pointer or reference to the image
- Have something else load the image AND draw the enemies, having the enemy not care what images are used.

Experiment, and see what works well for you :). (And for future reference, wrap your code in [source] tags [/source] to make it nice and readable with indentation like above.)
Many thanks, I think I'm starting to get how it should be done.

But if I load the iamge with one isntance of enemy can other instances of enemy draw the image if the draw function then jsut takes their coordinates and use the render part of the code?

Or do I ahce to point to that specific instance which loaded the image?
Something like this is typically done statically.

-Add a static VGCImage variable to your enemy class.
-Add a static function to your enemy class that loads the image.
-call the static function when you are initializing things, such as the beginning of a level.

Just in case you aren't familiar with what static means, by declaring a variable static, it will be shared by all instances of the enemy class. This way, you only load the image once, and all enemies can access it.
I think I'm closing in on this but I still dont think I got the hang of using statics.

This is what I came up with but I get linker erro LNK2001.

error LNK2001: unresolved external symbol "protected: static class VGCImage enemy::player" (?player@enemy@@1VVGCImage@@A) enemy.obj

And also LNK1120 1 unresolved external.

And I has no clue as to what's wrong.


void enemy::initImage(){	const string playerFilename       = "SmallMine.tif";const int    DROPS_X_FRAME_COUNT = 1;const int    DROPS_Y_FRAME_COUNT = 1;	VGCImage     player               = VGCDisplay::openImage(	playerFilename, 	DROPS_X_FRAME_COUNT, 	DROPS_Y_FRAME_COUNT	);	};void enemy::closeImage(){VGCDisplay::closeImage(player);};void enemy::renderEnemy(){	const VGCVector     frameIndex = VGCVector(0, 0);const VGCVector     position   = VGCVector(xPos, yPos);const VGCAdjustment adjustment = VGCAdjustment(0.0, 0.0);VGCDisplay::renderImage(player, frameIndex, position, adjustment);};

And the header:
class enemy {       public:static void initImage();static void closeImage();void drawEnemy();void initEnemy();void moveEnemy();void updateEnemy();int getyPos();int getxCent();int getyCent();void renderEnemy();protected:	static VGCImage player;	int xPos;	int yPos;  };
You declared the static variable but you didn't define it. Read more here

I should note that using a static member variable only makes sense if you expect all 'enemies' to have the same image. Otherwise you would want a regular member variable and assign an image in, for example, the constructor.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

The problem with defining my static variable is taht if I do it like this:
VGCImage     enemy::player               = VGCDisplay::openImage(	playerFilename, 	DROPS_X_FRAME_COUNT, 	DROPS_Y_FRAME_COUNT	);


It says it cant find PlayerFilename and Drops_X... and Drops_Y...

This topic is closed to new replies.

Advertisement