#include <math.h>
#include <GL/glut.h>
#include <stdio.h>
#include<iostream>
#include <Windows.h>
/设计目标/
//碰撞检测√
//自动运动√
//改变方向√
//键盘控制√
//界面设计
//文字计分系统
//开始暂停结束游戏效果
//砖块绘制及判定√
//修改碰撞检测中从斜侧碰撞的bug
/
#define MAX_CHAR 128 //绘制文字
GLfloat brick_weight = 1.6/4;
GLfloat brick_height = 0.2;
const GLint brick_line = 4; //砖块行数
const GLint brick_row = 3; //砖块列数
GLboolean changeDirection = false; //用来显示小球是否变向
int Score = 0;
GLboolean GameRun = true; //控制游戏运行或者停止
//画圆
void drawBall(float x, float y, float radius)
{
int count;
int sections = 200;
GLfloat TWOPI = 2.0f * 3.14159f;
glColor3f(1.0f, 1.0f, 1.0f);//白色
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x, y);
for (count = 0; count <= sections; count++)
{
glVertex2f(x + radius*cos(count*TWOPI / sections), y + radius*sin(count*TWOPI / sections));
}
glEnd();
}
//球杆&&砖块
struct CueANDBrick //cue意为球杆
{
int Num = 0;
bool isBrick=false; //flase为球杆,true为砖块
bool brick_on = true; //flase不显示,true显示
float pos_LD_X = 0.0;//左下角坐标
float pos_LD_Y = -0.8;
float pos_RU_X = 0.4;//右上角坐标
float pos_RU_Y = -0.79;
GLfloat xSpeed = 0.2;//水平移动的速度
} cue;
//小球
struct Ball
{
float pos_X = -0.6;//位置坐标
float pos_Y = 0.0;
float Radius = 0.03;//半径
GLfloat xSpeed = 0.005;//小球速度
GLfloat ySpeed = -0.005;
} BB;
CueANDBrick brick[brick_line][brick_row]; //[行][列]
//不填充矩形
void drawLine(float x1, float y1, float x2, float y2){
glBegin(GL_LINE_LOOP);
glVertex2f(x1, y1);
glVertex2f(x1, y2);
glVertex2f(x2, y2);
glVertex2f(x2, y1);
glEnd();
}
//计算砖块参数
void drawBrick(int line, int row){ //line为行 row为列
for (int i = 0; i < line; i++){ //i为行
for (int j = 0; j < row; j++){ //j为列
brick[i][j].Num = i + j + 1;
brick[i][j].isBrick = true;
if (brick[i][j].brick_on){
brick[i][j].pos_LD_X = -0.6 + i*brick_weight;
brick[i][j].pos_LD_Y = 1 - (j + 1)*brick_height;
brick[i][j].pos_RU_X = -0.6 + (i + 1)*brick_weight;
brick[i][j].pos_RU_Y = 1 - j*brick_height;
}
else{
brick[i][j].pos_LD_X = -2;
brick[i][j].pos_LD_Y = -2;
brick[i][j].pos_RU_X = -2;
brick[i][j].pos_RU_Y = -2;
}
//画砖块
if (brick[i][j].brick_on){
glLineWidth(1.0);
glColor3f(0.0f, 1.0f, 1.0f);
drawLine(brick[i][j].pos_LD_X, brick[i][j].pos_LD_Y, brick[i][j].pos_RU_X, brick[i][j].pos_RU_Y);
}
}
}
}
//填充矩形
void drawRectangle(void){
glColor3f(1.0f, 1.0f, 0.0f);
glRectf(cue.pos_LD_X,cue.pos_LD_Y,cue.pos_RU_X,cue.pos_RU_Y);
}
//碰检中提取出球杆和砖块结构,另写一个统一的判断算法
void Judgment(CueANDBrick&C_B){
//球杆&&砖块
//首先判断四个顶点的碰撞
float m1,m2, n1, n2;
m1 = BB.pos_X - C_B.pos_LD_X;
m2 = BB.pos_X - C_B.pos_RU_X;
n1 = BB.pos_Y - C_B.pos_LD_Y;
n2 = BB.pos_Y - C_B.pos_RU_Y;
if (pow(m1, 2) + pow(n1, 2)<pow(BB.Radius, 2) ||
pow(m1, 2) + pow(n2, 2)<pow(BB.Radius, 2) ||
pow(m2, 2) + pow(n1, 2)<pow(BB.Radius, 2) ||
pow(m2, 2) + pow(n2, 2)<pow(BB.Radius, 2) ){
BB.ySpeed = -BB.ySpeed;
BB.ySpeed = -BB.ySpeed;
printf("%s \t", "X && Y 变向");
changeDirection = true;
}
if (BB.pos_X > C_B.pos_LD_X&&BB.pos_X < C_B.pos_RU_X){
if (BB.pos_Y > C_B.pos_RU_Y && BB.pos_Y < (C_B.pos_RU_Y + BB.Radius)){ //自上而下的碰撞
BB.ySpeed = -BB.ySpeed;
printf("%s \t", "Y变向");
changeDirection = true;
}
else if (BB.pos_Y < C_B.pos_LD_Y && BB.pos_Y > (C_B.pos_LD_Y - BB.Radius)){ //自上而下的碰撞
BB.ySpeed = -BB.ySpeed;
printf("%s \t", "Y变向");
changeDirection = true;
}
}
if (BB.pos_Y > C_B.pos_LD_Y && BB.pos_Y < C_B.pos_RU_Y){
if (BB.pos_X < C_B.pos_LD_X && BB.pos_X > (C_B.pos_LD_X - BB.Radius)){ //自左而右的碰撞
BB.xSpeed = -BB.xSpeed;
printf("%s \t", "X变向");
changeDirection = true;
}
else if (BB.pos_X>C_B.pos_RU_X && BB.pos_X < (C_B.pos_RU_X + BB.Radius)){ //自右而左的碰撞
BB.xSpeed = -BB.xSpeed;
printf("%s \t", "X变向");
changeDirection = true;
}
}
}
//碰撞检测,collide意为碰撞
void Collide(void){
//墙边缘
if (BB.pos_Y < -1) {
GameRun = false;
return;
}
if (BB.pos_Y > 1) {
BB.ySpeed = -BB.ySpeed;
printf("%s \t", "Y变向");
}
if (BB.pos_X < -0.6 || BB.pos_X > 1) {
BB.xSpeed = -BB.xSpeed;
printf("%s \t", "X变向");
}
//球杆
Judgment(cue); //传入CueANDBrick结构参数
changeDirection = false; //每次都初始化为false
//砖块
for (int i = 0; i < brick_line; i++){ //i为行
for (int j = 0; j < brick_row; j++){ //j为列
Judgment(brick[i][j]);
if (changeDirection){ //说明小球击中了砖块,则将砖块隐藏
brick[i][j].brick_on = false;
changeDirection = false; //及时恢复false状态
printf("\n击中=%i \t",j+1);
Score+=10;
if (Score==120){
GameRun = false;
}
printf("Score= %i\n", Score);
}
}
}
}
//空闲时刷新小球位置
void myIdle(void){
if (GameRun){
BB.pos_X += BB.xSpeed;
BB.pos_Y += BB.ySpeed;
Collide(); //碰撞检测
glutPostRedisplay();
Sleep(5);
}
else{
return;
}
}
//绘制文字
void drawString(const char* str) {
static int isFirstCall = 1;
static GLuint lists;
if (isFirstCall) { // 如果是第一次调用,执行初始化
// 为每一个ASCII字符产生一个显示列表
isFirstCall = 0;
// 申请MAX_CHAR个连续的显示列表编号
lists = glGenLists(MAX_CHAR);
// 把每个字符的绘制命令都装到对应的显示列表中
wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
}
// 调用每个字符对应的显示列表,绘制每个字符
for (; *str != '\0'; ++str)
glCallList(lists + *str);
}
//UI设计
void UI(void){
glLineWidth(4.0); //线宽
glColor3f(1.0f, 0.0f, 1.0f);
drawLine(-1, -1, -0.6, 1);
//文字
glColor3f(1.0f, 1.0f, 1.0f);
glRasterPos2f(-0.9f, 0.8f);
drawString("Ball Game");
glRasterPos2f(-0.89f, 0.2f);
drawString("Score");
glRasterPos2f(-0.9f, 0.1f);
switch (Score)
{
case 0:
drawString("0/120");
break;
case 10:
drawString("10/120");
break;
case 20:
drawString("20/120");
break;
case 30:
drawString("30/120");
break;
case 40:
drawString("40/120");
break;
case 50:
drawString("50/120");
break;
case 60:
drawString("60/120");
break;
case 70:
drawString("70/120");
break;
case 80:
drawString("80/120");
break;
case 90:
drawString("90/120");
break;
case 100:
drawString("100/120");
break;
case 110:
drawString("110/120");
break;
case 120:
drawString("120/120");
break;
}
glRasterPos2f(-0.91f, -0.6f);
drawString("Designer");
glRasterPos2f(-0.91f, -0.7f);
drawString("HuangPu");
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // 重置当前的模型观察矩阵
if (GameRun){
//UI
UI();
//画图形
drawRectangle();
drawBrick(brick_line, brick_row);
drawBall(BB.pos_X, BB.pos_Y, BB.Radius);
}
else if (!GameRun && Score == 120){
//文字
glColor3f(1.0f, 1.0f, 1.0f);
glRasterPos2f(-0.1f, 0.0f);
drawString("YOU WIN !");
}
else if (!GameRun && Score < 120){
//文字
glColor3f(1.0f, 1.0f, 1.0f);
glRasterPos2f(-0.1f, 0.0f);
drawString("Try again !");
}
glutSwapBuffers();//双缓存刷新
}
//键盘控制
void keyboard(unsigned char key, int x, int y){
switch (key)
{
case'w':
printf("%s \n", "this is W");
glutPostRedisplay();
break;
case's':
printf("%s \n", "this is S");
glutPostRedisplay();
break;
case'a':
printf("%s \n", "this is A");
glutPostRedisplay();
break;
case'd':
printf("%s \n", "this is D");
glutPostRedisplay();
break;
default:
break;
}
}
//键盘方向键控制
void mySpecial(int key, int x, int y){
switch (key)
{
case GLUT_KEY_UP:
printf("%s \n", "this is up");
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
printf("%s \n", "this is down");
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
printf("%s \n", "this is left");
if (cue.pos_LD_X>-0.6){
cue.pos_LD_X -= cue.xSpeed;
cue.pos_RU_X -= cue.xSpeed;
glutPostRedisplay();
}
break;
case GLUT_KEY_RIGHT:
printf("%s \n", "this is right");
if ( cue.pos_RU_X < 1.0){
cue.pos_LD_X += cue.xSpeed;
cue.pos_RU_X += cue.xSpeed;
glutPostRedisplay();
}
break;
}
}
//初始化函数
void init(){
//更改清屏颜色
glClearColor(0.0, 0.0, 0.0, 0.0);//黑色
glClear(GL_COLOR_BUFFER_BIT);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowPosition(300, 50);
glutInitWindowSize(600, 600);
glutCreateWindow("hp_CG_02_打砖块");
init();
glutDisplayFunc(&myDisplay);
glutKeyboardFunc(keyboard);
glutSpecialFunc(mySpecial);
glutIdleFunc(myIdle);
glutMainLoop();
return 0;
}
这是第一次在CSDN写博客,只是想记录自己学习程序上的点滴。牛人众多不要怕,有道弄斧必到班门,不然怎么能进步呢。</p><p>这是一个Opengl小程序,c++代码,运行环境WIN8.1+VS2013+GLUT