写的比较粗糙的一个小游戏,算是对游戏编程流程的一个入门认识。

OpenGL中,如何加载纹理,如何绘制透明纹理,如何显示文字,如何制作简单动画(画面刷新机制),如何使用键盘和鼠标回调函数,这些我们已经很熟悉了。当然,这些都是最基本的要求。

那么,如何实现游戏基本逻辑?一般而言,用oop的思想能够很好地完成这一点,我们给每类对象维护一些状态量和方法,每个对象可以通过下标索引访问到这些状态量,我们把代码分成两部分 —— 第一部分,当达到一个触发条件时,我们改变状态量的值;第二部分,根据状态量,我们绘制不同形态的物体。

这样下来,整个流程就清晰很多了,我们不再需要写大量的条件判断语句,在条件触发后手动改变绘制形态,而是把改变记录下来,然后置之不理;帧刷新时绘制物体的函数读到了这些变化,然后自动做出调整。如果我们想加入新的状态量,我们只需要加入新的判断语句,并维护状态量即可,而不用改动之前的代码,也就是说不同过程相互之间是独立的。

一.飞机的状态量

在这里,我暂时仍然使用了C风格的变量来维护这些状态量。

我们注意到飞机产生的位置看起来很随机,它们的位置也是比较乱的,那么我们该如何管理这些飞机呢?

使用bool isShip[6][3]这个二维数组,我们可以很方便地控制这些飞机,其中6代表飞机会在6种不同的高度产生,3是每个高度最多的飞机数,一开始,我们只设置一个为true,其余都为false。

每隔一定帧数,我们产生飞机,我们首先随机产生一个高度h,在这个高度下,我们寻找isShip[h][0], isShip[h][1], isShip[h][2] 中还没有被占用的变量(即为false),得到新产生飞机的下标索引,如果都被占用了,那么就不产生飞机。飞机产生后占用这个变量(设为true),消失后又把位置让出(设为false)。

产生的同时,我们还要初始化一些其它的状态量,比如飞机的形状shipType, 飞机从左边还是从右边产生isLeft[6][3], 飞机的初始坐标move_x[6][3],move_y[6],飞船的子弹与飞机的碰撞次数。

这些量都是随机生成的,唯一要注意的是从左边还是从右边产生这一状态量,如果不加处理可能会发生左右碰撞现象,而这是我们不希望的,所以我们在扫描到这一行存在某个方向的飞机时,我们让新的飞机和它方向一样。如果没有检测到,才随机产生。

而飞机的坐标,我们只要在一定时间内不断给它加上或者减去一定值,到了边缘或者被击中后的时候把isShip设为false即可。

当然,这个飞机还会发射子弹,所以我们还需要一些量来维护子弹的状态,同样的,我们需要一个状态量isAttack[6][3][3]来维护子弹是否存在。这个量相比飞机多了一个维度,因为我们希望一个飞机至多可以发射3个子弹。

那么相应的,我们维护子弹的坐标attack_x[6][3][3],attack_y[6][3][3], 子弹是否击中飞isSuccess[6][3][3]

二.白线的控制

我们注意到这个游戏中飞船会不断地发射白线,看起来非常连贯,而且白线还会随着飞船的移动而改变位置。那么,这样的效果究竟是如何实现的呢?我们需要多少变量来保存白线的状态呢?

看似连续不断的白线,实际上是三帧画面的重复绘制!

在这个场景中,一共显示25根白线,而一共有三种状态量,所以我们用二维数组pos_y[25][3]来管理它们的y坐标,当然,x坐标方向不存在这样的移动动画,用一维数组维护即可。

解决了线条的动画效果后,我们来考虑如何实现线条随飞船移动而移动。

飞船可以左右移动,那么便有一个变量来维护它的x坐标,每次白线移动的时候,我们使用推移的方法,把后面白线的x坐标转移给前一根白线,然后最后的白线(离飞船最近的)用飞船的x坐标取代,这样,就产生了白线随飞船位置而产生的效果。

game.h

#pragma once
#define GLUT_DISABLE_ATEXIT_HACK
#include "GL/GLUT.H"
void loadTex(int i, char *filename, GLuint* texture);
void loadTex_alpha(int i, char *filename, GLuint* texture);

