Trying to make a simple 2d game, objects flashing with glutIdleFunc and glutSpecialFunc

StackOverflow https://stackoverflow.com/questions/23486004

  •  16-07-2023
  •  | 
  •  

Question

So I'm creating a simple, 2d game and I have a fish that just has to eat smaller fish. There's not really a problem with the game itself, but basically what happens is that I want other fish to move on their own, so I use the glutIdleFunc for that which works fine. However, I guess I'm not really sure on how I should make it work because I don't want that to happen until the first key is pressed. I decided to put it in my handleKey function (used to make the player move) but now my fish will disappear if the other fish move, or you can see it flashing as you hold a key down. I'm sure it's just a problem with swapping or clearing the buffer at some point, I understand you're supposed to do it once per frame, but I feel like it needs to be done as many times as I have and I can't seem to find what's causing my problem and an extra pair of eyes always helps...I'm sorry it's so lengthy and unorganized, I wanted to make it all work before cleaning it up.

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h> //used for random numbers
#include <GL/glut.h>
#include <GL\GL.h>
#include <math.h>
#include <iostream>

using namespace std;

#define X WIDTH/2
#define Y HEIGHT/2
#define PI 3.14159
#define INC .001



const int WIDTH = 720;
const int HEIGHT = 480;
const int numFish=10;
const int playerEyeRad=2;
const int eyeRad=1;
const int sharkEyeRad=3;


static float mouthSize = .7;
static int mouthOpen=0;
static int score=1;
static int lives=3;

bool gameRunning = true;

void *font = GLUT_BITMAP_TIMES_ROMAN_24;


struct Player
{
    int x,y;

    GLfloat deltax;
    GLfloat deltay;
    GLfloat spin;
    GLfloat scaleX;
    GLfloat scaleY;
    GLfloat scaleZ;

};


Player playerFish;


struct Fish
{
    int x,y;
    int size;
    GLfloat deltax;
    GLfloat deltay;
    GLfloat spin;
    GLfloat scale;
    bool goingLeft;
    bool goingRight;
    bool goingUp;
    bool goingDown;

};

Fish cpFish[numFish];
Fish barracuda;



char defaultMessage[] = "Fish game";
char *message = defaultMessage;

void initialize();
void output(int x, int y, char *string);
void firstDisplay();
void drawPlayer(int x, int y);
void translatePlayer(int key);
void handleKey(int key,int x,int y);  //function to handle when we press a key

void drawFish(int x, int y,int eyerad);
void setFish();
void displayFish();
void  translateFish();
void eat(int numFish);
void endGame();
void setBarracuda();
void drawBarracuda(int x, int y);
void translateBarracuda();
void barracudaEat();
void setPlayer();




int _tmain(int argc, char* argv[])
{
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE);

    glutInitWindowSize(WIDTH,HEIGHT);
    glutCreateWindow("Fish Game");


    initialize();

    setPlayer();
    setFish();
    setBarracuda();
    glutDisplayFunc(firstDisplay);
    glutSpecialFunc(handleKey);


    glutMainLoop();

    return 0;
}

void initialize()
{
    glClearColor(.098,.14,.96,0);


    glColor3f(1,1,1);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluOrtho2D(0,WIDTH,0,HEIGHT);


    return;

}

void output(int x, int y, char *string)
{
    int len, i;

    glRasterPos2f(x,y);

    len = (int) strlen(string);

    for(i=0;i<len;i++){
        glutBitmapCharacter(font,string[i]);
    }

    return;
}

void firstDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(0,0,0);
    output(X,Y, message);
    output (X, Y - 40,"by");
    output(X,Y - 80,"derp");


    drawBarracuda(barracuda.x,barracuda.y);
    displayFish();
    drawPlayer(playerFish.x,playerFish.y);
    glutSwapBuffers();
    glFlush();

    return;
}
void setPlayer()
{
    playerFish.x=100;
    playerFish.y=200;
    playerFish.scaleX=1;
    playerFish.scaleY=1;
    playerFish.scaleZ=1;
    playerFish.spin=0;
    playerFish.deltax=0;
    playerFish.deltay=0;

}

