提前准备好游戏要的素材,可以到爱给网去找,飞机大战我们需要的是一个我方战机图片,一个背景图,三个敌方战机的图,我方战机的图片,敌方战机的图片,并且将图片和.cpp放在同一文件夹下.
这里创建.cpp的文件是因为要用到图形库,所以创建.cpp的文件,然后图片格式都是png
1.我方飞机和背景图片的加载和贴图
#include<stdio.h> #include <graphics.h>//图形库头文件 #define HEIGHT 503 #define WIDTH 700 IMAGE img_bk, img_plane;//定义背景图片,玩家的类 int main() { initgraph(WIDTH, HEIGHT);//初始化游戏的背景 loadimage(&img_bk, "./back.png");//加载游戏背景图 loadimage(&img_plane, "./1.png");//加载游戏玩家图片 putimage(0, 0, &img_bk);//贴游戏背景图 putimage(200,200, &img_plane);//贴玩家战机的图片 getchar();//防止窗口闪退 }
背景图片是503*700,背景图片大小自己设置,为了让游戏体验感增强,如果铺满整个屏幕的话,会不好移动.
2.去掉飞机背后的黑色背景,使用一个算法函数
#include<stdio.h> #include <graphics.h> #define HEIGHT 503 #define WIDTH 700 IMAGE img_bk, img_plane; void drawAlpha(IMAGE* picture, int picture_x, int picture_y) //x为载入图片的X坐标,y为Y坐标 { // 变量初始化 DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带 DWORD* draw = GetImageBuffer(); DWORD* src = GetImageBuffer(picture); //获取picture的显存指针 int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带 int picture_height = picture->getheight(); //获取picture的高度,EASYX自带 int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带 int graphHeight = getheight(); //获取绘图区的高度,EASYX自带 int dstX = 0; //在显存里像素的角标 // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算 for (int iy = 0; iy < picture_height; iy++) { for (int ix = 0; ix < picture_width; ix++) { int srcX = ix + iy * picture_width; //在显存里像素的角标 int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度 int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R int sg = ((src[srcX] & 0xff00) >> 8); //G int sb = src[srcX] & 0xff; //B if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight) { if ((ix + picture_x) >= 0 && (ix + picture_x) <= graphWidth) //防止出边界后循环显示 { dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标 int dr = ((dst[dstX] & 0xff0000) >> 16); int dg = ((dst[dstX] & 0xff00) >> 8); int db = dst[dstX] & 0xff; draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg | (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db } } } } } int main() { initgraph(WIDTH, HEIGHT); loadimage(&img_bk, "./back.png"); loadimage(&img_plane, "./1.png"); putimage(0, 0, &img_bk);//贴背景前两个为图片左上角要贴在窗口的坐标 drawAlpha(&img_plane, 200, 200);//贴飞机图片 getchar(); }
这个函数我看不懂,是在网上搜的,我来解释一下三个参数,第一个是图片的地址,第二个参数,第三个参数的坐标是图片左上角从窗口的哪个位置贴,背景肯定是从窗口的左上角贴.
注意:使用这个函数在飞机移动屏幕过程中,会出现异常,不知道怎么解决,希望有大佬可以帮帮我,drawAlpha区别putimage可以把背景变透明
3.静态显示所有素材图片
#include<stdio.h> #include <graphics.h> #define HEIGHT 503 #define WIDTH 700 IMAGE img_bk, img_plane, img_a, img_b, img_c,img_abullet,img_bbullet,img_cbullet,img_planebullet; struct aircraft { int x, y; }; aircraft plane, a, b, c; void datainit() { plane = { 150,150 }; a = { 0,0 }; b = { 300,0 }; c = { 450,0 }; } void drawAlpha(IMAGE* picture, int picture_x, int picture_y) //x为载入图片的X坐标,y为Y坐标 { // 变量初始化 DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带 DWORD* draw = GetImageBuffer(); DWORD* src = GetImageBuffer(picture); //获取picture的显存指针 int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带 int picture_height = picture->getheight(); //获取picture的高度,EASYX自带 int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带 int graphHeight = getheight(); //获取绘图区的高度,EASYX自带 int dstX = 0; //在显存里像素的角标 // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算 for (int iy = 0; iy < picture_height; iy++) { for (int ix = 0; ix < picture_width; ix++) { int srcX = ix + iy * picture_width; //在显存里像素的角标 int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度 int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R int sg = ((src[srcX] & 0xff00) >> 8); //G int sb = src[srcX] & 0xff; //B if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight) { if ((ix + picture_x) >= 0 && (ix + picture_x) <= graphWidth) //防止出边界后循环显示 { dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标 int dr = ((dst[dstX] & 0xff0000) >> 16); int dg = ((dst[dstX] & 0xff00) >> 8); int db = dst[dstX] & 0xff; draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg | (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db } } } } } void load() { loadimage(&img_bk, "./back.png"); loadimage(&img_plane, "./1.png"); loadimage(&img_a, "./2.png"); loadimage(&img_b, "./3.png"); loadimage(&img_c, "./4.png"); loadimage(&img_abullet, "./5.png"); loadimage(&img_bbullet, "./6.png"); loadimage(&img_cbullet, "./7.png"); loadimage(&img_planebullet, "./8.png"); } void draw() { putimage(0, 0, &img_bk); drawAlpha(&img_plane,plane.x,plane.y); drawAlpha(&img_a, a.x, a.y); drawAlpha(&img_b, b.x, b.y); drawAlpha(&img_c, c.x, c.y); drawAlpha(&img_abullet,400,0 );//后两个参数是图片左上角在窗口要贴的位置 drawAlpha(&img_bbullet,400 ,50 ); drawAlpha(&img_cbullet, 400, 100); drawAlpha(&img_planebullet, 400, 150); } int main() { initgraph(WIDTH, HEIGHT); datainit(); load(); draw(); getchar(); }
定义3个敌方战机,a,b,c,3个敌机的子弹abullet,bbullet,cbullet,我方战机的子弹planebullet
IMAGE img_a, img_b, img_c,img_abullet,img_bbullet,img_cbullet,img_planebullet;
定义一个结构体记录每个图片左上角要贴在窗口的坐标.四个结构体表示我方战机,3个敌方战机在窗口上的坐标,图中的初始化只是为了让图片不重叠而已。
将加载图片的函数统一放在load函数里面,将贴图片的函数放在draw中.
4.我方飞机的移动
void player_move(int speed) //处理飞机移动 { if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState('W')) { if (plane.y > 0) plane.y -= speed; } if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState('S')) { if (plane.y + 126< HEIGHT) plane.y += speed; } if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState('A')) { if (plane.x > 0) plane.x -= speed; } if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState('D')) { if (plane.x + 51 < WIDTH) plane.x += speed; } }
这个移动函数在之前游戏里用了好多次,这里就不强调了.函数中的speed参数是我方战机的速度,每按一次会移动几个像素.这里的重点放在飞机边界的判断上,记得加双缓冲,要不然,屏幕会闪
边界的判断以及飞机的移动
if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState('S')) { if (plane.y + 126< HEIGHT) plane.y += speed; }
这里加126是为了不让程序出现异常,如果正常的话应该加51,因为我方战机图片大小是51*51;如果是51的话会出现如下视频的错误,不知道为什么,请看vcr
5.敌方战机的移动
首先我们要修改一下飞机结构体的变量
struct aircraft { int x, y; int width;//敌机图片的宽度 int height;//敌机图片的高度 int speed;//敌机的速度 int bornflag;//敌机在窗口里面置0,在外面置1 };
然后修改一下初始话敌机的属性.
void datainit() { plane = { 150,150 }; //a = { 0,0 }; /*b = { 300,0 };*/ /*c = { 450,0 };*/ a.speed = 1;//a敌机的速度 a.bornflag = 1;//a敌机是否存在 b.bornflag = 1; c.bornflag = 1; a.width = 100;//a敌机的宽度 a.height = 100;//a敌机的高度 b.speed = 1; b.width = 80; b.height = 100; c.height = 70; c.width = 70; c.speed = 3; }
敌机a的移动
敌机a的移动
如视频所示,对应的代码实现是
void ufoamove() { static int dir1 = 1; if (a.bornflag == 1) { a.bornflag = 0; a.x = rand() % (WIDTH - a.width); a.y = -50; } if (a.y > 200) { dir1 = 0; } else if (a.y < -150) { dir1 = 1; a.bornflag = 1; } if (1 == dir1) { a.y += a.speed; } else { a.y -= a.speed; } }
定义一个静态变量dir,dir为1的话,表示敌机前进,dir为0,敌机后退。因为是static,所以只有第一次初始化时候是1,别的时候不执行第一句.当敌机a没在窗口里面,说明a.bornflag == 1,就将a.bornflag 置为0,敌机a要出现了,随机数生成敌机a要出现的左右方向哪个地方,y=-50;是为了初始化的时候隐藏飞机.当敌机a前进200个像素时,dir置0,让敌机a后退.当敌机向上退出屏幕50个像素时,重新dir=1;敌机向前.此时会出现在另一个位置。在主函数中加入产生随机种子函数
srand(time(NULL));
包含头文件
#include<time.h> #include<stdlib.h>
敌机出屏幕,drawAlpha这个函数会出错,所以我们把draw中的drawAlpha都改成putimage,这样黑框框又出现了,(电子叹气)
void draw() { putimage(0, 0, &img_bk); putimage(plane.x, plane.y ,&img_plane ); putimage(a.x, a.y ,&img_a); putimage(b.x, b.y ,&img_b ); putimage(c.x, c.y, &img_c ); putimage(400, 0 ,&img_abullet ); putimage(400, 50 ,&img_bbullet); putimage(400, 100 ,&img_cbullet ); putimage(400, 150, &img_planebullet ); }
敌机b的移动
请看vcr
敌机b的移动
对应代码
void ufobmove() { static int step = b.speed; if (b.bornflag == 1) { b.bornflag = 0; b.x = rand() % (WIDTH - b.width); b.y = -b.height; } if (b.x <= 0 || b.x + b.width >= WIDTH) { step = -step; } b.x += step; b.y++; if (b.y >= HEIGHT) { b.bornflag = 1; } }
由视频可知敌机b的移动规律是在左右移动的同时还向前移动,step如果为正,向右移动,step如果为负,表示向左移动,如果b战机没有出现在窗口内(b.bornflag == 1),将b.bornflag 置0,表示要出现,随机数生成b战机的坐标.y=-b.height;初始化先隐藏起来.如果b战机到了左右边界,step=-step;
就向相反的方向移动了,左右移动实质是在给b.x±step;然后y++,b战机在左右移动的过程中,一直往前走.当b战机出了下边界,b.bornflag = 1;表示b战机出了窗口.
敌机c的移动
请看vcr
敌机c的移动
对应的代码为
void ufocmove() { static float disx = 0, disy = 0; static float tmpx = 0, tmpy = 0; static float vx = 0, vy = 0; float step = 1000 / c.speed; if (1 == c.bornflag) { c.bornflag = 0; tmpx = rand() % (WIDTH - c.width); tmpy = -c.height; disx = plane.x - tmpx; disy = plane.y - tmpy; vx = disx / step; vy = disy / step; } tmpx += vx; tmpy += vy; c.x = (int)(tmpx + 0.5); c.y = (int)(tmpy + 0.5); if (c.x < -c.width) { c.bornflag = 1; } else if (c.x > WIDTH) { c.bornflag = 1; } if (c.y > HEIGHT) { c.bornflag = 1; } }
这个c战机是要撞向我方飞机,tmpx,tmpy存放的是c战机的临时的位置,刚生成时,当然是他出生点的坐标,disx是c战机刚出来x方向上与当时我方战机x方向上的距离,同理另一个.step是,假如c.speed的速度为5的话,step==200,就是说将x方向上的距离分为200份,vx就是每一份的距离是多少像素,这里强制类型转化,c.x,c.y是整数,因为vx,vy不清楚,所以+0.5,四舍五入一下就是整数了.如果在左,右,下方向超出了,就c.bornflag = 1;离开窗口了.
6.整体代码展示
#include<stdio.h> #include <graphics.h> //#include<conio.h>//_getch(); #define HEIGHT 503 #define WIDTH 700 IMAGE img_bk, img_plane, img_a, img_b, img_c, img_abullet, img_bbullet, img_cbullet, img_planebullet; struct aircraft { int x, y; int width; int height; int speed; int bornflag; }; aircraft plane, a, b, c; void datainit() { plane = { 150,150 }; //a = { 0,0 }; /*b = { 300,0 };*/ /*c = { 450,0 };*/ a.speed = 1; a.bornflag = 1; b.bornflag = 1; c.bornflag = 1; a.width = 100; a.height = 100; b.speed = 1; b.width = 80; b.height = 100; c.height = 70; c.width = 70; c.speed = 3; } void drawAlpha(IMAGE* picture, int picture_x, int picture_y) //x为载入图片的X坐标,y为Y坐标 { // 变量初始化 DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带 DWORD* draw = GetImageBuffer(); DWORD* src = GetImageBuffer(picture); //获取picture的显存指针 int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带 int picture_height = picture->getheight(); //获取picture的高度,EASYX自带 int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带 int graphHeight = getheight(); //获取绘图区的高度,EASYX自带 int dstX = 0; //在显存里像素的角标 // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算 for (int iy = 0; iy < picture_height; iy++) { for (int ix = 0; ix < picture_width; ix++) { int srcX = ix + iy * picture_width; //在显存里像素的角标 int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度 int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R int sg = ((src[srcX] & 0xff00) >> 8); //G int sb = src[srcX] & 0xff; //B if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight) { if ((ix + picture_x) >= 0 && (ix + picture_x) <= graphWidth) //防止出边界后循环显示 { dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标 int dr = ((dst[dstX] & 0xff0000) >> 16); int dg = ((dst[dstX] & 0xff00) >> 8); int db = dst[dstX] & 0xff; draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg | (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db } } } } } void load() { loadimage(&img_bk, "./back.png"); loadimage(&img_plane, "./1.png"); loadimage(&img_a, "./2.png"); loadimage(&img_b, "./3.png"); loadimage(&img_c, "./4.png"); loadimage(&img_abullet, "./5.png"); loadimage(&img_bbullet, "./6.png"); loadimage(&img_cbullet, "./7.png"); loadimage(&img_planebullet, "./8.png"); } void draw() { putimage(0, 0, &img_bk); putimage(plane.x, plane.y ,&img_plane ); putimage(a.x, a.y ,&img_a); putimage(b.x, b.y ,&img_b ); putimage(c.x, c.y, &img_c ); putimage(400, 0 ,&img_abullet ); putimage(400, 50 ,&img_bbullet); putimage(400, 100 ,&img_cbullet ); putimage(400, 150, &img_planebullet ); } void player_move(int speed) //处理飞机移动 { if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState('W')) { if (plane.y > 0) plane.y -= speed; } if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState('S')) { if (plane.y + 51< HEIGHT) plane.y += speed; } if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState('A')) { if (plane.x > 0) plane.x -= speed; } if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState('D')) { if (plane.x + 51 < WIDTH) plane.x += speed; } } void ufoamove() { static int dir1 = 1; if (a.bornflag == 1) { a.bornflag = 0; a.x = rand() % (WIDTH - a.width); a.y = -50; } if (a.y > 200) { dir1 = 0; } else if (a.y < -150) { dir1 = 1; a.bornflag = 1; } if (1 == dir1) { a.y += a.speed; } else { a.y -= a.speed; } } void ufobmove() { static int step = b.speed; if (b.bornflag == 1) { b.bornflag = 0; b.x = rand() % (WIDTH - b.width); b.y = -b.height; } if (b.x <= 0 || b.x + b.width >= WIDTH) { step = -step; } b.x += step; b.y++; if (b.y >= HEIGHT) { b.bornflag = 1; } } void ufocmove() { static float disx = 0, disy = 0; static float tmpx = 0, tmpy = 0; static float vx = 0, vy = 0; float step = 1000 / c.speed; if (1 == c.bornflag) { c.bornflag = 0; tmpx = rand() % (WIDTH - c.width); tmpy = -c.height; disx = plane.x - tmpx; disy = plane.y - tmpy; vx = disx / step; vy = disy / step; } tmpx += vx; tmpy += vy; c.x = (int)(tmpx + 0.5); c.y = (int)(tmpy + 0.5); if (c.x < -c.width) { c.bornflag = 1; } else if (c.x > WIDTH) { c.bornflag = 1; } if (c.y > HEIGHT) { c.bornflag = 1; } } int main() { initgraph(WIDTH, HEIGHT); BeginBatchDraw(); datainit(); while (1) { load(); draw(); ufoamove(); ufobmove(); ufocmove(); player_move(5); FlushBatchDraw(); } EndBatchDraw(); getchar(); }