Game.cpp
上传用户:lygtks
上传日期:2022-06-08
资源大小:874k
文件大小:15k
源码类别:

射击游戏

开发平台:

Visual C++

  1. //在此处定义WINDOW头文件
  2. #include <windows.h> // Windows 头文件
  3. #include <stdio.h>
  4. //在此处引用程序要求的附加头文件:
  5. #include <glgl.h> // OpenGL32库的头文件
  6. #include <glglu.h> // Glu32库的头文件
  7. //在此处引用本程序的头文件
  8. #include "5DG_Window.h" // 框架文件
  9. #include "Class.h" // 类头文件
  10. #include "Fmod.h" // 音频库头文件
  11. #include "Texture.h" // 纹理导入头文件
  12. //在此处加入程序要求的库到链接器中:
  13. #pragma comment(lib, "opengl32.lib")
  14. #pragma comment(lib, "glu32.lib")
  15. #pragma comment(lib, "fmodvc.lib")
  16. //在此处定义WINDOWS全局变量:
  17. GL_Window* OGL_window;
  18. Keys* OGL_keys;
  19. //在此处定义用户变量:
  20. TextureTga playertex[3]; // 纹理数组,保存纹理名字
  21. TextureTga  computertex[3];
  22. TextureTga ammunitiontex[4];
  23. TextureTga awardtex[3];
  24. TextureTga othertex[4];
  25. GLuint base; // 输出字体的显示列表号
  26. bool start; // 该值为真,表示游戏开始
  27. bool startp; // 辅助控制start,以免按住时不断轮换
  28. bool end; // 该值为真,表示游戏结束
  29. bool keybombp; // 控制炸弹发射用的布尔值,以保证按住不放时也只能发射一个炸弹
  30. bool keyfirep; // 控制子弹发射声音的布尔值,以保证不会产生叠音
  31. int myPlaneNum; // 玩家目前余下的飞机数目
  32. DWORD lastTickCount=0; // 运行到上一帧的时间点,用于求帧间隔时间
  33. DWORD tickCount=0; // 运行到当前帧的时间点,用于求帧间隔时间
  34. int  timer=0; // 这一帧的运行时间
  35. DWORD endtime; // 结束动画的起始时间
  36. DWORD starttime; // 用于控制片头动画的显示时间
  37. FSOUND_SAMPLE *sound_1; // 发射子弹的声音指针
  38. FSOUND_SAMPLE *sound_2; // 射击中的声音指针
  39. FSOUND_SAMPLE *sound_3; // 遇到物品的声音指针
  40. FMUSIC_MODULE *sound_4; // 游戏的背影音乐指针
  41. float groudMove=0; // 控制背影不断向下移动的变量
  42. float startQuadOffset; // 控制片头动画移动的变量
  43. PlayerPlane myPlane; // 玩家飞机
  44. ComputerPlane computers[MAX_COMPUTER]; // 电脑飞机数组
  45. Award awards[MAX_AWARD]; // 物品数组
  46. Ammunition ammunitions[MAX_AMMUNITION]; // 子弹数组
  47. // 设置时钟
  48. void setTimer()
  49. {
  50. lastTickCount=tickCount;
  51. tickCount=GetTickCount();
  52. timer=tickCount-lastTickCount; // 得到每帧的运行时间
  53. }
  54. // 游戏初始化
  55. void GameInit(void)
  56. {
  57. int i;
  58. for(i=0; i<MAX_AMMUNITION; i++){ // 清除全部子弹
  59. ammunitions[i].setLife(0); // 将全部子弹无效
  60. ammunitions[i].setExplosible(false); // 并且不让爆炸
  61. }
  62. for(i=0; i<MAX_AWARD; i++){ // 清除全部物品
  63. awards[i].setLife(0); // 将全部物品无效
  64. }
  65. for (i=0; i<MAX_COMPUTER; i++) // 对所有电脑飞机进行初始化设置
  66. computers[i].compinit();
  67. myPlane.initPlane(0,-230,100,2); // 对玩家飞机初始化设置
  68. myPlaneNum=MAX_PLAYER; // 设置玩家飞机个数
  69. starttime=0; // 辅助控制游戏开始片头的播放时间
  70. startQuadOffset=0; // 辅助控制游戏开始片头移动距离
  71. }
  72. // 声音初始化
  73. GLvoid InitFMOD(GLvoid)
  74. {
  75. if (FSOUND_Init(44100, 32, 0)) // 把声音初始化为44khz
  76. {
  77. sound_1=FSOUND_Sample_Load(5, "Data/fire.wav", FSOUND_LOOP_NORMAL, 0);
  78. sound_2=FSOUND_Sample_Load(FSOUND_FREE, "Data/hitTheTarget.wav", FSOUND_2D, 0);
  79. sound_3=FSOUND_Sample_Load(FSOUND_FREE, "Data/eat.wav", FSOUND_2D, 0);
  80. sound_4=FMUSIC_LoadSong("Data/bg.mid");
  81. }
  82. }
  83. // 声音释放
  84. GLvoid FreeFMOD(GLvoid)
  85. {
  86. if(sound_1) FSOUND_Sample_Free(sound_1);
  87. if(sound_2) FSOUND_Sample_Free(sound_2);
  88. if(sound_3) FSOUND_Sample_Free(sound_3);
  89. if(sound_4) FMUSIC_FreeSong(sound_4);
  90. }
  91. // 输出字体
  92. void BuildFontGL(GLvoid) // 建立位图字体(Bitmap Fonts)
  93. {
  94. HFONT newFont; // 用以保存新的字体对象
  95. HFONT oldFont; // 用以保存原字体对象
  96. base = glGenLists(256); // 存储256个字符
  97. newFont = CreateFont( -18, // 字体的高度
  98. 0, // 字体的宽度
  99. 0, // 旋转的角度
  100. 0, // 定位角度
  101. FW_THIN, // 字体的粗细
  102. FALSE, // 斜体?
  103. FALSE, // 下划线?
  104. FALSE, // 删除线?
  105. ANSI_CHARSET, // 字符集
  106. OUT_TT_PRECIS, // 输出精度
  107. CLIP_DEFAULT_PRECIS, // 裁减精度
  108. ANTIALIASED_QUALITY, // 输出质量
  109. FF_DONTCARE|DEFAULT_PITCH, // 间距和字体族
  110. "Tahoma"); // 字体名称
  111. oldFont = (HFONT)SelectObject(OGL_window->hDC, newFont);  // 选进设备描述表 
  112. wglUseFontBitmaps(OGL_window->hDC, 0, 256, base); // 建立256个字符
  113. SelectObject(OGL_window->hDC, oldFont); // 恢复设备描述表
  114. DeleteObject(newFont); // 删除新字体
  115. }
  116. GLvoid KillFontGL(GLvoid) // 删除保存字体的显示表
  117. {
  118. glDeleteLists(base, 256); // 删除256个字符
  119. }
  120. GLvoid glPrint(const char *fmt, ...) // 建立Print函数
  121. {
  122. char text[256]; // 用以保存格式化后的字符串
  123. va_list ap; // 指向参数列表的指针
  124. if (fmt == NULL) // 没有可输出的字符?
  125. return; // 返回
  126. va_start(ap, fmt); // 遍历字符串,查找变量
  127. vsprintf(text, fmt, ap); // 将变量转换为显示的数字
  128. va_end(ap); // 结果保存在text内
  129. glPushAttrib(GL_LIST_BIT); // 显示表状态入栈
  130. glListBase(base); // 显示表偏移量
  131. glCallLists((int)strlen(text), GL_UNSIGNED_BYTE, text); // 绘制字符串
  132. glPopAttrib(); // 显示表状态出栈
  133. }
  134. // 载入所需纹理
  135. void LoadTexture(void)
  136. {
  137. BuildTexture("Data/Playercenter.tga", &playertex[0]);
  138. BuildTexture("Data/Playerleft.tga", &playertex[1]);
  139. BuildTexture("Data/Playerright.tga", &playertex[2]);
  140. BuildTexture("Data/Computer1.tga", &computertex[0]);
  141. BuildTexture("Data/Computer2.tga", &computertex[1]);
  142. BuildTexture("Data/Computer3.tga", &computertex[2]);
  143. BuildTexture("Data/Award1.tga", &awardtex[0]);
  144. BuildTexture("Data/Award2.tga", &awardtex[1]);
  145. BuildTexture("Data/Award3.tga", &awardtex[2]);
  146. BuildTexture("Data/Ball.tga", &ammunitiontex[0]);
  147. BuildTexture("Data/Heavyball.tga", &ammunitiontex[1]);
  148. BuildTexture("Data/Missile.tga", &ammunitiontex[3]);
  149. BuildTexture("Data/Groud1.tga", &othertex[0]);
  150. BuildTexture("Data/Groud2.tga", &othertex[1]);
  151. BuildTexture("Data/Planeexplode.tga", &othertex[2]);
  152. BuildTexture("Data/Ballexplode.tga", &othertex[3]);
  153. }
  154. // OpenGL初始化
  155. BOOL Initialize(GL_Window* window, Keys* keys)
  156. {
  157. // 设置全局变量
  158. OGL_window = window;
  159. OGL_keys = keys;
  160. glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 清屏为黑色
  161. glClearDepth(1.0f); // 设置深度缓存
  162. glDepthFunc(GL_LEQUAL); // 选择深度测试方式
  163. glEnable(GL_DEPTH_TEST); // 开启深度测试
  164. glShadeModel(GL_SMOOTH); // 阴暗处理采用平滑方式
  165. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 最精细的透视计算
  166. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  167. LoadTexture(); // 调用载入纹理函数
  168. BuildFontGL(); // 调用初始化字体函数
  169. InitFMOD(); // 调用初始化声音函数
  170. return TRUE; // 初始化成功返回TRUE
  171. }
  172. // 游戏背景绘制
  173. void Background(void)
  174. {
  175. glEnable(GL_TEXTURE_2D);
  176. // 左右两个始终存在的方框
  177. glPushMatrix();
  178. glTranslatef(250.0f, 0.0f, 10.0f);
  179. glBindTexture(GL_TEXTURE_2D,othertex[0].texID);
  180. glBegin(GL_QUADS);
  181. glTexCoord2i(0,  0);glVertex2i(  0, -300);
  182. glTexCoord2i(4,  0);glVertex2i(150, -300);
  183. glTexCoord2i(4, 10);glVertex2i(150,  300);
  184. glTexCoord2i(0, 10);glVertex2i(  0,  300);
  185. glEnd();
  186. glPopMatrix();
  187. glPushMatrix();
  188. glTranslatef(-250.0f, 0.0f, 10.0f);
  189. glBegin(GL_QUADS);
  190. glTexCoord2i(0, 0);glVertex2i(-150, -300);
  191. glTexCoord2i(4, 0);glVertex2i(   0, -300);
  192. glTexCoord2i(4,10);glVertex2i(   0,  300);
  193. glTexCoord2i(0,10);glVertex2i(-150,  300);
  194. glEnd();
  195. glPopMatrix();
  196. // 中央移动的星空背景
  197. glPushMatrix();
  198. glTranslatef(0.0f, 0.0f,-50.0f);
  199. glBindTexture(GL_TEXTURE_2D, othertex[1].texID);
  200. glBegin(GL_QUADS);
  201. glTexCoord2f(0.0f, 0.0f+groudMove);  glVertex2i(-250,-300);
  202. glTexCoord2f(2.0f, 0.0f+groudMove);  glVertex2i( 250,-300);
  203. glTexCoord2f(2.0f, 2.0f+groudMove);  glVertex2i( 250, 300);
  204. glTexCoord2f(0.0f, 2.0f+groudMove);  glVertex2i(-250, 300);
  205. glEnd();
  206. glPopMatrix();
  207. groudMove+=0.0001f*timer;
  208. glDisable(GL_TEXTURE_2D);
  209. }
  210. // 游戏未开始的场景绘制
  211. void Opening(void)
  212. {
  213. glRasterPos2f(-200.0f, 100.0f);
  214. glPrint("Press F5 to start a new game!");
  215. glRasterPos2f(-200.0f, 0.0f);
  216. glPrint(" Direction : W,S,A,D ");
  217. glRasterPos2f(-200.0f, -20.0f);
  218. glPrint(" Fire : J ; Missile: K");
  219. glRasterPos2f(-200.0f, -100.0f);
  220. int winscore=WIN_SCORE;
  221. glPrint("Mission : Earn %d Score! ", winscore);
  222. }
  223. // 开始游戏的主场景
  224. void Running(void)
  225. {
  226. int i;
  227. // 片头播放(播放时间4000ms)
  228. if(starttime<4000){
  229. starttime += timer;
  230. startp=true; // 禁用F5
  231. if(starttime<2000)
  232. startQuadOffset += 0.16f*timer;
  233. else
  234. startQuadOffset -= 0.16f*timer;
  235. // 下面的移动方块
  236. glPushMatrix();
  237. glTranslatef(0.0f,-300.0f,-20.0f);
  238. glTranslatef(0.0f, startQuadOffset, 0.0f);
  239. glBindTexture(GL_TEXTURE_2D, othertex[0].texID);
  240. glEnable(GL_TEXTURE_2D);
  241. glBegin(GL_QUADS);
  242. glTexCoord2i(0, 0);glVertex2i(-250,-320);
  243. glTexCoord2i(2, 0);glVertex2i( 250,-320);
  244. glTexCoord2i(2, 2);glVertex2i( 250,   0);
  245. glTexCoord2i(0, 2);glVertex2i(-250,   0);
  246. glEnd();
  247. glDisable(GL_TEXTURE_2D);
  248. glPopMatrix();
  249. // 上面的移动方块
  250. glPushMatrix();
  251. glTranslatef(0.0f, 300.0f,-20.0f);
  252. glTranslatef(0.0f,-startQuadOffset, 0.0f);
  253. glBindTexture(GL_TEXTURE_2D, othertex[0].texID);
  254. glEnable(GL_TEXTURE_2D);
  255. glBegin(GL_QUADS);
  256. glTexCoord2i(0, 0);glVertex2i(-250,   0);
  257. glTexCoord2i(2, 0);glVertex2i( 250,   0);
  258. glTexCoord2i(2, 2);glVertex2i( 250, 320);
  259. glTexCoord2i(0, 2);glVertex2i(-250, 320);
  260. glEnd();
  261. glDisable(GL_TEXTURE_2D);
  262. glPopMatrix();
  263. return;
  264. }
  265. startp=false;
  266. glEnable(GL_BLEND); // 开启透明,将边角透明掉
  267. // 电脑的飞机处理
  268. for(i=0; i<MAX_COMPUTER; i++){
  269. computers[i].move();
  270. computers[i].fire();
  271. computers[i].draw();
  272. computers[i].blast();
  273. computers[i].update();
  274. }
  275. // 子弹处理
  276. for(i=0; i<MAX_AMMUNITION; i++){
  277. ammunitions[i].move ();
  278. ammunitions[i].draw ();
  279. ammunitions[i].blast();
  280. }
  281. // 物品处理
  282. for(i=0; i<MAX_AWARD; i++){
  283. awards[i].move();
  284. awards[i].draw();
  285. awards[i].eat();
  286. }
  287. // 玩家飞机处理
  288. // 飞机移动
  289. if(OGL_keys->keyDown['W']==TRUE)
  290. myPlane.moveUp();
  291. else if(OGL_keys->keyDown['S']==TRUE)
  292. myPlane.moveDown ();
  293. if(OGL_keys->keyDown['A']==TRUE)
  294. myPlane.moveLeft ();
  295. else if(OGL_keys->keyDown['D']==TRUE)
  296. myPlane.moveRight ();
  297. else
  298. myPlane.stay();
  299. // 飞机发射子弹
  300. if(OGL_keys->keyDown['J']==TRUE){
  301. myPlane.fire();
  302. if(!keyfirep){
  303. FSOUND_PlaySound(5,sound_1);
  304. keyfirep=true;
  305. }
  306. }
  307. if(OGL_keys->keyDown['J']==FALSE || myPlaneNum<=0){
  308. keyfirep=false;
  309. FSOUND_StopSound(5);
  310. }
  311. // 飞机发射炸弹
  312. if(OGL_keys->keyDown['K']==TRUE && !keybombp){
  313. myPlane.fireBomb();
  314. keybombp=true;
  315. }
  316. if(OGL_keys->keyDown['K']==FALSE)
  317. keybombp=false;
  318. myPlane.draw(); // 飞机绘制
  319. myPlane.hitcomPlane(); // 飞机与敌机的碰撞检测
  320. myPlane.blast(); // 飞机的爆炸处理
  321. myPlane.update(); // 飞机的更新处理
  322. glDisable(GL_BLEND); // 绘制完毕,关闭透明
  323. // 显示玩家分数
  324. glPushMatrix();
  325. glRasterPos3f(140.0f,-285.0f,10.0);
  326. glPrint("score:%.2f", (float)myPlane.getScore());
  327. glPopMatrix();
  328. // 显示玩家的飞机数
  329. glPushMatrix();
  330. glColor3f(1.0f, 1.0f, 1.0f);
  331. glTranslatef(240.0f,-265.0f, 0.0);
  332. glEnable(GL_TEXTURE_2D);
  333. glBindTexture(GL_TEXTURE_2D, playertex[0].texID);
  334. for(i=1; i<=myPlaneNum; i++){
  335. glTranslatef(-20.0f, 0.0f, 0.0f);
  336. glBegin(GL_QUADS);
  337. glTexCoord2i(0, 0); glVertex2i(-10,-10);
  338. glTexCoord2i(1, 0); glVertex2i( 10,-10);
  339. glTexCoord2i(1, 1); glVertex2i( 10, 10);
  340. glTexCoord2i(0, 1); glVertex2i(-10, 10);
  341. glEnd();
  342. }
  343. glDisable(GL_TEXTURE_2D);
  344. glColor3f(1.0f, 1.0f, 1.0f);
  345. glPopMatrix();
  346. // 显示玩家持有的炸弹个数
  347. glPushMatrix();
  348. glTranslatef(-230.0f,-265.0f,0.0);
  349. glColor3f(1.0f, 1.0f, 1.0f);
  350. glEnable(GL_TEXTURE_2D);
  351. glBindTexture(GL_TEXTURE_2D, ammunitiontex[3].texID);
  352. for(i=1; i<=myPlane.getBombNum(); i++){
  353. glTranslatef(20.0f, 0.0f, 0.0);
  354. glBegin(GL_QUADS);
  355. glTexCoord2i(0, 0); glVertex2i(-10,-10);
  356. glTexCoord2i(1, 0); glVertex2i( 10,-10);
  357. glTexCoord2i(1, 1); glVertex2i( 10, 10);
  358. glTexCoord2i(0, 1); glVertex2i(-10, 10);
  359. glEnd();
  360. }
  361. glDisable(GL_TEXTURE_2D);
  362. glColor3f(1.0f, 1.0f, 1.0f);
  363. glPopMatrix();
  364. // 显示玩家飞机的生命长度
  365. // 表示生命的矩形前的飞机图标
  366. glPushMatrix();
  367. glTranslatef(-240.0f,-290.0f, 0.0f);
  368. glColor3f(1.0f, 1.0f, 1.0f);
  369. glEnable(GL_TEXTURE_2D);
  370. glBindTexture(GL_TEXTURE_2D, playertex[0].texID);
  371. glBegin(GL_QUADS);
  372. glTexCoord2i(0, 0); glVertex2i(-10,-10);
  373. glTexCoord2i(1, 0); glVertex2i( 10,-10);
  374. glTexCoord2i(1, 1); glVertex2i( 10, 10);
  375. glTexCoord2i(0, 1); glVertex2i(-10, 10);
  376. glEnd();
  377. glDisable(GL_TEXTURE_2D);
  378. glColor3f(1.0f, 1.0f, 1.0f);
  379. glPopMatrix();
  380. // 矩形长度表示生命的长短
  381. glPushMatrix();
  382. glTranslatef(-230.0f,-290.0f, 0.0f);
  383. glColor3f(1.0f, 0.0f, 0.0f);
  384. glBegin(GL_QUADS);
  385. glVertex2f(0.0f,-5.0f);
  386. glVertex2f(myPlane.getLife(),-5.0f);
  387. glVertex2f(myPlane.getLife(), 5.0f);
  388. glVertex2f(0.0f, 5.0f);
  389. glEnd();
  390. glColor3f(1.0f, 1.0f, 1.0f);
  391. glPopMatrix();
  392. }
  393. // 游戏结束函数
  394. void Ending(void)
  395. {
  396. FSOUND_StopSound(5); // 停止播放枪声
  397. FMUSIC_StopSong(sound_4);
  398. keyfirep=false;
  399. if(myPlane.getScore()<WIN_SCORE){ // 分数不够,游戏失败
  400. if(GetTickCount()-endtime<2000){ // 游戏结束后2s内显示
  401. startp=true; // 禁用F5
  402. glRasterPos3f(-200.0f, 100.0f,-20.0f);
  403. glPrint("Final Score:  %d!", myPlane.getScore());
  404. glRasterPos3f(-200.0f,-100.0f,-20.0f);
  405. glPrint("You Lost!! Try Again!!");
  406. }else{
  407. start=false;
  408. startp=false;
  409. end=false;
  410. }
  411. }else{ // 分数达到,游戏胜利
  412. if(GetTickCount()-endtime<2000){ // 游戏结束后2s内显示
  413. startp=true; // 禁用F5
  414. glRasterPos3f(-200.0f, 100.0f,-20.0f);
  415. glPrint("Congratulations!!");
  416. glRasterPos3f(-200.0f,-100.0f,-20.0f);
  417. glPrint("YOU WIN!!");
  418. }else{
  419. start=false;
  420. startp=false;
  421. end=false;
  422. }
  423. }
  424. }
  425. // 绘制的主场景
  426. void DrawSceneGL(void)
  427. {
  428. setTimer(); // 取得每帧的运行时间
  429. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  430. glLoadIdentity();
  431. Background(); // 绘制背景
  432. if(!start){ // 游戏尚未开始
  433. Opening(); // 调用游戏还未开始显示的内容函数
  434. }else{
  435. if(!end){ // 游戏开始且末结束
  436. Running(); // 调用游戏运行的主函数
  437. }else{ // 游戏运行结束
  438. Ending(); // 调用游戏结束的处理函数
  439. }
  440. }
  441. glFlush();
  442. }
  443. // 更新对消息的动作
  444. void Update(void)
  445. {
  446. if (OGL_keys->keyDown[VK_ESCAPE] == TRUE) // 判断ESC键是否按下
  447. {
  448. TerminateApplication (OGL_window); // 结束程序
  449. }
  450. if (OGL_keys->keyDown[VK_F1] == TRUE) // 判断F1是否按下
  451. {
  452. PostMessage (OGL_window->hWnd, WM_TOGGLEFULLSCREEN, 0, 0); // 在全屏/窗口模式间切换
  453. }
  454. // 对F5按键的处理,用于控制游戏开始
  455. if(OGL_keys->keyDown[VK_F5] == TRUE&&!startp){
  456. start=!start;
  457. startp=true;
  458. if(start){
  459. FMUSIC_PlaySong(sound_4);
  460. GameInit(); // 调用游戏初始化设置函数
  461. }else{
  462. FMUSIC_StopSong(sound_4);
  463. }
  464. }
  465. if(OGL_keys->keyDown[VK_F5] == FALSE)
  466. startp=false;
  467. }
  468. // 退出前扫尾工作
  469. void Deinitialize(void)
  470. {
  471. KillFontGL();
  472. FreeFMOD();
  473. }