void drawPlayer(int x, int y)
{
    float theta;

    //glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POLYGON); // fish body
        glColor3f(.56,.035,.035);
            for(theta=0;theta<2*PI;theta+=INC)
            {
                glVertex2f(x + 20* cos(theta),y + 10 * sin(theta));
            }
    glEnd();

    glBegin(GL_TRIANGLES); //bottom of fish tail
        glColor3f(.56,.035,.035);
            glVertex2i((x-35),(y-10));
            glVertex2i((x-5),(y-5));
            glVertex2i((x-20),y);
    glEnd();
        glBegin(GL_TRIANGLES); //top of fish tail
        glColor3f(.56,.035,.035);
            glVertex2i((x-35),(y+10));
            glVertex2i((x-5),y);
            glVertex2i((x-20),(y-5));
    glEnd();
    glBegin(GL_POLYGON); //fish eye
        glColor3f(0,0,0);
            for(theta=0;theta<2*PI;theta+=INC)
            {
                glVertex2f((x+7) + playerEyeRad * cos(theta),(y+3) + playerEyeRad * sin(theta));
            }
    glEnd();
    glBegin(GL_POLYGON); //fish mouth
        glColor3f(.098,.14,.96);
        //glColor3f(0,0,0);

            glVertex2i(112,198); 
            for(theta=-mouthSize;theta<mouthSize;theta+=INC)
            {
                glVertex2f(x + 20 * cos(theta),y + 10 * sin(theta));


            }


    glEnd();

    glEnable(GL_LINE_STIPPLE); //stipple the gills
        short stipplePattern=0x3F07;
    glColor3f(0,0,0);
        glBegin(GL_LINES);  
        glLineStipple(1,stipplePattern);
            glVertex2i(x,(y-2));
            glVertex2i((x+5),(y-2));
        glEnd();

        glBegin(GL_LINES);
        glLineStipple(1,stipplePattern);
            glVertex2i(x,(y-5));
            glVertex2i((x+5),(y-5));
        glEnd();

    glDisable(GL_LINE_STIPPLE); //disable stipple, end of gills


            return;
}


void translatePlayer(int key)
{
    glClear(GL_COLOR_BUFFER_BIT);

    if (key==GLUT_KEY_RIGHT && (playerFish.x + playerFish.deltax) < WIDTH - 20)
    {
        playerFish.deltax+=6;
        playerFish.spin=0;
    }
    if (key==GLUT_KEY_LEFT && (playerFish.x + playerFish.deltax) > 20)
    {
        playerFish.deltax-=6;
        playerFish.spin=180;
    }
    if (key==GLUT_KEY_UP && (playerFish.y + playerFish.deltay) < HEIGHT - 20)
    {
        playerFish.deltay+=6;
        playerFish.spin=90;
    }
    if (key==GLUT_KEY_DOWN && (playerFish.y + playerFish.deltay) > 20)
    {
        playerFish.deltay-=6;
        playerFish.spin=270;
    }

    if (score%5==0)
    {
        playerFish.scaleX++;
        playerFish.scaleY++;
        playerFish.scaleZ++;
        score=1;
        playerFish.x=(playerFish.x + playerFish.deltax )* playerFish.scaleX;
        playerFish.y=(playerFish.y + playerFish.deltay) * playerFish.scaleY;
    }

    glPushMatrix(); //push on translation matrix
    glTranslatef(playerFish.x + playerFish.deltax, playerFish.y + playerFish.deltay,0.0); //translate back to position
    glScalef(playerFish.scaleX,playerFish.scaleY,playerFish.scaleZ);
    if (key==GLUT_KEY_LEFT) // stops player from going upside down
        glRotatef(playerFish.spin,0,-1,0); //reflect y axis
    else
    glRotatef(playerFish.spin,0,0,1); // spin 

    glTranslatef(-playerFish.x,-playerFish.y,0.0); //translate back to origin
    drawPlayer(playerFish.x, playerFish.y); //draw player to screen
    glPopMatrix(); // pop the matrix


    glutSwapBuffers(); //swap the buffers 
    //glFlush();

    if (!gameRunning || playerFish.scaleX>=6|| lives <=0)
    endGame();


    // mouth open close 
    if(mouthSize < .05 && mouthOpen==0)
    {
        mouthSize = .7;
        mouthOpen++;
    }
    else
    {
        mouthSize=.007; 
        mouthOpen++;
        if (mouthOpen==5)
            mouthOpen=0;        
    }

    return;
}

