Search code examples
c++listopenglglut

Pixels move when initialized on their own, but not in loop?


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 Drops alongside a function to add Drops 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 Drops 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.


Solution

  • 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 Drops 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])
        //...
    }