问题描述
我在OpenGL中写了一个简单的砖块游戏。球是使用以下绘制的2D圆:
I've written a simple brick breaker game in OpenGL. The ball is a 2D circle drawn using :
for (float angle = 0; angle < (10); angle+=0.01)
{
glVertex2f((x_pos + sin(angle) * RADIUS), (y_pos + (cos(angle)) * RADIUS));
}
当游戏更改为全屏时会导致失真。 RADIUS定义为0.025。
我需要帮助,使板运动顺利以及。
此外,如果你玩这个游戏几次,你会注意到,最左边,当球击中桨,它上升到一定的高度,然后反弹回来。
完整代码:
This causes distortion when the game is changed to fullscreen. RADIUS is defined as 0.025 .I need help in making the paddle movements smooth as well.Also, if you play the game a couple of times, you'll notice that towards the extreme left, when the ball hits the paddle, it rises to a certain height and then bounces back down.Full code:
#include <GL/openglut.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#define RADIUS 0.025
#define SPEED 0.001
int WIDTH = 900;
int HEIGHT = 650;
int RATIO = WIDTH/HEIGHT;
bool show[5][10];
float x_brick[4][9];
float y_brick[4][9];
float P_XPOS = 0;
float P_YPOS = -0.8;
bool phit_center = false , phit_corner = false;
bool game_over = false;
bool RIGHT = 1,LEFT = 0,UP = 1,DOWN = 0;
bool started = false;
float x_pos = 0,y_pos = -0.75;
bool hit = false;
int lives = 3;
using namespace std;
void b_draw()
{
glColor3f(1.0,0.0,0.0);
glBegin(GL_QUADS);
for(int a = 0; a < 9; a++)
{
for(int b = 0; b < 4; b++)
{
if(show[b][a] == 1)
{
glVertex2f(x_brick[b][a],y_brick[b][a]);
glVertex2f(x_brick[b][a],y_brick[b][a] - 0.10);
glVertex2f(x_brick[b][a]+0.2,y_brick[b][a] - 0.10);
glVertex2f(x_brick[b][a]+0.2,y_brick[b][a]);
}
}
}
glEnd();
}
void c_draw()
{
glColor3f(0.0,0.0,0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x_pos,y_pos);
for (float angle = 0; angle < (10); angle+=0.01)
{
glVertex2f((x_pos + sin(angle) * RADIUS), (y_pos + (cos(angle)) * RADIUS));
}
glEnd();
}
bool b_hit()
{
hit = false;
int flag = 1;
for(int a = 0; a < 10; a++)
{
for(int b =0; b < 4; b++)
{
if(x_pos >= x_brick[b][a] && x_pos <= x_brick[b][a] + 0.2)
{
if(y_pos <= y_brick[b][a] && y_pos >= y_brick[b][a] - 0.1)
{
if(show[b][a] == 1)
{
show[b][a] = 0;
flag = 0;
hit = true;
break;
}
}
}
}
if(flag == 0)
break;
}
return hit;
}
bool crashed()
{
if(y_pos < P_YPOS - 0.05)
return true;
else return false;;
}
void p_hit()
{
phit_corner = false;
phit_center = false;
if(x_pos <= P_XPOS + 0.13 && x_pos >= P_XPOS - 0.13)
{
if(y_pos <= P_YPOS)
{
phit_center = true;
}
}
else if((x_pos >= P_XPOS + 0.13 && x_pos <= P_XPOS + 0.2) || (x_pos <= P_XPOS - 0.13 && x_pos >= P_XPOS - 0.2))
{
if(y_pos <= P_YPOS)
{
phit_corner = true;
}
}
}
void c_move()
{
if(UP && RIGHT)
{
x_pos += (SPEED);
y_pos += (SPEED);
}
if(UP && LEFT)
{
x_pos -= (SPEED);
y_pos += (SPEED);
}
if(DOWN && RIGHT)
{
x_pos += (SPEED);
y_pos -= (SPEED);
}
if(DOWN && LEFT)
{
x_pos -= (SPEED);
y_pos -= (SPEED);
}
b_hit();
if(x_pos >= (RATIO-RADIUS))
{
RIGHT = 0;
LEFT = 1;
}
else if(x_pos <= (-RATIO+RADIUS))
{
RIGHT = 1;
LEFT = 0;
}
if(y_pos >= (RATIO-RADIUS) || hit )
{
UP = 0;
DOWN = 1;
}
else if(y_pos <= (-RATIO+RADIUS) || hit )
{
UP = 1;
DOWN = 0;
}
p_hit();
if(phit_center)
{
DOWN = 0;
UP = 1;
}
if(phit_corner)
{
if(LEFT)
{
LEFT = 0;
RIGHT = 1;
}
else
{
RIGHT = 0;
LEFT = 1;
}
UP = 1;
DOWN = 0;
}
}
void p_draw()
{
glColor3f(0.0,0.0,0.0);
glBegin(GL_QUADS);
glVertex2f(P_XPOS-0.2,P_YPOS);
glVertex2f(P_XPOS+0.2,P_YPOS);
glVertex2f(P_XPOS+0.2,P_YPOS-0.05);
glVertex2f(P_XPOS-0.2,P_YPOS-0.05);
glEnd();
}
void BallLoop()
{
glClearColor(1.0,1.0,1.0,0);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
c_draw();
b_draw();
p_draw();
glFlush();
if(started)
c_move();
if(crashed())
{
x_pos = 0;
y_pos = -0.7;
started = 0;
UP = 1;
RIGHT = 1;
DOWN = 0;
LEFT = 0;
}
glutSwapBuffers();
glutPostRedisplay();
}
void user_input(unsigned char key, int x, int y)
{
if(key == 13)
started = true;
}
void ArrowKeys(int key, int x, int y)
{
if(key==GLUT_KEY_LEFT && P_XPOS >= -0.8)
for(float a = 0; a < 0.05; a+= 0.001)
{
P_XPOS -=0.003;
BallLoop();
}
if(key==GLUT_KEY_RIGHT && P_XPOS <= 0.8)
{
for(float a = 0; a < 0.05; a+= 0.001)
{
P_XPOS +=0.003;
BallLoop();
}
}
}
void set_xy()
{
for(int a = 0; a < 5; a++)
{
for(int b = 0; b < 10; b++)
{
show[a][b] = 1;
}
}
int c = 0;
for(float a = -0.94; c <= 8; a+=0.21)
{
for(int b = 0; b <= 5; b++)
{
x_brick[b][c] = a;
}
c++;
}
int d = 0;
for(float s = 0.99; d <= 3; s-=0.11)
{
for(int r = 0; r < 9; r++)
{
y_brick[d][r] = s;
}
d++;
}
}
void changeSize(int w, int h)
{
if(h == 0)
h = 1;
RATIO = w/h;
float ratio = 1.0* w / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
glMatrixMode(GL_MODELVIEW);
BallLoop();
}
int main(int argc, char **argv)
{
set_xy();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0,0);
glutInitWindowSize(WIDTH,HEIGHT);
glutCreateWindow("Brick Breaker - By Viraj");
glutReshapeFunc(changeSize);
glutDisplayFunc(BallLoop);
glutKeyboardFunc(user_input);
glutSpecialFunc(ArrowKeys);
glutMainLoop();
return 0;
}
推荐答案
这种问题,因为他们基于他们的代码上写得不好的教程。一个关键的错误是在重塑处理器中进行投影矩阵设置。在任何严重的OpenGL应用程序,包括,你会在渲染过程中切换投影几次 - HUD,小地图,GUI元素等。
A lot of people run into this kind of issue, because they base their code on badly written tutorials. One key mistake is to do the projection matrix setup in the reshape handler. In any serious OpenGL application, games including, you will switch the projection several times during rendering – for HUDs, minimaps, GUI elements etc.
处理程序,就在你需要该投影之前。此外,你错过了设置投影矩阵,你只设置视口 - 关闭,但不够。我不会调用显示处理程序 Ball_Loop
,但很好,这里是我如何修改它:
Instead you set projection in the display handler, right before you need that projection. Also you missed to set the projection matrix at all, you only set the viewport - close, but not enough. I'd not call the display handler Ball_Loop
, but well, here's how I'd modify it:
void BallLoop()
{
const int win_width = glutGet(GLUT_WINDOW_WIDTH);
const int win_height = glutGet(GLUT_WINDOW_HEIGHT);
const float win_aspect = (float)win_width/(float)win_height;
glClearColor(1.0,1.0,1.0,0);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1); /* those ortho limits should match your game logic */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
c_draw();
b_draw();
p_draw();
glFlush();
if(started)
c_move();
if(crashed())
{
x_pos = 0;
y_pos = -0.7;
started = 0;
UP = 1;
RIGHT = 1;
DOWN = 0;
LEFT = 0;
}
glutSwapBuffers();
glutPostRedisplay();
}
/ strong>完全固定和可播放的brickbreaker.cc源代码
EDIT fully fixed and playable brickbreaker.cc source code
#include <GL/glut.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
using namespace std;
#define RADIUS 0.025
#define RATIO (4./3.)
bool show[5][10];
float x_brick[4][9];
float y_brick[4][9];
float paddle_x = 0;
float paddle_y = -0.8;
float paddle_speed = 0;
const float PaddleSpeedFactor = 3.;
bool phit_center = false , phit_corner = false;
bool game_over = false;
float speed_x = 0.;
float speed_y = 0.;
float x_pos = 0,y_pos = -0.75;
int lives = 3;
float T_last_frame = 0.;
void draw_bricks()
{
glColor3f(1.0,0.0,0.0);
glBegin(GL_QUADS);
for(int a = 0; a < 9; a++)
{
for(int b = 0; b < 4; b++)
{
if(show[b][a] == 1)
{
glVertex2f(x_brick[b][a],y_brick[b][a]);
glVertex2f(x_brick[b][a],y_brick[b][a] - 0.10);
glVertex2f(x_brick[b][a]+0.2,y_brick[b][a] - 0.10);
glVertex2f(x_brick[b][a]+0.2,y_brick[b][a]);
}
}
}
glEnd();
}
void ball_draw()
{
glColor3f(0.0,0.0,0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x_pos,y_pos);
for (float angle = 0; angle < (10); angle+=0.01)
{
glVertex2f((x_pos + sin(angle) * RADIUS), (y_pos + (cos(angle)) * RADIUS));
}
glEnd();
}
bool brick_hit()
{
bool hit = false;
int flag = 1;
for(int a = 0; a < 10; a++)
{
for(int b =0; b < 4; b++)
{
if(x_pos >= x_brick[b][a] && x_pos <= x_brick[b][a] + 0.2)
{
if(y_pos <= y_brick[b][a] && y_pos >= y_brick[b][a] - 0.1)
{
if(show[b][a] == 1)
{
show[b][a] = 0;
flag = 0;
hit = true;
break;
}
}
}
}
if(flag == 0)
break;
}
return hit;
}
bool crashed()
{
if(y_pos < paddle_y - 0.05)
return true;
return false;
}
void paddle_hit()
{
phit_corner = false;
phit_center = false;
if(x_pos <= paddle_x + 0.13 && x_pos >= paddle_x - 0.13)
{
if(y_pos <= paddle_y)
{
phit_center = true;
}
}
else if( (x_pos >= paddle_x + 0.13 && x_pos <= paddle_x + 0.2) ||
(x_pos <= paddle_x - 0.13 && x_pos >= paddle_x - 0.2))
{
if(y_pos <= paddle_y)
{
phit_corner = true;
}
}
}
void paddle_move(float dT)
{
if(paddle_x < RATIO && paddle_x > -RATIO)
paddle_x += paddle_speed * PaddleSpeedFactor * dT;
if( paddle_x > 0.95) {
paddle_x = 0.95;
paddle_speed = 0.;
}
if( paddle_x < -0.95) {
paddle_x = -0.95;
paddle_speed = 0.;
}
paddle_speed *= (1. - 0.05);
if( fabs(paddle_speed) < 0.01 )
paddle_speed = 0.;
}
void ball_move(float dT)
{
x_pos += speed_x * dT;
y_pos += speed_y * dT;
if( brick_hit() ) {
speed_y *= -1;
}
if( x_pos >= (RATIO-RADIUS) || x_pos <= (-RATIO+RADIUS ) )
{
speed_x *= -1;
}
if( y_pos >= (1.-RADIUS) )
{
speed_y = -1;
}
paddle_hit();
if(phit_center)
{
speed_y = 1;
}
if(phit_corner)
{
speed_x *= -1;
speed_y = 1;
}
}
void paddle_draw()
{
glColor3f(0.0,0.0,0.0);
glBegin(GL_QUADS);
glVertex2f(paddle_x - 0.2, paddle_y);
glVertex2f(paddle_x + 0.2, paddle_y);
glVertex2f(paddle_x + 0.2, paddle_y - 0.05);
glVertex2f(paddle_x - 0.2, paddle_y - 0.05);
glEnd();
}
void step_game()
{
paddle_move(T_last_frame);
ball_move(T_last_frame);
if(crashed())
{
speed_x = 0;
speed_y = 0;
x_pos = 0;
y_pos = -0.7;
paddle_speed = 0;
paddle_x = 0;
}
glutPostRedisplay();
}
void launch_ball()
{
speed_y = 1.;
speed_x = 1.;
}
void user_input(unsigned char key, int x, int y)
{
if(key == 13)
launch_ball();
}
void ArrowKeys(int key, int x, int y)
{
if(key==GLUT_KEY_LEFT)
paddle_speed = -1.;
if(key==GLUT_KEY_RIGHT)
paddle_speed = +1.;
}
void set_xy()
{
for(int a = 0; a < 5; a++)
{
for(int b = 0; b < 10; b++)
{
show[a][b] = 1;
}
}
int c = 0;
for(float a = -0.94; c <= 8; a+=0.21)
{
for(int b = 0; b <= 5; b++)
{
x_brick[b][c] = a;
}
c++;
}
int d = 0;
for(float s = 0.99; d <= 3; s-=0.11)
{
for(int r = 0; r < 9; r++)
{
y_brick[d][r] = s;
}
d++;
}
}
void display()
{
const int win_width = glutGet(GLUT_WINDOW_WIDTH);
const int win_height = glutGet(GLUT_WINDOW_HEIGHT);
const float win_aspect = (float)win_width / (float)win_height;
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(win_aspect > RATIO) {
glOrtho(-win_aspect, win_aspect, -1., 1., -1., 1.);
} else {
glOrtho(-RATIO, RATIO, -RATIO/win_aspect, RATIO/win_aspect, -1., 1.);
}
glMatrixMode(GL_MODELVIEW);
glClearColor(0., 0., 1., 1.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glColor3f(1,1,1);
glVertex2f(-RATIO, -1);
glVertex2f(RATIO, -1);
glVertex2f(RATIO, 1);
glVertex2f(-RATIO, 1);
glEnd();
draw_bricks();
paddle_draw();
ball_draw();
glutSwapBuffers();
// GLUT doesn't offer cross plattform timing
// assume 60Hz refresh rate
T_last_frame = 1./60.;
}
int main(int argc, char **argv)
{
set_xy();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0,0);
glutInitWindowSize(800, 600);
glutCreateWindow("Brick Breaker - By Viraj");
glutDisplayFunc(display);
glutKeyboardFunc(user_input);
glutSpecialFunc(ArrowKeys);
glutIdleFunc(step_game);
glutMainLoop();
return 0;
}
,为了完整起见,这里是一个GLFW版本。
EDIT 2 and just for the sake of completeness, here's a GLFW version
#include <GL/glfw.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
#define RADIUS 0.025
#define RATIO (4./3.)
bool show[5][10];
float x_brick[4][9];
float y_brick[4][9];
const float SpeedFactor = 10.;
float paddle_x = 0;
float paddle_y = -0.8;
float paddle_speed = 0;
const float PaddleSpeedFactor = 3.;
bool phit_center = false, phit_corner = false;
bool game_over = false;
float speed_x = 0.;
float speed_y = 0.;
float x_pos;
float y_pos;
int lifes = 0;
void draw_bricks()
{
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_QUADS);
for (int a = 0; a < 9; a++) {
for (int b = 0; b < 4; b++) {
if (show[b][a] == 1) {
glVertex2f(x_brick[b][a], y_brick[b][a]);
glVertex2f(x_brick[b][a], y_brick[b][a] - 0.10);
glVertex2f(x_brick[b][a] + 0.2,
y_brick[b][a] - 0.10);
glVertex2f(x_brick[b][a] + 0.2, y_brick[b][a]);
}
}
}
glEnd();
}
void ball_draw()
{
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x_pos, y_pos);
for (float angle = 0; angle < (10); angle += 0.01) {
glVertex2f((x_pos + sin(angle) * RADIUS),
(y_pos + (cos(angle)) * RADIUS));
}
glEnd();
}
bool brick_hit()
{
for (int a = 0; a < 10; a++) {
for (int b = 0; b < 4; b++) {
if (x_pos >= x_brick[b][a]
&& x_pos <= x_brick[b][a] + 0.2) {
if (y_pos <= y_brick[b][a]
&& y_pos >= y_brick[b][a] - 0.1) {
if (show[b][a] == 1) {
show[b][a] = 0;
return true;
}
}
}
}
}
return false;
}
bool crashed()
{
if (y_pos < paddle_y - 0.05)
return true;
return false;
}
void paddle_hit()
{
phit_corner = false;
phit_center = false;
if (x_pos <= paddle_x + 0.13 && x_pos >= paddle_x - 0.13) {
if (y_pos <= paddle_y) {
phit_center = true;
}
} else if ((x_pos >= paddle_x + 0.13 && x_pos <= paddle_x + 0.2) ||
(x_pos <= paddle_x - 0.13 && x_pos >= paddle_x - 0.2)) {
if (y_pos <= paddle_y) {
phit_corner = true;
}
}
}
void paddle_move(float dT)
{
if (paddle_x < RATIO && paddle_x > -RATIO)
paddle_x += paddle_speed * PaddleSpeedFactor * dT;
if (paddle_x > 1.) {
paddle_x = 1.;
paddle_speed = 0.;
}
if (paddle_x < -1.) {
paddle_x = -1.;
paddle_speed = 0.;
}
}
void ball_move(float dT)
{
x_pos += speed_x * dT;
y_pos += speed_y * dT;
if (brick_hit()) {
speed_y *= -1;
}
if (x_pos >= (RATIO - RADIUS) || x_pos <= (-RATIO + RADIUS)) {
speed_x *= -1;
}
if (y_pos >= (1. - RADIUS)) {
speed_y = -1;
}
paddle_hit();
if (phit_center) {
speed_y = 1;
}
if (phit_corner) {
speed_x *= -1;
speed_y = 1;
}
}
void paddle_draw()
{
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2f(paddle_x - 0.2, paddle_y);
glVertex2f(paddle_x + 0.2, paddle_y);
glVertex2f(paddle_x + 0.2, paddle_y - 0.05);
glVertex2f(paddle_x - 0.2, paddle_y - 0.05);
glEnd();
}
void reset_game()
{
lifes = 3;
speed_x = 0;
speed_y = 0;
x_pos = 0;
y_pos = -0.7;
paddle_speed = 0;
paddle_x = 0;
}
void step_game(float dT)
{
if(!lifes)
return;
paddle_move(dT * SpeedFactor);
ball_move(dT * SpeedFactor);
if (crashed()) {
lifes--;
speed_x = 0;
speed_y = 0;
x_pos = 0;
y_pos = -0.7;
}
}
void launch_ball()
{
if(!lifes)
return;
speed_y = 1.;
speed_x = 1.;
}
void keyboard(int key, int action)
{
switch(key)
{
case GLFW_KEY_ENTER:
launch_ball();
break;
case GLFW_KEY_ESC:
reset_game();
break;
case GLFW_KEY_LEFT:
switch(action) {
case GLFW_PRESS:
paddle_speed = -1.;
break;
case GLFW_RELEASE:
paddle_speed = 0;
break;
} break;
case GLFW_KEY_RIGHT:
switch(action) {
case GLFW_PRESS:
paddle_speed = 1.;
break;
case GLFW_RELEASE:
paddle_speed = 0;
break;
} break;
}
}
void set_xy()
{
for (int a = 0; a < 5; a++) {
for (int b = 0; b < 10; b++) {
show[a][b] = 1;
}
}
int c = 0;
for (float a = -0.94; c <= 8; a += 0.21) {
for (int b = 0; b <= 5; b++) {
x_brick[b][c] = a;
}
c++;
}
int d = 0;
for (float s = 0.99; d <= 3; s -= 0.11) {
for (int r = 0; r < 9; r++) {
y_brick[d][r] = s;
}
d++;
}
}
float display()
{
int win_width;
int win_height;
glfwGetWindowSize(&win_width, &win_height);
const float win_aspect = (float)win_width / (float)win_height;
glfwSetTime(0.);
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (win_aspect > RATIO) {
glOrtho(-win_aspect, win_aspect, -1., 1., -1., 1.);
} else {
glOrtho(-RATIO, RATIO, -RATIO / win_aspect, RATIO / win_aspect,
-1., 1.);
}
glMatrixMode(GL_MODELVIEW);
glClearColor(0., 0., 1., 1.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glColor3f(1, 1, 1);
glVertex2f(-RATIO, -1);
glVertex2f(RATIO, -1);
glVertex2f(RATIO, 1);
glVertex2f(-RATIO, 1);
glEnd();
draw_bricks();
paddle_draw();
ball_draw();
glfwSwapBuffers();
return glfwGetTime();
}
int main(int argc, char **argv)
{
set_xy();
if( GL_FALSE == glfwInit() )
return -1;
if( GL_FALSE == glfwOpenWindow(800, 600, 8, 8, 8, 8, 0, 0, GLFW_WINDOW) )
return -2;
glfwSetWindowTitle("Viraj's Brick Breaker - GLFW version by datenwolf");
glfwSetKeyCallback(keyboard);
reset_game();
while( glfwGetWindowParam(GLFW_OPENED) ) {
glfwPollEvents();
float const dT = display();
step_game(dT);
}
glfwTerminate();
return 0;
}
这篇关于破砖机帮助。圆圈,桨和尴尬的弹跳的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!