//function used to handle keys being pressed
//param int key ascii value of key being pressed, int x, int y coordinates the glutspecialfunc requires
//return void
void handleKey(int key,int x,int y)
{
    //glClear(GL_COLOR_BUFFER_BIT);//clear the buffer bit
    //drawPlayer(playerFish.x + playerFish.deltax,playerFish.y+playerFish.deltay);

    //glutIdleFunc(translateFish);
    glutIdleFunc(NULL); 
    if(key == GLUT_KEY_DOWN ||key == GLUT_KEY_UP ||key == GLUT_KEY_LEFT ||key == GLUT_KEY_RIGHT) // if any of the arrow keys are being pressed
    {
        if (gameRunning && playerFish.scaleX <6 && lives > 0)
        {

        translatePlayer(key); //call on the translate function using the key integer value
        glFlush();
        //glutSwapBuffers();
        //glutIdleFunc(translateFish);
        }
    }

    glutIdleFunc(translateFish);

    glFlush();
    //glutSwapBuffers();
    return;
}//end handleKey


void drawFish(int x, int y, int eyeRad)
{
    float theta;

    glBegin(GL_POLYGON); // fish body
        glColor3f(.8,.75,.023);
            for(theta=0;theta<2*PI;theta+=INC)
            {
                glVertex2f(x + 10* cos(theta),y + 5 * sin(theta));
            }
    glEnd();

    glBegin(GL_TRIANGLES); //bottom of fish tail
        glColor3f(.8,.75,.023);
            glVertex2i((x-15),(y-5));
            glVertex2i((x-10),y);
            glVertex2i(x,(y-5));
    glEnd();
        glBegin(GL_TRIANGLES); //top of fish tail
        glColor3f(.8,.75,.023);
            glVertex2i((x-15),(y+5));
            glVertex2i(x,y);
            glVertex2i((x-10),(y-5));
    glEnd();
    glBegin(GL_POLYGON); //fish eye
        glColor3f(0,0,0);
            for(theta=0;theta<2*PI;theta+=INC)
            {
                glVertex2f((x+5) + eyeRad * cos(theta),(y+3) + eyeRad * sin(theta));
            }
    glEnd();
    return;
}
//function used to set x and y values for the computer fish
//param none
//return void

void setFish()
{
    int counter;
    int randX;
    int randY;



    for(counter=0;counter<numFish;counter++)
    {
        randX = (1+rand() % (WIDTH-50));
        randY = (1+ rand() % (HEIGHT-50));

        cpFish[counter].x=randX;
        cpFish[counter].y=randY;
        cpFish[counter].size=1;
        cpFish[counter].goingUp=true;
        cpFish[counter].goingDown=false;
        cpFish[counter].goingRight=true;
        cpFish[counter].goingLeft=false;

    }
    return;
}
//function used to display the fish to the screen
void displayFish()
{

    int counter;

    for(counter=0;counter<numFish;counter++)
    {
        //cout<<"Drawing fish to screen at position: "<<cpFish[counter].x<<" \t" <<cpFish[counter].y<<endl;
        drawFish(cpFish[counter].x,cpFish[counter].y,eyeRad);

    }
    return;
}

