将球移向圆锥体(投球游戏)

Move ball towards the Cone (balling game)

本文关键字:游戏 圆锥体      更新时间:2023-10-16

我正在制作投球游戏。到目前为止,我已经完成了创建球和圆锥体的编码。

我现在想做的是当UP-KEY被按下时,球应该朝着圆锥体移动

我尝试使用计时器函数并调用glutPostRedisplay(),这样球的Y坐标就会增加(在击中UP-KEY之后)并显示/移动。但问题是,当我这样做时,圆锥体和球体开始远离屏幕(因为glTranslate()或glRotate()方法在显示函数内)

当按下UP-KEY时,请建议我的代码将球移向那个圆锥体。

#include <GL/glut.h>
#include <stdlib.h>
#include <Math.h>     // Needed for sin, cos
#define PI 3.14159265f
int windowWidth = 640; // Windowed mode's width
int windowHeight = 480; // Windowed mode's height
int windowPosX = 50; // Windowed mode's top-left corner x
int windowPosY = 50; // Windowed mode's top-left corner y
GLfloat ballRadius = 0.1f; // Radius of the bouncing ball
GLfloat ballX = 0.0f; // Ball's center (x, y) position
GLfloat ballY = 0.0f;
GLfloat ballXMax, ballXMin, ballYMax, ballYMin; // Ball's center (x, y) bounds
GLfloat xSpeed = 0.02f; // Ball's speed in x and y directions
GLfloat ySpeed = 0.007f;
int refreshMillis = 30; // Refresh period in milliseconds
// Projection clipping area
GLdouble clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop;
bool fullScreenMode = true; // Full-screen or windowed mode?
bool paused = false; // Movement paused or resumed
bool moveUp = false, moveDown = false;
GLfloat xSpeedSaved, ySpeedSaved; // To support resume


