I'm working with OpenGL/Glut and trying to make a simple "rain" effect. I have a class for raindrops:
class Drop {
private:
int speed;
int posY;
int posX;
public:
Drop() { // constructor
speed = 5;
posY = 15;
posX = (rand() % 500);
}
void move() {
speed += 1;
posY += speed;
}
int getPosY() {
return posY;
}
int getPosX() {
return posX;
}
};
A list of Drop
s alongside a function to add Drop
s to the list.
list<Drop> listDrops;
void placeDrop() {
Drop d = Drop();
listDrops.push_back(d);
}
A function to redraw the OpenGL window:
void refreshDisplay() {
if (rand() % 5 == 1) {
placeDrop();
}
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5);
glBegin(GL_POINTS);
for (Drop a : listDrops) {
glColor3f(255,255,255); // white
glVertex2i(a.getPosX(),a.getPosY());
a.move();
}
glEnd();
glFlush();
glutSwapBuffers();
}
void repeater(int val) {
glutPostRedisplay();
glutTimerFunc(5, repeater, 0);
}
And of course my main and Glut init:
int main(int argc, char** argv) {
srand(time(NULL));
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(500, 500);
glutCreateWindow("Rain");
gluOrtho2D(0.0, 500.0, 500.0, 0.0);
glutDisplayFunc(refreshDisplay);
glutTimerFunc(0, repeater, 0);
glutMainLoop();
return 0;
}
All of the Drop
s are initialized properly, I can confirm by outputting their co-ordinates after creation. But they don't move at all. It's like Drop::move()
is being ignored.
If I instead initialize a global Drop aDrop
(just one), and get rid of the iterator over listDrops
in refreshDisplay()
and instead just have aDrop
drawn, it does move as expected.
You are calling move()
on a copy of each Drop
that is only scoped for one loop iteration
You can use
//---------
// |
// v
for (Drop &a : listDrops) {
glColor3f(255,255,255); // white
glVertex2i(a.getPosX(),a.getPosY());
a.move();
}
To take the Drop
s by reference
What you did previously was equivalent to
for (int i=0; i<listDrops.size();++i) {
Drop a = listDrops[i]; //a is a copy of the entry
assert(&a != &listDrops[i])
//...
}