void  translateFish()
{
    int fishNum;
    glClear(GL_COLOR_BUFFER_BIT);

    for(fishNum=0;fishNum<numFish;fishNum++)
    {


            if ((cpFish[fishNum].deltax + cpFish[fishNum].x)< WIDTH - 20 && cpFish[fishNum].goingRight)
            {
            cpFish[fishNum].deltax +=3;
            cpFish[fishNum].spin=0;
                if ((cpFish[fishNum].deltax + cpFish[fishNum].x) >= WIDTH - 20)
                {
                    cpFish[fishNum].goingRight=false;
                    cpFish[fishNum].goingLeft=true;
                }
            } // end right if
            if ((cpFish[fishNum].deltax + cpFish[fishNum].x)> 20 && cpFish[fishNum].goingLeft)
            {
            cpFish[fishNum].deltax -=3;
            cpFish[fishNum].spin = 180;
                if ((cpFish[fishNum].deltax + cpFish[fishNum].x)<= 20)
                {
                    cpFish[fishNum].goingLeft=false;
                    cpFish[fishNum].goingRight=true;
                }
            }// end left if
            if ((cpFish[fishNum].deltay + cpFish[fishNum].y)< HEIGHT - 20 && cpFish[fishNum].goingUp)
            {
            cpFish[fishNum].deltay +=3;

                if ((cpFish[fishNum].deltay + cpFish[fishNum].y)>= HEIGHT - 20)
                {
                    cpFish[fishNum].goingUp=false;
                    cpFish[fishNum].goingDown=true;
                }
            } // end up if
            if ((cpFish[fishNum].deltay + cpFish[fishNum].y)> 20 && cpFish[fishNum].goingDown)
            {
            cpFish[fishNum].deltay -=3;

                if ((cpFish[fishNum].deltay + cpFish[fishNum].y) <= 20)
                {
                    cpFish[fishNum].goingDown=false;
                    cpFish[fishNum].goingUp=true;
                }
            }// end down if

            glPushMatrix();
            glTranslatef(cpFish[fishNum].x + cpFish[fishNum].deltax,cpFish[fishNum].y + cpFish[fishNum].deltay,0);
            if(cpFish[fishNum].goingLeft)
                glRotatef(cpFish[fishNum].spin,0,-1,0);
            else
            glRotatef(cpFish[fishNum].spin,0,0,1);
            glTranslatef(-cpFish[fishNum].x,-cpFish[fishNum].y,0);
            drawFish(cpFish[fishNum].x,cpFish[fishNum].y,eyeRad);
            glPopMatrix();


            eat(fishNum);


        //  cout<<"Fish "<<fishNum<<"'s deltax + x: "<<cpFish[fishNum].deltax + cpFish[fishNum].x <<" \t deltay: "<<cpFish[fishNum].deltay + cpFish[fishNum].y<<endl;
            //cout<<"Going up = "<<cpFish[fishNum].goingUp<<"going down "<<cpFish[fishNum].goingDown<<" going Right "<<cpFish[fishNum].goingRight<<"  going left "<<cpFish[fishNum].goingLeft<<endl;
    }

        translateBarracuda();
        glutSwapBuffers();
        return;
}
void eat(int numFish)
{
    int playerSize=playerFish.scaleX;
    int fishSize=cpFish[numFish].size;
    int playerX=playerFish.x + playerFish.deltax;
    int playerY = playerFish.y + playerFish.deltay;
    int cpX=cpFish[numFish].x+cpFish[numFish].deltax;
    int cpY=cpFish[numFish].y+cpFish[numFish].deltay;

    int newX = (1+rand() % (WIDTH-50));
    int newY= (1+ rand() % (HEIGHT-50));
    //cout<<"PLAYER'S X: "<<playerX<<"\t PLAYER'S Y: "<<playerY<<"\t FISH" <<numFish<<" X "<<cpX<< "\t FISH "<<numFish<<" Y: " <<cpY<<endl;
    if ((fishSize <= playerSize)&&((cpX - playerX >= (-10*playerFish.scaleX)) && (cpX - playerX <= (10*playerFish.scaleX)) )&&((cpY - playerY >= (-10*playerFish.scaleY)) &&(cpY - playerY <= (10*playerFish.scaleY))))
    {
        cpFish[numFish].x = newX;
        cpFish[numFish].y = newY;
        score++;
        cpFish[numFish].goingUp=true;
        cpFish[numFish].goingDown=false;
        cpFish[numFish].goingRight=true;
        cpFish[numFish].goingLeft=false;
        cpFish[numFish].deltax=0;
        cpFish[numFish].deltay=0;

        drawFish(cpFish[numFish].x,cpFish[numFish].y, eyeRad);

    }


    if (playerSize==6)
        gameRunning=false;

}