/* Called back when the timer expired */
void Timer(int value) {
    glutPostRedisplay(); // Post a paint request to activate display()
    glutTimerFunc(refreshMillis, Timer, 0); // subsequent timer call at milliseconds
}
/* Callback handler for normal-key event */
void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 27: // ESC key
        exit(0);
        break;
    }
}
/* Callback handler for special-key event */
void specialKeys(int key, int x, int y) {
    switch (key) {
    case GLUT_KEY_F1: // F1: Toggle between full-screen and windowed mode
        fullScreenMode = !fullScreenMode; // Toggle state
        if (fullScreenMode) { // Full-screen mode
            windowPosX = glutGet(GLUT_WINDOW_X); // Save parameters for restoring later
            windowPosY = glutGet(GLUT_WINDOW_Y);
            windowWidth = glutGet(GLUT_WINDOW_WIDTH);
            windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
            glutFullScreen(); // Switch into full screen
        } else { // Windowed mode
            glutReshapeWindow(windowWidth, windowHeight); // Switch into windowed mode
            glutPositionWindow(windowPosX, windowPosX); // Position top-left corner
        }
        break;
    case GLUT_KEY_RIGHT: // Right: increase x speed
        xSpeed *= 1.05f;
        break;
    case GLUT_KEY_LEFT: // Left: decrease x speed
        xSpeed *= 0.95f;
        break;
    case GLUT_KEY_HOME: // Up: increase y speed
        ySpeed *= 1.05f;
        break;
    case GLUT_KEY_END: // Down: decrease y speed
        ySpeed *= 0.95f;
        break;
    case GLUT_KEY_DOWN:
        moveUp = false;
        moveDown = true;
        break;
    case GLUT_KEY_UP:
        ballY += ySpeed;
        /*moveDown = false;
        moveUp = true;*/
        break;
    case GLUT_KEY_PAGE_UP: // Page-Up: increase ball's radius
        ballRadius *= 1.05f;
        ballXMin = clipAreaXLeft + ballRadius;
        ballXMax = clipAreaXRight - ballRadius;
        ballYMin = clipAreaYBottom + ballRadius;
        ballYMax = clipAreaYTop - ballRadius;
        break;
    case GLUT_KEY_PAGE_DOWN: // Page-Down: decrease ball's radius
        ballRadius *= 0.95f;
        ballXMin = clipAreaXLeft + ballRadius;
        ballXMax = clipAreaXRight - ballRadius;
        ballYMin = clipAreaYBottom + ballRadius;
        ballYMax = clipAreaYTop - ballRadius;
        break;
    }
}
static void resize(int width, int height) {
    GLfloat aspect = (GLfloat) width / (GLfloat) height;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-aspect, aspect, -1.0, 1.0, 2.0, 100.0);
    if (height == 0)
        height = 1; // To prevent divide by 0
    // Set the viewport to cover the new window
    glViewport(0, 0, width, height);
    if (width >= height) {
        clipAreaXLeft = -1.0 * aspect;
        clipAreaXRight = 1.0 * aspect;
        clipAreaYBottom = -1.0;
        clipAreaYTop = 1.0;
    } else {
        clipAreaXLeft = -1.0;
        clipAreaXRight = 1.0;
        clipAreaYBottom = -1.0 / aspect;
        clipAreaYTop = 1.0 / aspect;
    }
}
static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3d(0, 0, 1);
    glPushMatrix();
    glTranslated(-1.0, 0.5, -10);
    glRotated(70, -1.0, 0.0, 0.0);
    glutSolidCone(1, 2, 70, 50);
    glPopMatrix();
    glTranslatef(ballX, ballY, -6.0f); // Translate to (xPos, yPos)
    // Use triangular segments to form a circle
    glBegin(GL_TRIANGLE_FAN);
    glColor3f(0.0f, 0.0f, 1.0f); // Blue
    glVertex2f(0.0f, 0.0f); // Center of circle
    int numSegments = 100;
    GLfloat angle;
    for (int i = 0; i <= numSegments; i++) { // Last vertex same as first vertex
        angle = i * 2.0f * PI / numSegments; // 360 deg for all segments
        glVertex2f(cos(angle) * ballRadius, sin(angle) * ballRadius);
    }
    glEnd();
    if (moveUp)
        ballY += ySpeed;
    if (moveDown)
        ballY -= ySpeed;
    // Check if the ball exceeds the edges
    if (ballX > ballXMax) {
        ballX = ballXMax;
        xSpeed = -xSpeed;
    } else if (ballX < ballXMin) {
        ballX = ballXMin;
        xSpeed = -xSpeed;
    }
    if (ballY > ballYMax) {
        ballY = ballYMax;
        ySpeed = -ySpeed;
    } else if (ballY < ballYMin) {
        ballY = ballYMin;
        ySpeed = -ySpeed;
    }
    glutSwapBuffers();
}
/*
 const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
 const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
 const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f };
 const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
 const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
 const GLfloat high_shininess[] = { 100.0f };
 */
/* Program entry point */
int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitWindowSize(windowWidth, windowHeight); // Initial window width and height
    glutInitWindowPosition(windowPosX, windowPosY); // Initial window top-left corner (x, y)
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Balling game");
    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glClearColor(1, 1, 1, 1);

    glutSpecialFunc(specialKeys); // Register callback handler for special-key event
    glutKeyboardFunc(keyboard); // Register callback handler for special-key event
    glutFullScreen(); // Put into full screen
    /*glEnable(GL_CULL_FACE);
     glCullFace(GL_BACK);
     glEnable(GL_DEPTH_TEST);
     glDepthFunc(GL_LESS);
     glEnable(GL_LIGHT0);
     glEnable(GL_NORMALIZE);
     glEnable(GL_COLOR_MATERIAL);
     glEnable(GL_LIGHTING);
     glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
     glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
     glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
     glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
     glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);*/
    glutMainLoop();
    return EXIT_SUCCESS;
}

@Immueggpain这是在按下UP_KEY时将球(在2d中)向上移动的代码。

