• 12
• 10
• 10
• 13
• 10

# Does Anyone Get Any Flicker Effect Using Vectors for Rendering Objects? (OpenGL C++)

This topic is 3211 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm using a std::vector structure to represent particles or projectiles the user shoots out and if a projectile dies or gets removed from the list it seems like the particles flicker a bit now and then from a projectile dieing or spawning. Here is my code: mp_Projectile is the Vector structure

if(mp_Projectile.size() != 0){

for(int i = 0; i<mp_Projectile.size(); i++)
{

if(mp_Projectile.empty())
{
break;
}

if(mp_Projectile.at(i).fLife < 0.0)
{

mp_Projectile.at(i).fAlive = false;

mp_Projectile.erase(mp_Projectile.begin()+i);
NumberOfProjectiles--;
break;
}else{

if(!Paused)
{
mp_Projectile.at(i).fPosition.m_fX +=  90.0 * DeltaTime;
mp_Projectile.at(i).fLife -= 8.0 * DeltaTime;
}

//Render Laser!
if(!mp_Projectile.empty() &&  NumberOfProjectiles > 0)
mp_Board.DrawBillboard(mp_Projectile.at(i).fPosition, 0.5, texture[14].texID, false, mp_Projectile.at(i).fLife);

if(!Paused)
{
bool breakLaserLoop = false;

for(int v = 0; v<carSys.ReturnNumberOfCars(); v++)
{

if(carSys.ReturnLane(v) ==  mp_Projectile.at(i).fLane &&
mp_Projectile.at(i).fPosition.m_fX >= carSys.ReturnX(v)-3 &&  NumberOfProjectiles > 0)
{

mp_Projectile.at(i).fAlive = false;
carSys.KillCar(v);
mp_Projectile.erase(mp_Projectile.begin()+i);
NumberOfProjectiles--;
breakLaserLoop = true;
break;

if(breakLaserLoop) break;
}

}
}

}

}
}


I'm wondering how I can get rid of the flicker effect I'm getting on my projectiles if someone can please tell me a tip. It's not a bad flicker, but it happens a little. Thanks, Ajm.

##### Share on other sites
that's probably c'se you erase elements inside the vector at any time.
erasing is 'slow' and may cause some the flickering.
better would be something like this :
Quote:
 vector temp;for_each_projectile{if (live>0) {Draw();update();temp.push_back(current);}}//totally clear up original vector, assign temp vector to original vector;

##### Share on other sites
Also, blending modes mean a lot. If you aren't sorting your particles, then alpha blending will cause the particles to flicker when they are in the wrong drawing order.

##### Share on other sites
hm

first up, avoid calling fuctions in the test expression of your for loop, get the size of the vector into a temporary variable, and use the variable in the comparison in the for loop.

int size = m_array.size();
for(int i = 0; i < size; i++);

secondly, dont delete elements from the vector. you can use the fLife variable to determine whether a particle is "alive" or not, if its not alive, dont render it. and you can reuse "dead" particles to make new "live" ones when you need to. a little bit of logic and you could even sort your "live" particles to the front of the list (again, without actually altering the structure of the vector itself).

if your going to be using a lot of tests on this fLife variable, it might be a good idea to switch it to be an integer measure of milliseconds (rather than a float measure of seconds). floating point compares can be costly, and inaccurate.

typically, particle systems are statically allocated, they get given a buffer of size N particles, and thats it. if they need more than N particles, the system starts killing the oldest particles to create new ones. have a look at some sliding window algorithms too.

also, use iterators.

have fun

##### Share on other sites
Here's the code thrown through the VS autoformatter:

if(mp_Projectile.size() != 0){	for(int i = 0; i<mp_Projectile.size(); i++)	{		if(mp_Projectile.empty())		{			break;		}		if(mp_Projectile.at(i).fLife < 0.0)			{			mp_Projectile.at(i).fAlive = false;			mp_Projectile.erase(mp_Projectile.begin()+i);			NumberOfProjectiles--;			break;		}else{			if(!Paused)			{				mp_Projectile.at(i).fPosition.m_fX +=  90.0 * DeltaTime;				mp_Projectile.at(i).fLife -= 8.0 * DeltaTime;			}			//Render Laser!			if(!mp_Projectile.empty() &&  NumberOfProjectiles > 0) 				mp_Board.DrawBillboard(mp_Projectile.at(i).fPosition, 0.5, texture[14].texID, false, mp_Projectile.at(i).fLife);			if(!Paused)			{				bool breakLaserLoop = false;				for(int v = 0; v<carSys.ReturnNumberOfCars(); v++)				{					if(carSys.ReturnLane(v) ==  mp_Projectile.at(i).fLane && 						mp_Projectile.at(i).fPosition.m_fX >= carSys.ReturnX(v)-3 &&  NumberOfProjectiles > 0)					{						mp_Projectile.at(i).fAlive = false;						carSys.KillCar(v);						mp_Projectile.erase(mp_Projectile.begin()+i);						NumberOfProjectiles--;						breakLaserLoop = true;						break;						if(breakLaserLoop) break;					}				}			}		}		}}

Pro tip: Proper indentation is your friend!

##### Share on other sites
if(mp_Projectile.size() != 0){	for(int i = 0; i<mp_Projectile.size(); i++)	{		if(mp_Projectile.empty())		{			break;		}

All the code highlighted in red will never get called. If .empty() == true, then .size() == 0. This means that the loop will check if 0 (i) < 0 (size) -- and since it isn't, the loop won't occur in the first place. This code can be deleted.
		if(mp_Projectile.at(i).fLife < 0.0)			{			mp_Projectile.at(i).fAlive = false;			mp_Projectile.erase(mp_Projectile.begin()+i);			NumberOfProjectiles--;			break;

Break means the loop ends. The loop that your entire paste is in. Consider what happens when you erase the first element out of, say, 100. What happens to the other 99 projectiles that you haven't yet looped over? Do they get looped over? No. They don't get rendered for that frame. They'll get rendered during the next frame, but not this one. It's a lot easier to notice this kind of problem now that we've fixed the indentation.

This is probably causing your flicker.

You can go to the next loop iteration immediately by using continue instead of break, but if the only thing you do is replace it, you'll still be skipping an element -- since projectile i+1 becomes the new projectile i, and the loop will execute ++i before comming across any of this code again -- meaning the element after the one you just erased will end up being i-1.

				for(int v = 0; v<carSys.ReturnNumberOfCars(); v++)				{					if(carSys.ReturnLane(v) ==  mp_Projectile.at(i).fLane && 						mp_Projectile.at(i).fPosition.m_fX >= carSys.ReturnX(v)-3 &&  NumberOfProjectiles > 0)					{						mp_Projectile.at(i).fAlive = false;						carSys.KillCar(v);						mp_Projectile.erase(mp_Projectile.begin()+i);						NumberOfProjectiles--;						breakLaserLoop = true;						break;						if(breakLaserLoop) break;					}

Again, this is more code that will never be run. The earlier break; on the line immediately above, ends the loop immediately. And since this is the only place where you use breakLaserLoop's value, you can get rid of all the code refering to it as well. Either that or you can move it outside of the car loop so that it actually does break out of the laser loop like you seem to want to -- but remember, that will completely end the loop (and thus cause flicker)

It's good to get rid of 'dead code' like this -- it hurts readability and makes it harder to see what code could be the cause of problems.

[Edited by - MaulingMonkey on June 4, 2009 8:01:43 PM]