void endGame()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0,0,0);
    glClearColor(1,1,1,0);
    if (!gameRunning || playerFish.scaleX>=6)
    {

        output(X,Y,"You win!");
        //exit;
    }

    else 
    {
        if (lives<=0)
        {

        output(X,Y,"Game over, you lost");
    //  exit;
        }
    }

    glutSwapBuffers();

}

void drawBarracuda(int x, int y)
{
    float theta;
    glBegin(GL_POLYGON); // fish body

        glColor3f(.596,.596,.576);
            for(theta=0;theta<2*PI;theta+=INC)
            {
                glVertex2f(x + 45* cos(theta),y + 10 * sin(theta));
            }
    glEnd();

    glBegin(GL_TRIANGLES); //bottom of fish tail
        glColor3f(.596,.596,.576);
            glVertex2i((x-55),(y-10));
            glVertex2i((x-25),(y-5));
            glVertex2i((x-40),y);
    glEnd();
        glBegin(GL_TRIANGLES); //top of fish tail
        glColor3f(.596,.596,.576);
            glVertex2i((x-55),(y+10));
            glVertex2i((x-25),y);
            glVertex2i((x-40),(y-5));
    glEnd();
    glBegin(GL_POLYGON); //fish eye
        glColor3f(0,0,0);
            for(theta=0;theta<2*PI;theta+=INC)
            {
                glVertex2f((x+7) + sharkEyeRad * cos(theta),(y+3) + sharkEyeRad * sin(theta));
            }
    glEnd();
    glBegin(GL_POLYGON); //fish mouth
        glColor3f(.098,.14,.96);
        //glColor3f(0,0,0);

            glVertex2i((x+12),(y-2)); 
            for(theta=-mouthSize;theta<mouthSize;theta+=INC)
            {
                glVertex2f(x + 45 * cos(theta),y + 10 * sin(theta));


            }


    glEnd();
        glEnable(GL_LINE_STIPPLE); //stipple the gills
        short stipplePattern=0x3F07;
    glColor3f(0,0,0);
        glBegin(GL_LINES);  
        glLineStipple(1,stipplePattern);
            glVertex2i((x-10),(y-2));
            glVertex2i((x-5),(y-2));
        glEnd();

        glBegin(GL_LINES);
        glLineStipple(1,stipplePattern);
            glVertex2i((x-10),(y-5));
            glVertex2i((x-5),(y-5));
        glEnd();

    glDisable(GL_LINE_STIPPLE); //disable stipple, end of gills

}

void setBarracuda()
{
    barracuda.x=100;
    barracuda.y=350;
    barracuda.size=3;
    barracuda.goingLeft=false;
    barracuda.goingRight=true;
    barracuda.goingUp=false;
    barracuda.goingDown=false;

}

void translateBarracuda()
{
    if ((barracuda.deltax + barracuda.x)< WIDTH - 20 && barracuda.goingRight)
            {
            barracuda.deltax +=9;
            barracuda.spin=0;
                if ((barracuda.deltax + barracuda.x) >= WIDTH - 20)
                {
                    int newX=100;
                    int newY=(1 + rand() % HEIGHT);
                    drawBarracuda(newX,newY);
                    barracuda.x=newX;
                    barracuda.y=newY;
                    barracuda.deltax=0;
                    barracuda.deltay=0;
                }
            } // end right if


            glPushMatrix();
            glTranslatef(barracuda.x + barracuda.deltax,barracuda.y + barracuda.deltay,0);
            glRotatef(barracuda.spin,0,0,1);
            glTranslatef(-barracuda.x,-barracuda.y,0);
            drawBarracuda(barracuda.x,barracuda.y);
            glPopMatrix();

            barracudaEat();

}