#include <GL/glut.h>  // GLUT, include glu.h and gl.h
#include <Math.h>     // Needed for sin, cos
#define PI 3.14159265f
// Global variables
char title[] = "Full-Screen & Windowed Mode"; // Windowed mode's title
int windowWidth = 640; // Windowed mode's width
int windowHeight = 480; // Windowed mode's height
int windowPosX = 50; // Windowed mode's top-left corner x
int windowPosY = 50; // Windowed mode's top-left corner y
GLfloat ballRadius = 0.1f; // Radius of the bouncing ball
GLfloat ballX = 0.0f; // Ball's center (x, y) position
GLfloat ballY = 0.0f;
GLfloat ballXMax, ballXMin, ballYMax, ballYMin; // Ball's center (x, y) bounds
GLfloat xSpeed = 0.02f; // Ball's speed in x and y directions
GLfloat ySpeed = 0.007f;
int refreshMillis = 30; // Refresh period in milliseconds
// Projection clipping area
GLdouble clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop;
bool fullScreenMode = true; // Full-screen or windowed mode?
bool paused = false; // Movement paused or resumed
bool moveUp = false, moveDown = false;
GLfloat xSpeedSaved, ySpeedSaved; // To support resume
/* Initialize OpenGL Graphics */
void initGL() {
    glClearColor(0.0, 0.0, 0.0, 1.0); // Set background (clear) color to black
}
/* Callback handler for window re-paint event */
void display() {
    glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer
    glMatrixMode(GL_MODELVIEW); // To operate on the model-view matrix
    glLoadIdentity(); // Reset model-view matrix
    glColor3d(0, 0, 1);
        glPushMatrix();
        glTranslated(-1.0, 0.5, -10);
        glRotated(70, -1.0, 0.0, 0.0);
        glutSolidCone(1, 2, 70, 50);
        glPopMatrix();
    glTranslatef(ballX, ballY, 0.0f); // Translate to (xPos, yPos)
    // Use triangular segments to form a circle
    glBegin(GL_TRIANGLE_FAN);
    glColor3f(0.0f, 0.0f, 1.0f); // Blue
    glVertex2f(0.0f, 0.0f); // Center of circle
    int numSegments = 100;
    GLfloat angle;
    for (int i = 0; i <= numSegments; i++) { // Last vertex same as first vertex
        angle = i * 2.0f * PI / numSegments; // 360 deg for all segments
        glVertex2f(cos(angle) * ballRadius, sin(angle) * ballRadius);
    }
    glEnd();

    glutSwapBuffers(); // Swap front and back buffers (of double buffered mode)
    // Animation Control - compute the location for the next refresh
    //ballX += xSpeed;
    if (moveUp)
        ballY += ySpeed;
    if (moveDown)
        ballY -= ySpeed;
    // Check if the ball exceeds the edges
    if (ballX > ballXMax) {
        ballX = ballXMax;
        xSpeed = -xSpeed;
    } else if (ballX < ballXMin) {
        ballX = ballXMin;
        xSpeed = -xSpeed;
    }
    if (ballY > ballYMax) {
        ballY = ballYMax;
        ySpeed = -ySpeed;
    } else if (ballY < ballYMin) {
        ballY = ballYMin;
        ySpeed = -ySpeed;
    }
}
/* Call back when the windows is re-sized */
void reshape(GLsizei width, GLsizei height) {
    // Compute aspect ratio of the new window
    if (height == 0)
        height = 1; // To prevent divide by 0
    GLfloat aspect = (GLfloat) width / (GLfloat) height;
    // Set the viewport to cover the new window
    glViewport(0, 0, width, height);

    // Set the aspect ratio of the clipping area to match the viewport
    glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
    glLoadIdentity(); // Reset the projection matrix
    if (width >= height) {
        clipAreaXLeft = -1.0 * aspect;
        clipAreaXRight = 1.0 * aspect;
        clipAreaYBottom = -1.0;
        clipAreaYTop = 1.0;
    } else {
        clipAreaXLeft = -1.0;
        clipAreaXRight = 1.0;
        clipAreaYBottom = -1.0 / aspect;
        clipAreaYTop = 1.0 / aspect;
    }
    gluOrtho2D(clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop);
    ballXMin = clipAreaXLeft + ballRadius;
    ballXMax = clipAreaXRight - ballRadius;
    ballYMin = clipAreaYBottom + ballRadius;
    ballYMax = clipAreaYTop - ballRadius;
}
/* Called back when the timer expired */
void Timer(int value) {
    glutPostRedisplay(); // Post a paint request to activate display()
    glutTimerFunc(refreshMillis, Timer, 0); // subsequent timer call at milliseconds
}
/* Callback handler for normal-key event */
void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 27: // ESC key
        exit(0);
        break;
    }
}
/* Callback handler for special-key event */
void specialKeys(int key, int x, int y) {
    switch (key) {
    case GLUT_KEY_F1: // F1: Toggle between full-screen and windowed mode
        fullScreenMode = !fullScreenMode; // Toggle state
        if (fullScreenMode) { // Full-screen mode
            windowPosX = glutGet(GLUT_WINDOW_X); // Save parameters for restoring later
            windowPosY = glutGet(GLUT_WINDOW_Y);
            windowWidth = glutGet(GLUT_WINDOW_WIDTH);
            windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
            glutFullScreen(); // Switch into full screen
        } else { // Windowed mode
            glutReshapeWindow(windowWidth, windowHeight); // Switch into windowed mode
            glutPositionWindow(windowPosX, windowPosX); // Position top-left corner
        }
        break;
    case GLUT_KEY_RIGHT: // Right: increase x speed
        xSpeed *= 1.05f;
        break;
    case GLUT_KEY_LEFT: // Left: decrease x speed
        xSpeed *= 0.95f;
        break;
    case GLUT_KEY_HOME: // Up: increase y speed
        ySpeed *= 1.05f;
        break;
    case GLUT_KEY_END: // Down: decrease y speed
        ySpeed *= 0.95f;
        break;
    case GLUT_KEY_DOWN:
        moveUp = false;
        moveDown = true;
        break;
    case GLUT_KEY_UP:
        moveDown = false;
        moveUp = true;
        break;
    case GLUT_KEY_PAGE_UP: // Page-Up: increase ball's radius
        ballRadius *= 1.05f;
        ballXMin = clipAreaXLeft + ballRadius;
        ballXMax = clipAreaXRight - ballRadius;
        ballYMin = clipAreaYBottom + ballRadius;
        ballYMax = clipAreaYTop - ballRadius;
        break;
    case GLUT_KEY_PAGE_DOWN: // Page-Down: decrease ball's radius
        ballRadius *= 0.95f;
        ballXMin = clipAreaXLeft + ballRadius;
        ballXMax = clipAreaXRight - ballRadius;
        ballYMin = clipAreaYBottom + ballRadius;
        ballYMax = clipAreaYTop - ballRadius;
        break;
    }
}
/* Callback handler for mouse event */
void mouse(int button, int state, int x, int y) {
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { // Pause/resume
        paused = !paused; // Toggle state
        if (paused) {
            xSpeedSaved = xSpeed; // Save parameters for restore later
            ySpeedSaved = ySpeed;
            xSpeed = 0; // Stop movement
            ySpeed = 0;
        } else {
            xSpeed = xSpeedSaved; // Restore parameters
            ySpeed = ySpeedSaved;
        }
    }
}
/* Main function: GLUT runs as a console application starting at main() */
int main(int argc, char** argv) {
    glutInit(&argc, argv); // Initialize GLUT
    glutInitDisplayMode(GLUT_DOUBLE); // Enable double buffered mode
    glutInitWindowSize(windowWidth, windowHeight); // Initial window width and height
    glutInitWindowPosition(windowPosX, windowPosY); // Initial window top-left corner (x, y)
    glutCreateWindow(title); // Create window with given title
    glutDisplayFunc(display); // Register callback handler for window re-paint
    glutReshapeFunc(reshape); // Register callback handler for window re-shape
    glutTimerFunc(0, Timer, 0); // First timer call immediately
    glutSpecialFunc(specialKeys); // Register callback handler for special-key event
    glutKeyboardFunc(keyboard); // Register callback handler for special-key event
    glutFullScreen(); // Put into full screen
    glutMouseFunc(mouse); // Register callback handler for mouse event
    initGL(); // Our own OpenGL initialization
    glutMainLoop(); // Enter event-processing loop
    return 0;
}

这是绘制一个圆锥体的小代码(在3d中)。

glColor3d(0, 0, 1);
    glPushMatrix();
    glTranslated(-1.0, 0.5, -10);
    glRotated(70, -1.0, 0.0, 0.0);
    glutSolidCone(1, 2, 70, 50);
    glPopMatrix();

但是,当我将此代码放入display方法中时,它不会显示圆锥体。

也许与glFrustum()有关,但我不知道怎么做?

有什么建议吗?