目录
一、知识点总结
第四章
4.2多球反弹
4.3实时钟表
4.5鼠标交互的消砖块
第五章 图片和声音素材在游戏的应用
二、代码实现
第五章
5.1flappy bird
5.2飞机大战
5.3复杂动画效果
5.4双人反弹球
一、知识点总结
第四章 绘图游戏开发
1 4.2多球反弹 2 多球反弹,不仅要判断多球与墙壁是否碰撞,还要判断球与球是否碰撞。球球碰撞的实现方法是:记录离每个球最近的球,判断球距(球心与球心)是否大于两倍半径。
公式为(x1-x2)2+(y1-y2)2<=4r2 碰撞后速度交换。 3 float minDistances2[BallNum][2]; // 记录某个小球,距离它最近的小球的距离,这个小球的下标 4 for (i=0;i<BallNum;i++) 5 { 6 minDistances2[i][0] = 9999999; 7 minDistances2[i][1] = -1; 8 } 9 10 // 求解所有小球两两之间的距离平方 11 for (i=0;i<BallNum;i++) 12 { 13 for (j=0;j<BallNum;j++) 14 { 15 if (i!=j) // 自己和自己不需要比 16 { 17 float dist2; 18 dist2 = (ball_x[i] - ball_x[j])*(ball_x[i] - ball_x[j]) 19 + (ball_y[i] - ball_y[j])*(ball_y[i] - ball_y[j]); 20 if (dist2<minDistances2[i][0]) 21 { 22 minDistances2[i][0] = dist2; 23 minDistances2[i][1] = j; 24 } 25 } 26 } 27 } 28 29 // 判断球之间是否碰撞 30 for (i=0;i<BallNum;i++) 31 { 32 if (minDistances2[i][0]<=4*radius*radius) // 最小距离小于阈值,发生碰撞 33 { 34 j = minDistances2[i][1]; 35 // 交换速度 36 int temp; 37 temp = ball_vx[i]; ball_vx[i] = ball_vx[j]; ball_vx[j] = temp; 38 temp = ball_vy[i]; ball_vy[i] = ball_vy[j]; ball_vy[j] = temp; 39 40 minDistances2[j][0] = 999999999; // 避免交换两次速度,又回去了 41 minDistances2[j][1] = -1; 42 } 43 } 44 45 4.3实时钟表 46 表盘上写文本 47 outtextxy(center_x - 25, center_y + Width/6, "我的时钟"); 48 49 重点:获取电脑时间,并显示在表盘上 50 SYSTEMTIME ti; // 定义变量保存当前时间 51 GetLocalTime(&ti); // 获取当前时间 52 // 秒钟角度变化 53 secondAngle = ti.wSecond * 2*PI/60; // 一圈一共2*PI,一圈60秒,一秒钟秒钟走过的角度为2*PI/60 54 // 由角度决定的秒针端点坐标,用到三角函数,需要引入#include <math.h> 55 secondEnd_x = center_x + secondLength*sin(secondAngle); 56 secondEnd_y = center_y - secondLength*cos(secondAngle); 57 58 可以用于日期的比较: 59 SYSTEMTIME st1,st2; 60 GetSystemTime(&st1); 61 GetSystemTime(&st2); 62 int re=memcmp(&st1,&st2,sizeof(SYSTEMTIME)); 63 一条秒针的绘制,和隐藏 64 setlinestyle(PS_SOLID, 2); 65 setcolor(YELLOW); 66 line(center_x, center_y, secondEnd_x, secondEnd_y); // 画秒针 67 68 setcolor(BLACK); 69 setlinestyle(PS_SOLID, 2); 70 line(center_x, center_y, secondEnd_x, secondEnd_y); // 隐藏前一帧的秒针
1 #include <graphics.h> 2 #include <conio.h> 3 #include <math.h> 4 5 #define High 480 // 游戏画面尺寸 6 #define Width 640 7 #define PI 3.14159 8 9 int main() 10 { 11 initgraph(Width, High); // 初始化 640 x 480 的绘图窗口 12 int center_x,center_y; // 中心点的坐标,也是表的中心 13 center_x = Width/2; 14 center_y = High/2; 15 int secondLength = Width/5; // 秒针的长度 16 int minuteLength = Width/6; // 分针的长度 17 int hourLength = Width/7; // 时针的长度 18 19 int secondEnd_x,secondEnd_y; // 秒针的终点 20 int minuteEnd_x,minuteEnd_y; // 分针的终点 21 int hourEnd_x,hourEnd_y; // 时针的终点 22 float secondAngle; // 秒钟对应的角度 23 float minuteAngle; // 分钟对应的角度 24 float hourAngle; // 时钟对应的角度 25 26 SYSTEMTIME ti; // 定义变量保存当前时间 27 28 BeginBatchDraw(); 29 while (1) 30 { 31 // 绘制一个简单的表盘 32 setlinestyle(PS_SOLID, 1); 33 setcolor(WHITE); 34 circle(center_x, center_y, Width/4); 35 36 // 画刻度 37 int x, y,i; 38 for (i=0; i<60; i++) 39 { 40 x = center_x + int(Width/4.3 * sin(PI * 2 * i / 60)); 41 y = center_y + int(Width/4.3 * cos(PI * 2 * i / 60)); 42 43 if (i % 15 == 0) 44 bar(x - 5, y - 5, x + 5, y + 5); 45 else if (i % 5 == 0) 46 circle(x, y, 3); 47 else 48 putpixel(x, y, WHITE); 49 } 50 51 outtextxy(center_x - 25, center_y + Width/6, "我的时钟"); 52 53 GetLocalTime(&ti); // 获取当前时间 54 // 秒钟角度变化 55 secondAngle = ti.wSecond * 2*PI/60; // 一圈一共2*PI,一圈60秒,一秒钟秒钟走过的角度为2*PI/60 56 // 分钟角度变化 57 minuteAngle = ti.wMinute * 2*PI/60 + secondAngle/60; // 一圈一共2*PI,一圈60分,一分钟分钟走过的角度为2*PI/60 58 // 时钟角度变化 59 hourAngle = ti.wHour * 2*PI/12 + minuteAngle/12; // 一圈一共2*PI,一圈12小时,一小时时钟走过的角度为2*PI/12 60 // 由角度决定的秒针端点坐标 61 secondEnd_x = center_x + secondLength*sin(secondAngle); 62 secondEnd_y = center_y - secondLength*cos(secondAngle); 63 64 // 由角度决定的分针端点坐标 65 minuteEnd_x = center_x + minuteLength*sin(minuteAngle); 66 minuteEnd_y = center_y - minuteLength*cos(minuteAngle); 67 68 // 由角度决定的时针端点坐标 69 hourEnd_x = center_x + hourLength*sin(hourAngle); 70 hourEnd_y = center_y - hourLength*cos(hourAngle); 71 72 setlinestyle(PS_SOLID, 2); 73 setcolor(YELLOW); 74 line(center_x, center_y, secondEnd_x, secondEnd_y); // 画秒针 75 76 setlinestyle(PS_SOLID, 5); 77 setcolor(BLUE); 78 line(center_x, center_y, minuteEnd_x, minuteEnd_y); // 画分针 79 80 setlinestyle(PS_SOLID, 10); 81 setcolor(RED); 82 line(center_x, center_y, hourEnd_x, hourEnd_y); // 画时针 83 84 FlushBatchDraw(); 85 Sleep(10); 86 87 setcolor(BLACK); 88 setlinestyle(PS_SOLID, 2); 89 line(center_x, center_y, secondEnd_x, secondEnd_y); // 隐藏前一帧的秒针 90 setlinestyle(PS_SOLID, 5); 91 line(center_x, center_y, minuteEnd_x, minuteEnd_y); // 隐藏前一帧的分针 92 setlinestyle(PS_SOLID, 10); 93 line(center_x, center_y, hourEnd_x, hourEnd_y); // 隐藏前一帧的时针 94 } 95 96 EndBatchDraw(); 97 getch(); // 按任意键继续 98 closegraph(); // 关闭绘图窗口 99 return 0; 100 }
72 73 4.5鼠标交互的消砖块 74 75 MOUSEMSG m; // 定义鼠标消息 76 if (MouseHit()) //这个函数用于检测当前是否有鼠标消息 77 { 78 m = GetMouseMsg(); // 获取一条鼠标消息 79 if(m.uMsg == WM_MOUSEMOVE)//鼠标移动时,在鼠标位置画白点 80 { 81 putpixel(m.x,m.y,WHITE); 82 } 83 else if(m.uMsg == WM_LBUTTONDOWN)//鼠标左键按下时,画方块 84 { 85 retangle(m.x-5,m.y-5,m.x+5,m.y+5); 86 } 87 else if(m.uMsg == WM_RBUTTONUP)//鼠标右键抬起时,画圆 88 { 89 circle(m.x,m.y,10); 90 } 91 } 92 砖块和挡板的消失出现,与4.3时钟一样,绘制黑色的圆,黑色的挡板和砖
第五章 图片和声音素材在游戏的应用
1 5.1图片和声音的应用 2 图片: 3 IMAGE img_bk;//定义图片 4 loadimage(&img_bk, "D:\\background.jpg");//绝对地址读取图片 5 putimage(0, 0, &img_bk); // 在坐标(0,0)显示图片 6 遮盖图运用: 7 //用黑色的区域将白边隐藏,黑色具有变成透明 8 IMAGE img_bd1,img_bd2 9 loadimage(&img_bd1, "D:\\bird1.jpg"); 10 loadimage(&img_bd2, "D:\\bird2.jpg"); 11 putimage(bird_x, bird_y, &img_bd1,NOTSRCERASE); // 显示小鸟 12 putimage(bird_x, bird_y, &img_bd2,SRCINVERT); 13 14 声音: 15 mciSendString():使用API函数向windows发指令,播放MAP3,使用前,需要在函数外加引用Windows Multimedia API 即: 16 #pragma comment(lib,"Winmm.lib") 17 循环播放:repeat 18 mciSendString("open D:\\background.mp3 alias bkmusic", NULL, 0, NULL);//打开背景音乐 19 mciSendString("play bkmusic repeat", NULL, 0, NULL); // 循环播放 20 播放单次(多次播放时,加第一句,关闭上一次,再打开播放) 21 mciSendString("close jpmusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 22 mciSendString("open D:\\Jump.mp3 alias jpmusic", NULL, 0, NULL); // 打开跳动音乐 23 mciSendString("play jpmusic", NULL, 0, NULL); // 仅播放一次 24 25 5.2飞机大战 26 与之前C语言的飞机大战逻辑相同,只需使用EasyX的语句就行。整体逻辑如下: 27 1.首先导入图片(背景,飞机) 28 2.用遮盖图法导入飞机,使坐标位于画面中心。 29 3.加入鼠标交互代码,鼠标移动时,更新飞机坐标 30 4.导入子弹图片,加入子弹向上移动的动作,将子弹与鼠标交互结合,使子弹出现在飞机上方。起始时隐藏子弹到画面外。 31 5.导入敌机图片,加入自动下落动作,用浮点数定义速度。任意位置重新生成敌机。加判断,敌机被子弹击中消失,得分++,敌机击中飞机,显示爆炸效果,游戏结束 32 6.加音乐,初始时加背景音乐,发送子弹加发射音乐。 33 outtextxy(Width*0.48, High*0.95, "得分:");//记录得分 34 判断击中,比较简陋至今判断一个大致的距离。可以用unity的胶囊碰撞体改良。 35 if (abs(bullet_x-enemy_x)+abs(bullet_y-enemy_y) < 80) // 子弹击中敌机 36 37 鼠标交互代码:
1 if (isExpolde==0) 2 { 3 MOUSEMSG m; // 定义鼠标消息 4 while (MouseHit()) //这个函数用于检测当前是否有鼠标消息 5 { 6 m = GetMouseMsg(); 7 if(m.uMsg == WM_MOUSEMOVE) 8 { 9 // 飞机的位置等于鼠标所在的位置 10 position_x = m.x; 11 position_y = m.y; 12 } 13 else if (m.uMsg == WM_LBUTTONDOWN) 14 { 15 // 按下鼠标左键,发射子弹 16 bullet_x = position_x; 17 bullet_y = position_y-85; 18 mciSendString("close fgmusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 19 mciSendString("open D:\\f_gun.mp3 alias fgmusic", NULL, 0, NULL); // 打开音乐 20 mciSendString("play fgmusic", NULL, 0, NULL); // 仅播放一次 21 } 22 } 23 }
39 40 音效交互代码:
1 if (isExpolde==0) 2 { 3 if (bullet_y>-25) 4 bullet_y = bullet_y-2; 5 6 if (enemy_y<High-25) 7 enemy_y = enemy_y+0.5; 8 else 9 enemy_y = 10; 10 if (abs(bullet_x-enemy_x)+abs(bullet_y-enemy_y) < 80) // 子弹击中敌机 11 { 12 enemy_x = rand()%Width; 13 enemy_y = -40; 14 bullet_y = -85; 15 mciSendString("close gemusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 16 mciSendString("open D:\\gotEnemy.mp3 alias gemusic", NULL, 0, NULL); // 打开音乐 17 mciSendString("play gemusic", NULL, 0, NULL); // 仅播放一次 18 score++; 19 if (score>0 && score%5==0 && score%2!=0) 20 { 21 mciSendString("close 5music", NULL, 0, NULL); // 先把前面一次的音乐关闭 22 mciSendString("open D:\\5.mp3 alias 5music", NULL, 0, NULL); // 打开音乐 23 mciSendString("play 5music", NULL, 0, NULL); // 仅播放一次 24 } 25 if (score%10==0) 26 { 27 mciSendString("close 10music", NULL, 0, NULL); // 先把前面一次的音乐关闭 28 mciSendString("open D:\\10.mp3 alias 10music", NULL, 0, NULL); // 打开音乐 29 mciSendString("play 10music", NULL, 0, NULL); // 仅播放一次 30 } 31 } 32 33 if (abs(position_x-enemy_x)+abs(position_y-enemy_y) < 150) // 敌机击中我们 34 { 35 isExpolde = 1; 36 mciSendString("close exmusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 37 mciSendString("open D:\\explode.mp3 alias exmusic", NULL, 0, NULL); // 打开音乐 38 mciSendString("play exmusic", NULL, 0, NULL); // 仅播放一次 39 } 40 }
42 43 5.3复杂的动画效果 44 整体逻辑是:几张图片循环播放+人物整体移动 45 图片导入函数分析: 46 void putimage( 47 int dstX, //绘制位置的X坐标 48 int dstY, // 绘制位置的Y坐标 49 int dstWidth, // 绘制的宽度 50 int dstHeight, // 绘制的高度 51 IMAGE *pSrcImg, // 要绘制的IMAGE对象指针 52 int srcX, // 绘制内容在IMAGE对象中的左上角X坐标 53 int srcY, // 绘制内容在IMAGE对象中的左上角Y坐标 54 DWORD dwRop = SRCCOPY // The three-element grating operating code 55 ); 56 例如: 57 !!区别:人物在素材图中的位置 VS 在游戏画布上的整体位置 58 putimage(0,0,75,130,&img_human,0,0);//从(0,0)点开始绘制75*130大小的图,指向img_human对象,IMAGE对象的(0,0)开始 59 60 putimage(0,0,75,130,&img_human,left_i*75,0);//加入图片切割,不同的left_i*75,对应不同动作素材,可以使人物原地动起来 61 62 putimage(x,y,75,130,&img_human,left_i*75,0);//加入x,y坐标,整个图像在游戏画面中移动。 63 同时要注意需要消除上一个动画, 64 clearrectangle(x,y,x+75,y+130); // 清空画面全部矩形区域 65 66 67 实现人物移动的代码:
1 while (1) 2 { 3 if(kbhit()) // 判断是否有输入 4 { 5 input = getch(); // 根据用户的不同输入来移动,不必输入回车 6 if (input == 'a') // 左移 7 { 8 clearrectangle(x,y,x+75,y+130); // 清空画面全部矩形区域 9 left_i++; 10 if (x>60) // 没有达到左边的墙,才移动小人的坐标 11 x = x-10; 12 putimage(x,y,75,130,&img_human,left_i*75,0); 13 FlushBatchDraw(); 14 Sleep(1); 15 if (left_i==3) 16 left_i = 0; 17 } 18 else if (input == 'd') // 右移 19 { 20 clearrectangle(x,y,x+75,y+130); // 清空画面全部矩形区域 21 right_i++; 22 if (x<340) // 没有达到右边的墙,才移动小人的坐标 23 x = x+10; 24 putimage(x,y,75,130,&img_human,right_i*75,120); 25 FlushBatchDraw(); 26 Sleep(1); 27 if (right_i==3) 28 right_i = 0; 29 } 30 }
70 71 构建游戏中的地图 72 思路:采用二维数组存地图,初始化使设置四周为墙。显示时,判断为墙,显示墙的图片。 73 loadimage(&img_walls, "D:\\walls.gif"); 74 int maps[8][5] = {0}; // 存储地图信息,0为空地,1为墙 75 // 显示地图图案 76 for (i=0;i<8;i++) 77 for (j=0;j<5;j++) 78 if (maps[i][j]==1) 79 putimage(i*60,j*60,&img_walls); 80 81 82 5.4双人反弹球 83 知识点:异步输入函数的使用 84 用getch()每次只能读一个字符。用windows API中GetAsyncKeyState()函数,同时识别两个按键被按下的情况。参数的对应按键的ASCII码。 85 例如: 86 上箭头:VK_UP,下箭头:VK_DOWN,左箭头←:VK_LEFT,右箭头→:VK_RIGHT 87 if (GetAsyncKeyState(0x57) & 0x8000 ) // w 88 bar1_top-=step; 89 if ((GetAsyncKeyState(0x53) & 0x8000)) //s 90 bar1_top+=step; 91 if ((GetAsyncKeyState(VK_UP) & 0x8000)) // 上方向键 92 bar2_top-=step; 93 if ((GetAsyncKeyState(VK_DOWN) & 0x8000)) // 下方向键 94 bar2_top+=step;
二、代码实现
第五章
注意:项目资源应该放该工程文件下
5.1flappy bird
1 #pragma warning(disable:4996); 2 #include <graphics.h> 3 #include <conio.h> 4 5 // 引用 Windows Multimedia API 6 #pragma comment(lib,"Winmm.lib") 7 8 IMAGE img_bk, img_bd1, img_bd2, img_bar_up1, img_bar_up2, img_bar_down1, img_bar_down2;int bird_x; 9 int bird_y; 10 11 void startup() 12 { 13 initgraph(350, 600); 14 loadimage(&img_bk, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\background.jpg"); 15 loadimage(&img_bd1, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\bird1.jpg"); 16 loadimage(&img_bd2, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\bird2.jpg"); 17 loadimage(&img_bar_up1, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\bar_up1.gif"); 18 loadimage(&img_bar_up2, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\bar_up2.gif"); 19 loadimage(&img_bar_down1, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\bar_down1.gif"); 20 loadimage(&img_bar_down2, "D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\bar_down2.gif"); 21 bird_x = 50; 22 bird_y = 200; 23 BeginBatchDraw(); 24 25 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\background.mp3 alias bkmusic", NULL, 0, NULL);//打开背景音乐 26 mciSendString("play bkmusic repeat", NULL, 0, NULL); // 循环播放 27 } 28 29 void show() 30 { 31 putimage(0, 0, &img_bk); // 显示背景 32 putimage(150, -300, &img_bar_up1, NOTSRCERASE); // 显示上一半的障碍物 33 putimage(150, -300, &img_bar_up2, SRCINVERT); 34 putimage(150, 400, &img_bar_down1, NOTSRCERASE); // 显示下一半的障碍物 35 putimage(150, 400, &img_bar_down2, SRCINVERT); 36 putimage(bird_x, bird_y, &img_bd1, NOTSRCERASE); // 显示小鸟 37 putimage(bird_x, bird_y, &img_bd2, SRCINVERT); 38 FlushBatchDraw(); 39 Sleep(50); 40 } 41 42 void updateWithoutInput() 43 { 44 if (bird_y < 500) 45 bird_y = bird_y + 3; 46 } 47 48 void updateWithInput() 49 { 50 char input; 51 if (kbhit()) // 判断是否有输入 52 { 53 input = getch(); 54 if (input == ' ' && bird_y > 20) 55 { 56 bird_y = bird_y - 60; 57 mciSendString("close jpmusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 58 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\flappy bird图片音乐素材\\Jump.mp3 alias jpmusic", NULL, 0, NULL); // 打开跳动音乐 59 mciSendString("play jpmusic", NULL, 0, NULL); // 仅播放一次 60 } 61 } 62 } 63 64 void gameover() 65 { 66 EndBatchDraw(); 67 getch(); 68 closegraph(); 69 } 70 71 int main() 72 { 73 startup(); // 数据初始化 74 while (1) // 游戏循环执行 75 { 76 show(); // 显示画面 77 updateWithoutInput(); // 与用户输入无关的更新 78 updateWithInput(); // 与用户输入有关的更新 79 } 80 gameover(); // 游戏结束、后续处理 81 return 0; 82 }
5.2飞机大战
1 #pragma warning(disable:4996); 2 #include <graphics.h> 3 #include <conio.h> 4 #include <math.h> 5 #include <stdio.h> 6 7 // 引用 Windows Multimedia API 8 #pragma comment(lib,"Winmm.lib") 9 10 #define High 800 // 游戏画面尺寸 11 #define Width 590 12 13 IMAGE img_bk; // 背景图片 14 float position_x,position_y; // 飞机位置 15 float bullet_x,bullet_y; // 子弹位置 16 float enemy_x,enemy_y; // 敌机位置 17 IMAGE img_planeNormal1,img_planeNormal2; // 正常飞机图片 18 IMAGE img_planeExplode1,img_planeExplode2; // 爆炸飞机图片 19 IMAGE img_bullet1,img_bullet2; // 子弹图片 20 IMAGE img_enemyPlane1,img_enemyPlane2; // 敌机图片 21 int isExpolde = 0; // 飞机是否爆炸 22 int score = 0; // 得分 23 24 void startup() 25 { 26 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\game_music.mp3 alias bkmusic", NULL, 0, NULL);//打开背景音乐 27 mciSendString("play bkmusic repeat", NULL, 0, NULL); // 循环播放 28 initgraph(Width,High); 29 loadimage(&img_bk, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\background.jpg"); 30 loadimage(&img_planeNormal1, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\planeNormal_1.jpg"); 31 loadimage(&img_planeNormal2, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\planeNormal_2.jpg"); 32 loadimage(&img_bullet1, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\bullet1.jpg"); 33 loadimage(&img_bullet2, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\bullet2.jpg"); 34 loadimage(&img_enemyPlane1, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\enemyPlane1.jpg"); 35 loadimage(&img_enemyPlane2, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\enemyPlane2.jpg"); 36 loadimage(&img_planeExplode1, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\planeExplode_1.jpg"); 37 loadimage(&img_planeExplode2, "D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\planeExplode_2.jpg"); 38 position_x = Width*0.5; 39 position_y = High*0.7; 40 bullet_x = position_x; 41 bullet_y = -85; 42 enemy_x = Width*0.5; 43 enemy_y = 10; 44 BeginBatchDraw(); 45 } 46 47 void show() 48 { 49 putimage(0, 0, &img_bk); // 显示背景 50 if (isExpolde==0) 51 { 52 putimage(position_x-50, position_y-60, &img_planeNormal1,NOTSRCERASE); // 显示正常飞机 53 putimage(position_x-50, position_y-60, &img_planeNormal2,SRCINVERT); 54 55 putimage(bullet_x-7, bullet_y, &img_bullet1,NOTSRCERASE); // 显示子弹 56 putimage(bullet_x-7, bullet_y, &img_bullet2,SRCINVERT); 57 putimage(enemy_x, enemy_y, &img_enemyPlane1,NOTSRCERASE); // 显示敌机 58 putimage(enemy_x, enemy_y, &img_enemyPlane2,SRCINVERT); 59 } 60 else 61 { 62 putimage(position_x-50, position_y-60, &img_planeExplode1,NOTSRCERASE); // 显示爆炸飞机 63 putimage(position_x-50, position_y-60, &img_planeExplode2,SRCINVERT); 64 } 65 outtextxy(Width*0.48, High*0.95, "得分:"); 66 char s[5]; 67 sprintf(s, "%d", score); 68 outtextxy(Width*0.55, High*0.95, s); 69 FlushBatchDraw(); 70 Sleep(2); 71 } 72 73 void updateWithoutInput() 74 { 75 if (isExpolde==0) 76 { 77 if (bullet_y>-25) 78 bullet_y = bullet_y-2; 79 80 if (enemy_y<High-25) 81 enemy_y = enemy_y+0.5; 82 else 83 enemy_y = 10; 84 if (fabs(bullet_x-enemy_x)+fabs(bullet_y-enemy_y) < 80) // 子弹击中敌机 85 { 86 enemy_x = rand()%Width; 87 enemy_y = -40; 88 bullet_y = -85; 89 mciSendString("close gemusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 90 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\gotEnemy.mp3 alias gemusic", NULL, 0, NULL); // 打开音乐 91 mciSendString("play gemusic", NULL, 0, NULL); // 仅播放一次 92 score++; 93 if (score>0 && score%5==0 && score%2!=0) 94 { 95 mciSendString("close 5music", NULL, 0, NULL); // 先把前面一次的音乐关闭 96 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\5.mp3 alias 5music", NULL, 0, NULL); // 打开音乐 97 mciSendString("play 5music", NULL, 0, NULL); // 仅播放一次 98 } 99 if (score%10==0) 100 { 101 mciSendString("close 10music", NULL, 0, NULL); // 先把前面一次的音乐关闭 102 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\10.mp3 alias 10music", NULL, 0, NULL); // 打开音乐 103 mciSendString("play 10music", NULL, 0, NULL); // 仅播放一次 104 } 105 } 106 107 if (fabs(position_x-enemy_x)+fabs(position_y-enemy_y) < 150) // 敌机击中我们 108 { 109 isExpolde = 1; 110 mciSendString("close exmusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 111 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\explode.mp3 alias exmusic", NULL, 0, NULL); // 打开音乐 112 mciSendString("play exmusic", NULL, 0, NULL); // 仅播放一次 113 } 114 } 115 } 116 117 void updateWithInput() 118 { 119 if (isExpolde==0) 120 { 121 MOUSEMSG m; // 定义鼠标消息 122 while (MouseHit()) //这个函数用于检测当前是否有鼠标消息 123 { 124 m = GetMouseMsg(); 125 if(m.uMsg == WM_MOUSEMOVE) 126 { 127 // 飞机的位置等于鼠标所在的位置 128 position_x = m.x; 129 position_y = m.y; 130 } 131 else if (m.uMsg == WM_LBUTTONDOWN) 132 { 133 // 按下鼠标左键,发射子弹 134 bullet_x = position_x; 135 bullet_y = position_y-85; 136 mciSendString("close fgmusic", NULL, 0, NULL); // 先把前面一次的音乐关闭 137 mciSendString("open D:\\新建文件夹\\游戏项目\\多球反弹\\飞机大战图片音乐素材\\f_gun.mp3 alias fgmusic", NULL, 0, NULL); // 打开音乐 138 mciSendString("play fgmusic", NULL, 0, NULL); // 仅播放一次 139 } 140 } 141 } 142 } 143 144 void gameover() 145 { 146 EndBatchDraw(); 147 getch(); 148 closegraph(); 149 } 150 151 int main() 152 { 153 startup(); // 数据初始化 154 while (1) // 游戏循环执行 155 { 156 show(); // 显示画面 157 updateWithoutInput(); // 与用户输入无关的更新 158 updateWithInput(); // 与用户输入有关的更新 159 } 160 gameover(); // 游戏结束、后续处理 161 return 0; 162 }
5.3复杂动画效果
1 #pragma warning(disable:4996); 2 #include <graphics.h> 3 #include <conio.h> 4 int main() 5 { 6 initgraph(480, 300); 7 IMAGE img_human, img_walls; // 定义 IMAGE 对象 8 loadimage(&img_human, "D:\\新建文件夹\\游戏项目\\多球反弹\\复杂动画效果\\行走素材图.jpg"); 9 //putimage(0, 0, &img_human); 10 //clearrectangle(0, 0, 300, 300); 11 loadimage(&img_walls, "D:\\新建文件夹\\游戏项目\\多球反弹\\复杂动画效果\\walls.jpg"); 12 //putimage( 0, 0, &img_walls); 13 int x, y; // 小人整体的坐标位置 14 x = 250; 15 y = 80; 16 int left_i = 0; // 向左行走动画的序号 17 int right_i = 0; // 向右行走动画的序号 18 char input; 19 20 int maps[8][5] = { 0 }; // 存储地图信息,0为空地,1为墙 21 int i, j; 22 // 以下让地图四个边界为墙 23 for (i = 0;i < 8;i++) 24 { 25 maps[i][0] = 1; 26 maps[i][4] = 1; 27 } 28 for (j = 0;j < 5;j++) 29 { 30 maps[0][j] = 1; 31 maps[7][j] = 1; 32 } 33 34 // 显示地图图案 35 for (i = 0;i < 8;i++) 36 for (j = 0;j < 5;j++) 37 if (maps[i][j] == 1) 38 putimage(i * 60, j * 60, &img_walls); 39 40 putimage(x, y, 75, 130, &img_human, 0, 0); 41 BeginBatchDraw(); 42 43 while (1) 44 { 45 if (kbhit()) // 判断是否有输入 46 { 47 input = getch(); // 根据用户的不同输入来移动,不必输入回车 48 if (input == 'a') // 左移 49 { 50 clearrectangle(x, y, x + 75, y + 130); // 清空画面全部矩形区域 51 left_i++; 52 if (x > 60) // 没有达到左边的墙,才移动小人的坐标 53 x = x - 10; 54 putimage(x, y, 75, 130, &img_human, left_i * 75, 0); 55 FlushBatchDraw(); 56 Sleep(1); 57 if (left_i == 3) 58 left_i = 0; 59 } 60 else if (input == 'd') // 右移 61 { 62 clearrectangle(x, y, x + 75, y + 130); // 清空画面全部矩形区域 63 right_i++; 64 if (x < 340) // 没有达到右边的墙,才移动小人的坐标 65 x = x + 10; 66 putimage(x, y, 75, 130, &img_human, right_i * 75, 120); 67 FlushBatchDraw(); 68 Sleep(1); 69 if (right_i == 3) 70 right_i = 0; 71 } 72 } 73 } 74 75 return 0; 76 }
5.4双人反弹球
1 #pragma warning(disable:4996); 2 #include <conio.h> 3 #include <graphics.h> 4 #include<windows.h> 5 #define High 480 // 游戏画面尺寸 6 #define Width 640 7 // 全局变量 8 int ball_x, ball_y; // 小球的坐标 9 int ball_vx, ball_vy; // 小球的速度 10 int radius; // 小球的半径 11 int bar1_left, bar1_right, bar1_top, bar1_bottom; // 挡板1的上下左右位置坐标 12 int bar2_left, bar2_right, bar2_top, bar2_bottom; // 挡板2的上下左右位置坐标 13 int bar_height, bar_width; // 挡板的高度、宽度 14 15 void startup() // 数据初始化 16 { 17 ball_x = Width / 2; 18 ball_y = High / 2; 19 ball_vx = 1; 20 ball_vy = 1; 21 radius = 20; 22 23 bar_width = Width / 30; 24 bar_height = High / 2; 25 26 bar1_left = Width * 1 / 20; 27 bar1_top = High / 4; 28 bar1_right = bar1_left + bar_width; 29 bar1_bottom = bar1_top + bar_height; 30 31 bar2_left = Width * 18.5 / 20; 32 bar2_top = High / 4; 33 bar2_right = bar2_left + bar_width; 34 bar2_bottom = bar2_top + bar_height; 35 36 initgraph(Width, High); 37 BeginBatchDraw(); 38 } 39 40 void clean() // 消除画面 41 { 42 setcolor(BLACK); 43 setfillcolor(BLACK); 44 fillcircle(ball_x, ball_y, radius); 45 fillcircle(ball_x, ball_y, radius); 46 bar(bar1_left, bar1_top, bar1_right, bar1_bottom); 47 bar(bar2_left, bar2_top, bar2_right, bar2_bottom); 48 } 49 50 void show() // 显示画面 51 { 52 setcolor(GREEN); 53 setfillcolor(GREEN); 54 fillcircle(ball_x, ball_y, radius); // 绘制绿圆 55 56 setcolor(YELLOW); 57 setfillcolor(YELLOW); 58 bar(bar1_left, bar1_top, bar1_right, bar1_bottom); // 绘制黄色挡板 59 bar(bar2_left, bar2_top, bar2_right, bar2_bottom); 60 61 FlushBatchDraw(); 62 // 延时 63 Sleep(3); 64 } 65 66 void updateWithoutInput() // 与用户输入无关的更新 67 { 68 // 挡板和小圆碰撞,小圆反弹 69 if (ball_x + radius >= bar2_left && ball_y + radius >= bar2_top && ball_y + radius <= bar2_bottom) 70 ball_vx = -ball_vx; 71 else if (ball_x - radius <= bar1_right && ball_y + radius >= bar1_top && ball_y + radius <= bar1_bottom) 72 ball_vx = -ball_vx; 73 74 // 更新小圆坐标 75 ball_x = ball_x + ball_vx; 76 ball_y = ball_y + ball_vy; 77 78 if ((ball_x <= radius) || (ball_x >= Width - radius)) 79 ball_vx = -ball_vx; 80 if ((ball_y <= radius) || (ball_y >= High - radius)) 81 ball_vy = -ball_vy; 82 } 83 84 void updateWithInput() // 与用户输入有关的更新 85 { 86 int step = 1; 87 if (GetAsyncKeyState(0x57) & 0x8000) // w 88 bar1_top -= step; 89 if ((GetAsyncKeyState(0x53) & 0x8000)) //s 90 bar1_top += step; 91 if ((GetAsyncKeyState(VK_UP) & 0x8000)) // 上方向键 92 bar2_top -= step; 93 if ((GetAsyncKeyState(VK_DOWN) & 0x8000)) // 下方向键 94 bar2_top += step; 95 96 bar1_bottom = bar1_top + bar_height; 97 bar2_bottom = bar2_top + bar_height; 98 } 99 100 void gameover() 101 { 102 EndBatchDraw(); 103 closegraph(); 104 } 105 106 int main() 107 { 108 startup(); // 数据初始化 109 while (1) // 游戏循环执行 110 { 111 clean(); // 把之前绘制的内容取消 112 updateWithoutInput(); // 与用户输入无关的更新 113 updateWithInput(); // 与用户输入有关的更新 114 show(); // 显示新画面 115 } 116 gameover(); // 游戏结束、后续处理 117 return 0; 118 }