void barracudaEat()
{
    int playerSize=playerFish.scaleX;
    int barracudaSize=barracuda.size;
    int barracudaPosX = barracuda.x + barracuda.deltax;
    int barracudaPosY = barracuda.y + barracuda.deltay;
    int playerX = playerFish.x + playerFish.deltax;
    int playerY = playerFish.y + playerFish.deltay;


    if ((playerSize < barracudaSize)&&((playerX - barracudaPosX >= (-10*playerFish.scaleX)) && (playerX - barracudaPosX <= (10*playerFish.scaleX)) )&&((playerY - barracudaPosY >= (-10*playerFish.scaleY)) &&(playerY - barracudaPosY <= (10*playerFish.scaleY))))
    {
        lives--;
        playerFish.x = 100;
        playerFish.y = 200;
        playerFish.deltax=0;
        playerFish.deltay=0;
        playerFish.spin=0;
        playerFish.scaleX=1;
        playerFish.scaleY=1;
        playerFish.scaleZ=1;
    if (lives==0)
    {
        endGame();

    }

    }
    else
    {
        if ((playerSize >= barracudaSize)&&((playerX - barracudaPosX >= (-10*playerFish.scaleX)) && (playerX - barracudaPosX <= (10*playerFish.scaleX)) )&&((playerY - barracudaPosY >= (-10*playerFish.scaleY)) &&(playerY - barracudaPosY <= (10*playerFish.scaleY))))
        {
            drawBarracuda(0,600);
            barracuda.x=0;
            barracuda.y=600;
            gameRunning=false;
            endGame();

        }
    }



}
Was it helpful?

Solution 3

I fixed my issues and I got the game to work, thank you for everyone's input!!! I'm new to the site so I have no idea how to close the question though!

Just as an example, I took my original translatePlayer function and broke it up into an updateFunction. Everything you see in this function was taken out of the translatePlayer function

void updatePlayer()
{
    //opens and closes the player's mouth but not each time the key is pressed
    if(mouthSize < .05 && mouthOpen==0) 
    {
        mouthSize = .7;
        mouthOpen++;
    }
    else
    {
        mouthSize=.007; 
        mouthOpen++;
        if (mouthOpen==5)
            mouthOpen=0;        
    }

    //All the transformations for the player happen here

    glPushMatrix(); //push on translation matrix
    glTranslatef(playerFish.x + playerFish.deltax, playerFish.y + playerFish.deltay,0.0); //translate back to position
    glScalef(playerFish.scaleX,playerFish.scaleY,playerFish.scaleZ);
    if (playerFish.spin==180) // stops player from going upside down
        glRotatef(playerFish.spin,0,-1,0); //reflect y axis
    else
    glRotatef(playerFish.spin,0,0,1); // spin 

    glTranslatef(-playerFish.x,-playerFish.y,0.0); //translate back to origin
    drawPlayer(playerFish.x, playerFish.y); //draw player to screen
    glPopMatrix(); // pop the matrix

    //the player gets scaled according to the score variable, then gets reset back to 1 so the player isn't always being scaled up
        if (score%5==0)
    {
        playerFish.scaleX++;
        playerFish.scaleY++;
        playerFish.scaleZ++;
        score=1;
    }

} //end updatePlayer

OTHER TIPS

Have you tried commenting glClear(GL_COLOR_BUFFER_BIT); from everywhere, and having it in only one place, i.e. in the glutDisplayFunc, in this case void firstDisplay()

The basic rule with OpenGL is: All drawing happens only from within the display routine and from nowhere else. No OpenGL commands must be called from input event handlers. Input event handlers set/accumulate into program variables and post a redraw condition. Then let the next display iteration draw the changes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top