textrue.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include"game.h"
#define BITMAP_ID 0x4D42   //读纹理图片
static unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{FILE *filePtr;    // 文件指针    BITMAPFILEHEADER bitmapFileHeader;    // bitmap文件头    unsigned char    *bitmapImage;        // bitmap图像数据    int    imageIdx = 0;        // 图像位置索引    unsigned char    tempRGB;    // 交换变量    // 以“二进制+读”模式打开文件filename     filePtr = fopen(filename, "rb");if (filePtr == NULL) {printf("file not open\n");return NULL;}// 读入bitmap文件图    fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);// 验证是否为bitmap文件    if (bitmapFileHeader.bfType != BITMAP_ID) {fprintf(stderr, "Error in LoadBitmapFile: the file is not a bitmap file\n");return NULL;}// 读入bitmap信息头    fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);// 将文件指针移至bitmap数据    fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);// 为装载图像数据创建足够的内存    bitmapImage = new unsigned char[bitmapInfoHeader->biSizeImage];// 验证内存是否创建成功    if (!bitmapImage) {fprintf(stderr, "Error in LoadBitmapFile: memory error\n");return NULL;}// 读入bitmap图像数据    fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);// 确认读入成功    if (bitmapImage == NULL) {fprintf(stderr, "Error in LoadBitmapFile: memory error\n");return NULL;}//由于bitmap中保存的格式是BGR,下面交换R和B的值,得到RGB格式    for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) {tempRGB = bitmapImage[imageIdx];bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];bitmapImage[imageIdx + 2] = tempRGB;}// 关闭bitmap图像文件   fclose(filePtr);return bitmapImage;
}//读纹理图片
static unsigned char *LoadBitmapFile_alpha(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{FILE *filePtr;    // 文件指针    BITMAPFILEHEADER bitmapFileHeader;    // bitmap文件头    unsigned char    *bitmapImage;        // bitmap图像数据    int    imageIdx = 0;        // 图像位置索引    // 以“二进制+读”模式打开文件filename     filePtr = fopen(filename, "rb");if (filePtr == NULL) {printf("file not open\n");return NULL;}// 读入bitmap文件图    fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);// 验证是否为bitmap文件    if (bitmapFileHeader.bfType != BITMAP_ID) {fprintf(stderr, "Error in LoadBitmapFile: the file is not a bitmap file\n");return NULL;}// 读入bitmap信息头    fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);// 将文件指针移至bitmap数据    fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);// 为装载图像数据创建足够的内存    bitmapImage = new unsigned char[bitmapInfoHeader->biSizeImage];// 验证内存是否创建成功    if (!bitmapImage) {fprintf(stderr, "Error in LoadBitmapFile: memory error\n");return NULL;}// 读入bitmap图像数据    fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);// 确认读入成功    if (bitmapImage == NULL) {fprintf(stderr, "Error in LoadBitmapFile: memory error\n");return NULL;}unsigned char*   bitmapData;   // 纹理数据 bitmapData = new unsigned char[bitmapInfoHeader->biSizeImage / 3 * 4];int count = 0;//由于bitmap中保存的格式是BGR,下面交换R和B的值,得到RGB格式    for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) {bitmapData[count] = bitmapImage[imageIdx + 2];bitmapData[count + 1] = bitmapImage[imageIdx + 1];bitmapData[count + 2] = bitmapImage[imageIdx];if (bitmapData[count] == 255 && bitmapData[count + 1] == 255 && bitmapData[count + 2] == 255) {bitmapData[count + 3] = 0;}else bitmapData[count + 3] = 255;count += 4;}// 关闭bitmap图像文件   fclose(filePtr);return bitmapData;
}//加载纹理的函数
void loadTex(int i, char *filename, GLuint* texture)
{BITMAPINFOHEADER bitmapInfoHeader;                                 // bitmap信息头    unsigned char*   bitmapData;                                       // 纹理数据    bitmapData = LoadBitmapFile(filename, &bitmapInfoHeader);glBindTexture(GL_TEXTURE_2D, texture[i]);// 指定当前纹理的放大/缩小过滤方式    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexImage2D(GL_TEXTURE_2D,0,         //mipmap层次(通常为,表示最上层)     GL_RGB,    //我们希望该纹理有红、绿、蓝数据    bitmapInfoHeader.biWidth, //纹理宽带,必须是n,若有边框+2     bitmapInfoHeader.biHeight, //纹理高度,必须是n,若有边框+2     0, //边框(0=无边框, 1=有边框)     GL_RGB,    //bitmap数据的格式    GL_UNSIGNED_BYTE, //每个颜色数据的类型    bitmapData);    //bitmap数据指针    }//加载纹理的函数
void loadTex_alpha(int i, char *filename, GLuint* texture)
{BITMAPINFOHEADER bitmapInfoHeader;                                 // bitmap信息头    unsigned char*   bitmapData;                                       // 纹理数据    bitmapData = LoadBitmapFile_alpha(filename, &bitmapInfoHeader);glBindTexture(GL_TEXTURE_2D, texture[i]);// 指定当前纹理的放大/缩小过滤方式    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);glTexImage2D(GL_TEXTURE_2D,0,         //mipmap层次(通常为,表示最上层)     GL_RGBA,    //我们希望该纹理有红、绿、蓝数据    bitmapInfoHeader.biWidth, //纹理宽带,必须是n,若有边框+2     bitmapInfoHeader.biHeight, //纹理高度,必须是n,若有边框+2     0, //边框(0=无边框, 1=有边框)     GL_RGBA,    //bitmap数据的格式    GL_UNSIGNED_BYTE, //每个颜色数据的类型    bitmapData);    //bitmap数据指针    }

main.cpp

#define _CRT_SECURE_NO_WARNINGS  #include <stdio.h>
#include <string.h>
#include<time.h>
#include <stdlib.h>
#include <windows.h>
#include"game.h"  GLuint texture[5];//视区
float whRatio;
int wHeight = 0;
int wWidth = 0;//控制飞机生成(最好能改成类)float move_x[6][3];//移动飞机的x坐标
float move_y[6] = { 2.5f,2.0f,1.5f,1.0f,0.0f,-0.5f };//移动飞机的y坐标
bool isShip[6][3];//该位置是否存在飞机
int collisionTimes[6][3] = { 0 };//碰撞次数
bool isAttack[6][3][3];//该飞机是否发子弹
float attack_x[6][3][3];//子弹的x坐标
float attack_y[6][3][3];//子弹的y坐标
bool isSuccess[6][3][3];//是否击中飞船
bool isLeft[6][3];//飞机是否从左边产生
int shipType[6][3];//飞机的形状//白线位置
float pos[25] = { 0.0f };//25条白线的x坐标
float pos_y[25][3];//25条白线的y坐标(3种状态)
float pos_x = 0.0f; //飞船的x坐标
int status = 0;//计时
int count = 0;
int count2 = 0;
int count3 = 0;//视点
float center[] = { 0, 0, 0 };
float eye[] = { 0, 0, 5 };//分数
int score = 0;//生命值
int life = 300;void drawRect(GLuint texture)
{glEnable(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, texture);  //选择纹理texture[status]   const GLfloat x1 = -0.5, x2 = 0.5;const GLfloat y1 = -0.5, y2 = 0.5;const GLfloat point[4][2] = { { x1,y1 },{ x2,y1 },{ x2,y2 },{ x1,y2 } };int dir[4][2] = { { 0,0 },{ 1,0 },{ 1,1 },{ 0,1 } };glBegin(GL_QUADS);for (int i = 0; i < 4; i++) {glTexCoord2iv(dir[i]);glVertex2fv(point[i]);}glEnd();glDisable(GL_TEXTURE_2D);
}inline bool collisionTest(float y1, float y2, float y3, float x1, float x2, float x3)
{if (x3 > x1 && x3 < x2 && y1 < y3 && y3 < y2) return true;else return false;
}inline bool collisionTest(float y1, float y2, float y3, float y4, float x1, float x2, float x3)
{if (x3 > x1 && x3 < x2 && (y1<y3 && y1 > y4 || y2 < y3 && y2 > y4)) return true;else return false;
}//绘制飞船发出的白线
void drawLine()
{glTranslatef(0.0, 2.9f, 0.0f);for (int i = 0; i < 25; i++) {glBegin(GL_LINES);glVertex3f(pos[i], -0.05f, 1.0f);glVertex3f(pos[i], 0.05f, 1.0f);glEnd();glTranslatef(0.0, -0.2f, 0.0f);}
}//控制从右边产生的飞机的移动
void shipMoveRight(int i,int j)
{glPushMatrix();glTranslatef(move_x[i][j], move_y[i], 1.0f);glScalef(0.6, 0.5, 1);move_x[i][j] -= 0.0005f;if (move_x[i][j] < -3.5f) {isShip[i][j] = false;collisionTimes[i][j] = 0;}if (collisionTimes[i][j] >= 5) {glColor3f(1, 0, 0);}drawRect(texture[shipType[i][j]]);glColor3f(1, 1, 1);glPopMatrix();}//控制从左边产生的飞机的移动
void shipMoveLeft(int i, int j)
{glPushMatrix();glTranslatef(move_x[i][j], move_y[i], 1.0f);glScalef(0.6, 0.5, 1);move_x[i][j] += 0.0005f;if (move_x[i][j] > 3.5f) {isShip[i][j] = false;collisionTimes[i][j] = 0;}if (collisionTimes[i][j] >= 5) {glColor3f(1, 0, 0);}drawRect(texture[shipType[i][j]]);glColor3f(1, 1, 1);glPopMatrix();}void printData()
{static int frame = 0, time, timebase = 0;static char buffer[256]; //字符串缓冲区  frame++;int life2 = 10;int score2 = 10;time = glutGet(GLUT_ELAPSED_TIME);//返回两次调用glutGet(GLUT_ELAPSED_TIME)的时间间隔,单位为毫秒  if (time - timebase > 1000) { //时间间隔差大于1000ms时  life2 = life;score2 = score;sprintf(buffer, "Score : %d   Life : %d",score2, life2); //写入buffer中  timebase = time; //上一次的时间间隔  frame = 0;}char *c;glDisable(GL_DEPTH_TEST);     // 禁止深度测试  glMatrixMode(GL_PROJECTION);  // 选择投影矩阵  glPushMatrix();               // 保存原矩阵  glLoadIdentity();             // 装入单位矩阵  glOrtho(0, 480, 0, 480, -1, 1);    // 位置正投影  glMatrixMode(GL_MODELVIEW);   // 选择Modelview矩阵  glPushMatrix();               // 保存原矩阵  glLoadIdentity();             // 装入单位矩阵  glRasterPos2f(10, 10);for (c = buffer; *c != '\0'; c++) {glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c); //绘制字符  }glMatrixMode(GL_PROJECTION);  // 选择投影矩阵  glPopMatrix();                // 重置为原保存矩阵  glMatrixMode(GL_MODELVIEW);   // 选择Modelview矩阵  glPopMatrix();                // 重置为原保存矩阵  glEnable(GL_DEPTH_TEST);      // 开启深度测试  //弹出对话框提示游戏结束if (life2 == 0) {char result[30];char str[30];strcpy(result, "游戏结束,您的得分是:");_itoa(score2, str, 10);strcat(result, str);MessageBox(NULL, TEXT(result), TEXT("注意"), MB_ICONINFORMATION);exit(0);}
}void drawScene()
{//绘制星空背景glPushMatrix();glScalef(8, 6, 1);drawRect(texture[0]);glPopMatrix();//绘制白线glPushMatrix();glColor3f(1.0f, 1.0f, 1.0f);if (count >= 50 && count < 100) {glTranslatef(0.0f, 0.066f, 0.0f);status = 1;}else if (count >= 100 && count < 150) {glTranslatef(0.0f, 0.132f, 0.0f);status = 2;}else status = 0;drawLine();glPopMatrix();//设置深度缓存为只读glDepthMask(GL_FALSE);//绘制移动的飞机for (int i = 0; i < 6; i++) {for (int j = 0; j < 3; j++) {if (isShip[i][j]) {//判断飞机从哪个方向产生if(!isLeft[i][j])shipMoveRight(i, j);else shipMoveLeft(i, j);if (isShip[i][j] == false)continue;int t = status;for (int k = 0; k < 25; k++) {//判断白线和飞机是否发生碰撞if (collisionTest(pos_y[k][t] - 0.05f, pos_y[k][t] + 0.05f, move_y[j] - 0.3f, move_x[i][j] - 0.1f, move_x[i][j] + 0.1f, pos[k])) {collisionTimes[i][j]++;if (shipType[i][j] == 3 && collisionTimes[i][j]>15) {isShip[i][j] = false;score += 10;printData();collisionTimes[i][j] = 0;}else if (shipType[i][j] == 1 && collisionTimes[i][j]>100) {isShip[i][j] = false;score += 15;printData();collisionTimes[i][j] = 0;}}}}for (int k = 0; k < 3; k++) {//绘制飞机的子弹if (isAttack[i][j][k]) {glPushMatrix();glColor3f(1, 0, 0);glTranslatef(attack_x[i][j][k], attack_y[i][j][k], 0.0f);glBegin(GL_LINES);glVertex3f(0.0f, -0.03f, 1.0f);glVertex3f(0.0f, 0.03f, 1.0f);glEnd();glPopMatrix();glColor3f(1, 1, 1);//判断子弹是否击中飞船if (!isSuccess[i][j][k] && collisionTest(attack_y[i][j][k] - 0.03f, attack_y[i][j][k] + 0.03f, -1.95f,-2.65f, pos_x - 0.38f, pos_x + 0.38f, attack_x[i][j][k])) {isSuccess[i][j][k] = true;life -= 10;printData();}//移动子弹位置if (count % 50 == 0) {attack_y[i][j][k] -= 0.05f;}//子弹消失if (attack_y[i][j][k] < -2.5f) {isAttack[i][j][k] = false;isSuccess[i][j][k] = false;}}}}}//绘制飞船glPushMatrix();glTranslatef(pos_x, -2.3f, 1.0f);glScalef(0.8, 0.7, 0);drawRect(texture[2]);glPopMatrix();//取消设置深度缓存为只读glDepthMask(GL_TRUE);//控制随机生成飞机if (count >= 150) {count = 0;for (int i = 1; i < 25; i++) {pos[i - 1] = pos[i];}pos[24] = pos_x;count2++;if (count2 == 5 || count2 == 10) {for (int i = 0; i < 6; i++) {for (int j = 0; j < 3; j++) {if (isShip[i][j]) {for (int k = 0; k < 3; k++) {//控制飞机开始发射子弹if (isAttack[i][j][k] == false) {isAttack[i][j][k] = true;attack_x[i][j][k] = move_x[i][j];attack_y[i][j][k] = move_y[i];break;}}}}}}if (count2 == 10) {count2 = 0;int num = rand() % 6;for (int i = 0; i < 3; i++) {//找到可以生成飞机的位置if (isShip[num][i] == false) {bool flag = false;//保证飞机从左右发射时不相撞,在同一行已经有飞机的时候,和已有飞机方向相同for (int j = 0; j < 3; j++) {if (isShip[num][j] == true) {flag = true;isLeft[num][i] = isLeft[num][j];break;}}//同一行不存在飞机的时候,随机生成飞机产生方向if (!flag) {isLeft[num][i] = rand() % 2;}isShip[num][i] = true;//随机生成飞机种类int random = rand() % 3;if (random == 0) {shipType[num][i] = 1;}else shipType[num][i] = 3;//初始化操作collisionTimes[num][i] = 0;if(isLeft[num][i])move_x[num][i] = -3.0f;else move_x[num][i] = 3.0f;break;}}}}else count++;
}void updateView(int height, int width)
{glViewport(0, 0, width, height);glMatrixMode(GL_PROJECTION);//设置矩阵模式为投影       glLoadIdentity();   //初始化矩阵为单位矩阵          whRatio = (GLfloat)width / (GLfloat)height;  //设置显示比例     glOrtho(-3, 3, -3, 3, -100, 100); //正投影glMatrixMode(GL_MODELVIEW);  //设置矩阵模式为模型
}void reshape(int width, int height)
{if (height == 0)      //如果高度为0      {height = 1;   //让高度为1(避免出现分母为0的现象)      }wHeight = height;wWidth = width;updateView(wHeight, wWidth); //更新视角
}void idle()
{glutPostRedisplay();
}void init()
{srand(unsigned(time(NULL)));glEnable(GL_DEPTH_TEST);//开启深度测试   glEnable(GL_ALPHA_TEST);//开启alpha测试glAlphaFunc(GL_GREATER, 0.1);glEnable(GL_LIGHTING);  //开启光照模式   glClearColor(1.0f, 1.0f, 1.0f,1.0f);memset(pos, -10.0f, sizeof(pos));glGenTextures(4, texture);loadTex(0, "1.bmp", texture);loadTex_alpha(1, "ship3.bmp", texture);loadTex_alpha(2, "ship.bmp", texture);loadTex_alpha(3, "ship2.bmp", texture);pos_y[0][0] = 2.9f;pos_y[0][1] = 2.9f + 0.66f;pos_y[0][2] = 2.9f + 0.132f;for (int i = 0; i < 3; i++) {for (int j = 1; j < 25; j++) {pos_y[j][i] = pos_y[j-1][i]-0.2f;}}memset(isShip, false, sizeof(isShip));memset(isAttack, false, sizeof(isAttack));isShip[0][0] = true;shipType[0][0] = 3;move_x[0][0] = 3.0f;}void key(unsigned char k, int x, int y)
{switch (k){case 'a': {pos_x -= 0.05f;if (pos_x < -2.90f)pos_x = -2.90f;break;}case 'd':{pos_x += 0.05f;if (pos_x > 2.90f)pos_x = 2.90f;break;}}updateView(wHeight, wWidth); //更新视角
}void redraw()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓存    glMatrixMode(GL_MODELVIEW);glLoadIdentity();   //初始化矩阵为单位矩阵      gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0);                // 场景(0,0,0)的视点中心 (0,5,50),Y轴向上  glPolygonMode(GL_FRONT, GL_FILL);glFrontFace(GL_CCW);glEnable(GL_CULL_FACE);// 启用光照计算glEnable(GL_LIGHTING);// 指定环境光强度(RGBA)GLfloat ambientLight[] = { 2.0f, 2.0f, 2.0f, 1.0f };// 设置光照模型,将ambientLight所指定的RGBA强度值应用到环境光glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);// 启用颜色追踪glEnable(GL_COLOR_MATERIAL);// 设置多边形正面的环境光和散射光材料属性,追踪glColorglColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);drawScene();//绘制场景   printData();glutSwapBuffers();//交换缓冲区
}int main(int argc, char *argv[])
{glutInit(&argc, argv);//对glut的初始化         glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);//初始化显示模式:RGB颜色模型,深度测试,双缓冲           glutInitWindowSize(800, 600);//设置窗口大小         int windowHandle = glutCreateWindow("Simple GLUT App");//设置窗口标题           glutDisplayFunc(redraw); //注册绘制回调函数         glutReshapeFunc(reshape);   //注册重绘回调函数         glutKeyboardFunc(key); //注册按键回调函数glutIdleFunc(idle);//注册全局回调函数:空闲时调用       init();glutMainLoop();  // glut事件处理循环       return 0;
}

图片资源

ship.bmp

ship2.bmp

ship3.bmp

[OpenGL] 小游戏 - 太空对战相关推荐

  1. 腾讯云为小游戏开发者升级工具箱 小游戏联机对战引擎免费用

    由微信小游戏举办的"微信小游戏创意大赛"正在火热进行中.12月23日,腾讯云宣布,除了给参赛者提供基础云资源,还将提供更多工具支持.开发者在通过初赛后,可免费使用腾讯云" ...

  2. 怎么开发联机小游戏_微信小游戏创意大赛火热进行中,小游戏联机对战引擎免费用...

    腾讯云为小游戏开发者升级工具箱 小游戏联机对战引擎免费用 由微信小游戏举办的"微信小游戏创意大赛"正在火热进行中.12月23日,腾讯云宣布,除了给创意大赛的参赛者提供基础云资源,还 ...

  3. [转载]腾讯云大学大咖分享 |小游戏联机对战引擎实践(含源码)

    一个高效率的学习安排,应该是:10%时间,了解行业和技术的发展动态:40%的时间,看教程和慕课:30%的时间,看别人写的代码样例.这三件事做完,最后20%时间再动手编程.看资料和教程,占多数时间.资料 ...

  4. H5互动游戏平台推荐:盘点那些超火的多人小游戏互动对战平台

    虽然是个妹子,但我超有游戏天赋呦!还记得我和表哥在小时候经常在家里用世嘉.ps等主机联机玩幽游白书.魂斗罗的日子,那份美好变成了我们这代人童年最宝贵的记忆,不管是对战的互相嘲讽还是与好友一同通关的瞬间 ...

  5. 【Unity3D开发小游戏】《战棋小游戏》Unity开发教程

    一.前言 这次想要做的一个小游戏,或者说一个小Demo,其实是一个简单且传统的战棋战斗场景.初步的设计是:在2D世界里创建一张由六边形地块组成的战斗地图,敌我双方依据体力在地图上轮流行动并向对方发动攻 ...

  6. python制作射击游戏_零基础用Python开发的第一个小游戏——太空射击

    写在最前面 你想成为Python高手吗?你想使用Python编写一个炫酷的游戏吗? 那么今天这篇文章就能带着你从零开始编写一个Python小游戏.希望你能喜欢. 话不多说,我们先来看一副动图 ​ 号: ...

  7. java 集合小游戏 ->武将对战V1.0.0(待完善...)

    集合文字小游戏 -> 武将对战 1. 项目需求 2. 需求分析 2.1 建立一个武将对象(编号,姓名,所属地,性别出生年,去世年,武力值) 2.2 获取字符串类型的武将数据 2.3 拆分武将数据 ...

  8. 前端答题小游戏_这是什么神奇操作!两个前端一周上线一款联机小游戏

    这是一款在一周之内完成立项到上线的防疫知识对战小游戏,你玩过吗? 一起来战疫 它在上线四小时内用户数激增60倍,获得新华社力荐,开发过程中仅投入2个前端开发+1个美术+1个策划,这款小游戏里,单机玩法 ...

  9. 单机小游戏变多人联机,原来只需要几分钟!

    | 导语 8月17日,"小程序·云开发"系列沙龙(小游戏专场)圆满落幕.本期沙龙云+社区携手微信 & 云开发官方团队为大家揭秘爆款微信小游戏背后的技术,全面讲解小程序·云开 ...

最新文章

  1. 网络爬虫-python-爬取天涯求职贴
  2. 处理接口超时_架构设计|异步请求如何同步处理?
  3. Djago模型层(基础)
  4. 嵌入式操作系统内核原理和开发(等值block内存池设计)
  5. mybatis mysql 模糊查询语句_mybatis+Spring mysql的模糊查询问题
  6. 【bzoj3000】Big Number 【斯特林公式】
  7. Thingsboard 3.1.0 - REST API
  8. C#窗体标准计算器(上) 初级新手请多担待。
  9. git add未commit reset恢复文件
  10. 什么是标签?跟数据中台有什么关系?
  11. 正在升级android s8,国行版三星S8/S8+再添新操作 升级安卓8.0
  12. GCA matting(2020, trimap)
  13. 【Android 基础知识】翻页类视图 ViewPager
  14. 南安普顿大学计算机专业如何,南安普顿大学计算机专业,南安最值得读的专业之一!...
  15. 泰坦尼克号 机器学习_机器学习项目泰坦尼克号问题陈述
  16. Nodejs Addons
  17. 电脑桌面有HTML一直删除不了,程序员电脑桌面是什么样的? 网友: IE浏览器必删, 不能留!...
  18. 儿子读书成绩不好能学计算机专业吗,我的儿子十七岁了,学习成绩不好,也不爱念书,整天就是玩电脑和手机,我想让他学点儿技术不知道学什么适...
  19. 如何制订一个有效的内部规范
  20. Git Github Tips

热门文章

  1. Nginx编译安装与配置
  2. 边框圆角化方式(原文链接http://www.cnblogs.com/SJP666/p/4678730.html)
  3. codeforces 332B B. Maximum Absurdity(rmq)
  4. KSImageNamed 安装后无效解决方法
  5. HTML中图片轮播效果
  6. linux系统fflush函数
  7. JavaBean 与 POJO
  8. Nutch 分布式运行模式 (v1.14)
  9. 计算机打印unknow,系统安装打印机驱动提示unknown device解决方法
  10. HTML5+CSS3小实例:简约不简单的社交分享按钮