这个项目开始于2019年下半年,也就是大二上长学期的时候,当时申报了一个校级srtp项目,自拟题为“基于瞳孔检测的注意力检测方法研究”,而这一部分是作为最后眼控展示的一个小平台。有趣的是,当时开题答辩第一个上台,被怼得要死,中期答辩也是,好在结题答辩在我一波疯狂舔审核老师的操作后,竟然混了个校级优秀项目,后来还在大学生创新创业成果展贴了咱的展板(我的大头...),不过yysy,现在看起来这项目确实很low哈哈哈哈哈。
    这个项目估计会分成三章更完:游戏部分、人脸检测和瞳孔检测部分
以及两个统一的完整展示。下面是第一部分正文:

一、开发平台及辅助工具

开发平台:Visual Studio
编程语言:C++ / C语言
界面开发:EasyX(点击访问)

二、游戏介绍
1、主界面

    启动游戏之后主界面如下图所示;

主界面

    通过按下键盘最右边的方向键 “↑、←、↓、→” 可以 操纵飞机移动到"开始游戏"字样处开始游戏,也可以同时按下类似“←↑”这样的组合实现 斜向移动
    进入游戏应该可以听到游戏音乐,任意时刻点击右上角的喇叭按钮可以 开关音乐

2、游玩界面

    进入游戏之后,操纵方式同前,界面如下:

游玩界面

    此时应该在玩家周围自界面最顶端产生了随机位置、随机数量的 敌机
    通过操控玩家飞机进行躲避,可以看到左上角 分数累加;
    当玩家与敌机发生碰撞之后,玩家会扣血,当 玩家血量扣完时,游戏结束;
    玩家可以按下空格键 发射子弹进行攻击,当敌机与子弹发生碰撞后,敌机会扣血,当 敌机血量扣完时,会从游戏界面中消失;

3、暂停

    点击右上角的Pokemon精灵球可以暂停/继续游戏

4、结束界面

    玩家死亡后,结束界面如下,玩家可以选择再来一次或者退出游戏;
    当玩家游玩分数高于最高纪录时,在游戏结束时会保存最高分。

结束界面
三、游戏实现
1、贴图准备

    背景图网上随便找的一张,其余贴图都是自己用AI画的(当时暑假留校比较闲,成天没事就搞这些花里胡哨的嘻嘻)

2、参数等预定义

    下面这些主要是贴图的一些属性的预定义,而方向键的定义按照习惯还是定义成了wasd等字母按键了,实际上用的还是键盘上的上下左右键:

//贴图属性
#define PlayerBlock 75  //玩家方块大小,等于玩家飞机图像文件大小75x75
#define PlayerBlood 100 //玩家血量
#define PlayerSpeed 3   //玩家移动速度,数值越大越快#define EnemyBlock  80  //敌机方块大小,等于敌机飞机图像文件大小80x80
#define EnemyBlood 100   //敌机血量
#define EnemySpeed  3   //敌机移动速度,数值越大越快
#define Enemy_NUM 15    //屏幕最多出现的敌机数量#define BulletBlock 20   //子弹方块大小
#define Bullet_NUM 20   //屏幕最多出现的子弹数量
#define BulletSpeed 5   //子弹移动速度,数值越大越快//定义方向键
#define LEFT           'a'
#define UP             'w'
#define RIGHT          'd'
#define DOWN           's'
#define L_UP           'q'
#define R_UP           'e'
#define L_DOWN         'z'
#define R_DOWN         'x'

    考虑到各个贴图的属性都差不多,这里就定义成一个结构体了,别问为啥不用Class类,问就是喜欢一个个函数,用起来舒服就完事!需要注意的是Block结构体成员point保存的是贴图方块的左上角顶点,这在第8点碰撞检测部分需要特别注意。
    完整定义如下:

struct SinglePoint
{int x = 0;//定义点坐标int y = 0;
};struct Block
{IMAGE image;//图片文件SinglePoint point;//左顶点uint8_t aliveflag = 0;//是否显示使能,默认不显示uint8_t kickedflag = 0;//是否被攻击,默认未被攻击long alivetime;//存活时间float blood;//血量
};
3.初始化界面函数

    在该函数中,依次进行:游戏背景音乐、子弹音效、死亡音效的装载;根据电脑分辨率动态调整游戏界面尺寸;各贴图装载;玩家飞机位置初始化。

//初始化界面
void Menu()
{mciSendString(TEXT("open music\\地下BGM.wav alias backmusic"), NULL, 0, NULL);mciSendString(TEXT("open music\\der.wav alias begin"), NULL, 0, NULL);mciSendString(TEXT("open music\\SuperMariogameover.wav alias gameover"), NULL, 0, NULL);//playmusic(play, backmusic);uint16_t ScreenW = GetSystemMetrics(SM_CXFULLSCREEN); //获取屏幕宽度,即横向分辨率uint16_t ScreenH = GetSystemMetrics(SM_CYFULLSCREEN); //获取屏幕高度// 初始化绘图区域窗口WindowW = 5 * ScreenW / 5;WindowH = 5 * ScreenH / 5;initgraph(WindowW, WindowH, NOMINIMIZE | SHOWCONSOLE);setbkmode(TRANSPARENT);//设置背景透明//装载背景图、玩家飞机图、敌机障碍图loadimage(&back, "JPG", MAKEINTRESOURCE(BACK_JPG), WindowW, WindowH);loadimage(&(player.image), "JPG", MAKEINTRESOURCE(Player0));loadimage(&Planeimg[0], "JPG", MAKEINTRESOURCE(Plane0));loadimage(&Planeimg[1], "JPG", MAKEINTRESOURCE(Plane1));loadimage(&Planeimg[2], "JPG", MAKEINTRESOURCE(Plane2));loadimage(&pokemon, "JPG", MAKEINTRESOURCE(Click));goon = pokemon;//开始键rotateimage(&pokemon, &pokemon, -PI / 2);//暂停键loadimage(&speaker[0], "JPG", MAKEINTRESOURCE(Silence));loadimage(&speaker[1], "JPG", MAKEINTRESOURCE(Sound));//初始化背景putimage(0, 0, &back);//初始化玩家坐标player.point.x = WindowH - 1 - PlayerBlock;player.point.y = (WindowW - PlayerBlock) / 2;/************掩码显示**************putimage(player.point.y, player.point.x, &(player_cover.image), SRCAND);//掩码图与运算*putimage(player.point.y, player.point.x, &(player.image), SRCPAINT);//原图或运算*********************************/putimage(player.point.y, player.point.x, &(player.image), SRCAND);//初始化玩家飞机坐标
}
4.敌机产生

    为方便理解,作以下解释:

1、enemy[]为上述Block结构类型,存储数量为Enemy_NUM的敌机信息(即结构体成员信息)
2、在该项目中,约定行为x,列为y;
3、敌机产生位置:x坐标默认为0,y坐标为玩家位置y坐标左右各3个敌机贴图大小(即3*EnemyBlock)的随机位置;
4、敌机移动速度:引入速度变量EnemySpeed,本质是每次循环敌机下行像素值,同时为避免刷新过快;引入刷新控制时间Nowtime,通过判断Nowtime是奇数还是偶数决定是否进行敌机贴图刷新;
5、敌机移动到最底端:若玩家未死亡,分数加一,对应敌机各属性清零,为下一次产生做准备。

    下面是完整程序:

void Enemyplaneshow(uint8_t number, uint8_t** Board)
{if (enemy[number].point.x == 0){enemy[number].image = Planeimg[rand() % 3];//敌机机型图随机enemy[number].blood = EnemyBlood;//血量初始化int Locationrand = rand() % (6 * EnemyBlock) + player.point.y - 3 * EnemyBlock;//获得一个在玩家左右三个敌机位置区间的随机数enemy[number].point.y = Limit_num(0, Locationrand, WindowW - EnemyBlock);//限幅Board[enemy[number].point.x][enemy[number].point.y] = 1;//敌机面板置1enemy[number].alivetime = clock();}putimage(enemy[number].point.y, enemy[number].point.x, &(enemy[number].image), SRCAND);//显示敌机飞机//获取当前时间,用于控制速度long Nowtime = (clock() - enemy[number].alivetime) * 1000.0 / CLOCKS_PER_SEC;//更新敌机坐标if (enemy[number].point.x < WindowH - EnemySpeed){if (Nowtime % 2 == 0){Board[enemy[number].point.x][enemy[number].point.y] = 0;//移动前敌机面板清0enemy[number].point.x += EnemySpeed;Board[enemy[number].point.x][enemy[number].point.y] = 1;//移动后敌机面板置1}else enemy[number].point.x = enemy[number].point.x;}else{Board[enemy[number].point.x][enemy[number].point.y] = 0;//结束敌机面板清0enemy[number].point.x = 0;enemy[number].aliveflag = 0;enemy[number].kickedflag = 0;Score++;//飞机出界玩家还未死亡,得分加一;}
}
5、键盘输入检测函数

    为了解决getch()和getchar()等获取键盘输入函数存在的需要等待用户输入而造成的程序卡死问题(主要是影响贴图刷新,不然就卡成PPT了呜呜呜),调用Windows的API,利用函数GetAsyncKeyState异步获取键盘输入,函数定义可以点击查阅官方教程。
    完整程序如下,分别检测键盘上的方向键“↑、←、↓、→”并返回按键值:

//输入检测
char Inputcheck()
{if (GetAsyncKeyState(VK_LEFT) & 0x8000){if (GetAsyncKeyState(VK_UP) & 0x8000) return 'q';else if (GetAsyncKeyState(VK_DOWN) & 0x8000) return 'z';else return 'a';}else if (GetAsyncKeyState(VK_RIGHT) & 0x8000){if (GetAsyncKeyState(VK_UP) & 0x8000) return 'e';else if (GetAsyncKeyState(VK_DOWN) & 0x8000) return 'x';else return 'd';}else if (GetAsyncKeyState(VK_UP) & 0x8000) return 'w';else if (GetAsyncKeyState(VK_DOWN) & 0x8000) return 's';return 0;
}
6、玩家坐标更新

    这一部分是放在main函数中的(其实吧主要是懒得封装了呜呜呜),每次执行完按键检测之后,利用switch case语句执行判断玩家坐标作何更新,其中PlayerSpeed用于控制玩家移动速度,很简单粗暴。完整程序如下:

Input = Inputcheck();//检测玩家方向控制的输入
//根据不同输入进行玩家飞机的移动
switch (Input)
{
case LEFT:player.point.y -= PlayerSpeed;player.point.y = Limit_num(0, player.point.y, WindowW - 1 - PlayerBlock);break;
case RIGHT:player.point.y += PlayerSpeed;player.point.y = Limit_num(0, player.point.y, WindowW - 1 - PlayerBlock);break;
case UP:player.point.x -= PlayerSpeed;player.point.x = Limit_num(0, player.point.x, WindowH - 1 - PlayerBlock);break;
case DOWN:player.point.x += PlayerSpeed;player.point.x = Limit_num(0, player.point.x, WindowH - 1 - PlayerBlock);break;
case L_UP:player.point.y -= PlayerSpeed; player.point.x -= PlayerSpeed;player.point.y = Limit_num(0, player.point.y, WindowW - 1 - PlayerBlock);player.point.x = Limit_num(0, player.point.x, WindowH - 1 - PlayerBlock);break;
case L_DOWN:player.point.y -= PlayerSpeed; player.point.x += PlayerSpeed;player.point.y = Limit_num(0, player.point.y, WindowW - 1 - PlayerBlock);player.point.x = Limit_num(0, player.point.x, WindowH - 1 - PlayerBlock);break;
case R_UP:player.point.y += PlayerSpeed; player.point.x -= PlayerSpeed;player.point.y = Limit_num(0, player.point.y, WindowW - 1 - PlayerBlock);player.point.x = Limit_num(0, player.point.x, WindowH - 1 - PlayerBlock);break;
case R_DOWN:player.point.y += PlayerSpeed; player.point.x += PlayerSpeed;player.point.y = Limit_num(0, player.point.y, WindowW - 1 - PlayerBlock);player.point.x = Limit_num(0, player.point.x, WindowH - 1 - PlayerBlock);break;
default:break;
}
//更新玩家飞机显示
putimage(player.point.y, player.point.x, &(player.image), SRCAND);
7、子弹产生

    与敌机产生类似,使用队列数组存储各子弹位置便于绘图。不同的是,子弹方块与玩家方块一样均为正立的正三角形▲,不使用贴图而直接调用EasyX的绘图函数绘制,且产生位置为玩家机头位置,子弹绘制结果是一个个小的纸飞机嘻嘻。具体程序如下:

void Bulletshow(uint8_t number, uint8_t** Board)
{//if (player.point.x < BulletBlock - 1) return;//玩家在最顶部时,直接返回if (bullet[number].point.x == 0){bullet[number].point.x = player.point.x - BulletBlock / 2;//行数设置为玩家顶部bullet[number].point.y = Limit_num(0, player.point.y + PlayerBlock / 2, WindowW - EnemyBlock);//列数设置为玩家中轴并限幅Board[bullet[number].point.x][bullet[number].point.y] = 1;//子弹面板置1bullet[number].alivetime = clock();}HRGN rgn = CreateRectRgn(bullet[number].point.y - BulletBlock / 2 + 4, bullet[number].point.x, bullet[number].point.y + BulletBlock / 2 - 4, bullet[number].point.x + BulletBlock / 2 * sqrt(3));setcliprgn(rgn);DeleteObject(rgn);//画纸飞机setfillcolor(WHITE);//设置填充色setpolyfillmode(WINDING);//设置凹多边形填充//分别对应四个顶点POINT pts[] = { { bullet[number].point.y, bullet[number].point.x},  //上{ bullet[number].point.y - BulletBlock / 2, bullet[number].point.x + BulletBlock / 2 * sqrt(3) }, //左{ bullet[number].point.y , bullet[number].point.x + BulletBlock / 2}, //中{ bullet[number].point.y + BulletBlock / 2,bullet[number].point.x + BulletBlock / 2 * sqrt(3) }  //右};solidpolygon(pts, 4);//画中间阴影直线setlinecolor(0xD0D0D0);line(bullet[number].point.y, bullet[number].point.x - 1, bullet[number].point.y, bullet[number].point.x - 1 + 3 * BulletBlock / 5);setcliprgn(NULL);//获取当前时间,用于控制速度long Nowtime = (clock() - bullet[number].alivetime) * 1000.0 / CLOCKS_PER_SEC;if (bullet[number].point.x > BulletSpeed){if (Nowtime % 5 == 0){Board[bullet[number].point.x][bullet[number].point.y] = 0;//移动前子弹面板清0bullet[number].point.x -= BulletSpeed;Board[bullet[number].point.x][bullet[number].point.y] = 1;//移动后子弹面板置1}else bullet[number].point.x = bullet[number].point.x;}else{Board[bullet[number].point.x][bullet[number].point.y] = 0;//结束子弹面板清0bullet[number].point.x = 0;bullet[number].aliveflag = 0;}
}
8、碰撞检测

    这里涉及的是玩家<->敌机以及子弹<->敌机之间的两种碰撞,敌机<->敌机之间的碰撞本工程中不作检测(所以会出现两敌机部分重合的Bug情况,不过频率比较少)。为便于理解,以玩家<->敌机的碰撞检测作以下说明:

1、为减轻编程难度,将玩家飞机抽象为正立的正三角形▲,敌机抽象为倒立的正三角形▼
2、通过考虑玩家附近可能出现的三种极端情况的敌机位置以贴图左上角顶点作为考虑对象可以划出一个最小的待碰撞检测正三角区域,即下图中粉色虚线内部区域:

这里涉及到该碰撞区域三个顶点的坐标求取,简单的数学问题,就不作说明了,程序中写的很清楚,特别注意计算起点均在贴图左上顶点
3、通过判断该区域内敌机面板EnemyBoard是否存在等于1的情况,即该区域内是否有敌机,即可判断是否发生碰撞。

    完整程序如下:

/*               /▼/ ▲▼  ▼
*/
/*碰撞检测,(x,y)左上角的坐标,Blockhit碰撞方块大小,例如EnemyBlock,Blockhitted被碰撞方块大小,例如PlayerBlockMode = 0 表示
//原理:以玩家周围可能出现的三种极端情况的敌机划定碰撞检测范围,得出一个玩家三角块和敌机三角块组合形成的更大的三角区域以此区域进行遍历检测是否有敌机使用:Boomcheck(player.point.x, player.point.y, EnemyBlock, PlayerBlock, EnemyBoard, enemy, Enemy_NUM, 0)
*/
int8_t Boomcheck(int x, int y, uint16_t Blockhit, uint16_t Blockhitted, uint8_t** Board, Block block[], uint8_t blocksum, uint8_t Mode)
{int left, right;//定义每一行的左右扫描边界int begin = x - Num_45(1.0 * Blockhit / 2 * sqrt(3));//定义扫描开始行int end = x + Num_45(Blockhitted / 2 * sqrt(3));//定义扫描结束行SinglePoint Top;Top.y = y - (Num_45(1.0 * Blockhit / 2) - Num_45(1.0 * Blockhitted / 2));for (int i = begin; i < end; i++){if (i >= 0 && i < WindowH){left = Limit_num(0, Top.y - Num_45(1.0 * (i - begin) / sqrt(3)), WindowW);right = Limit_num(0, Top.y + Num_45(1.0 * (i - begin) / sqrt(3)), WindowW);for (int j = left; j <= right; j++){//检测到了碰撞if (Board[i][j] == 1){if (Mode == 1){   //查找是哪一个编号的方块发生的碰撞for (int number = 0; number < blocksum; number++){if (block[number].point.x == i && block[number].point.y == j){return number;}}}else{return 1;}}}}}return -1;//未碰撞
}
9、绘图

    如果你有类似的绘图经历,一定绕不过去两个坎:

1、如何实现贴图透明部分替换为背景色?
2、如何解决相邻两次绘图之间绘图的闪烁问题?

    怎么解决呢?咱先来说第一个:

9.1、问题一解决方法
A、解决方法一:

    这也是我在该项目中用的方法。仔细看我上面写的程序,不管是敌机还是玩家,不难发现每次绘图时我调用的只有一个函数putimage(),对比两次调用:

putimage(enemy[number].point.y, enemy[number].point.x, &(enemy[number].image), SRCAND);//显示敌方飞机
putimage(player.point.y, player.point.x, &(player.image), SRCAND);//更新玩家飞机显示

    除开绘图位置x、y以及贴图文件image,关注最后一个参数SRCAND,这一参数意义是:“通过使用AND (与)操作符来将源和目标区域内的颜色合并”,啥意思呢?就是两个数作与运算,例如0x0101 AND 0x1010结果为0x0000。
    那为什么通过这种方式就可以实现透明贴图呢?以16位RGB为例,项目中采用的贴图均为白底,对应RGB为0xFFFF,仔细想想可以发现0xFFFF与任何数字作与运算均为该数字原来的值,通过这种方式就可以将贴图中白色的部分替换为背景色啦!不过通过上一个例子可以看出,这样的方法缺陷是会导致贴图非白色部分的颜色出现“色差”,所以提供第二种方法供参考。

B、解决办法二:

    这方法也是在CSDN一篇博客中学到的,当时看的那篇找不到了,就找了个类似的供参考:OpenCV之通过位运算实现图像的叠加,原理作简单阐述:

1、将需要贴图的图片提取出轮廓,将其内部区域置为黑色0x0000,其余区域为白色0xFFFF,得到掩码图;
2、将掩码图与背景图作与运算,抠出贴图待显示的区域;
3、待显示贴图底色要求为黑色0x0000,此时,将贴图与第2步同一区域作或运算,即可实现透明贴图。

    这种方法我在Menu()函数中以注释的方法贴了出来,即:

    /************掩码显示*************/putimage(player.point.y, player.point.x, &(player_cover.image), SRCAND);//掩码图与运算putimage(player.point.y, player.point.x, &(player.image), SRCPAINT);//原图或运算/*********************************/
9.2、问题二解决方法

    图像闪烁这个问题当时也是困扰了我好几天,后来仔细翻阅EasyX官方文档,终于找到了解决的好办法,怎么解决的呢?
    其实用起来很简单,一共就三个函数:

BeginBatchDraw();//开始连续画图
FlushBatchDraw();//连续画图
EndBatchDraw();//结束连续画图

    用的时候第一个函数在程序开始时调用,最后一个函数在程序退出时调用,第二个程序在循环中调用即可实现连续绘图而不会出现闪烁,不过第二个函数调用的时机其实我掌握的也不是很好,还是得多试试。

10、游戏音效

    其实到这个地方整个游戏的基本功能几乎都实现了,主要考虑到游戏体验,才加了音效部分,这里还是作一下简单的介绍:

1、考虑到游戏音乐(包括背景音乐、死亡音效)播放涉及开始播放、暂停播放、重新播放等多个功能需求,因此用MCI的API指令之一mciSebdString函数实现
2、对于发射子弹音效,因为涉及音效的打断,也就是我们常听到的连续开火时“啾啾啾啾啾”的音乐效果,所以使用的是Windows用于播放音乐的API函数PlaySound()。

具体运用程序如下:

enum Function
{play, pause, resume, close, replay
};enum Music
{backmusic, beginmusic, firemusic, gameovermusic
};void playmusic(uint8_t function, uint8_t number)
{switch (function){case play:switch (number){case backmusic:mciSendString(TEXT("play backmusic"), NULL, 0, NULL);break;case beginmusic:mciSendString(TEXT("play begin from 0"), NULL, 0, NULL);break;case firemusic:PlaySound(TEXT("music\\fire.wav"), NULL, SND_FILENAME | SND_ASYNC);break;case gameovermusic:mciSendString(TEXT("play gameover from 0"), NULL, 0, NULL);break;default:break;}break;case pause:switch (number){case backmusic:mciSendString(TEXT("pause backmusic"), NULL, 0, NULL);break;case beginmusic:mciSendString(TEXT("pause begin"), NULL, 0, NULL);break;case gameovermusic:mciSendString(TEXT("pause gameover"), NULL, 0, NULL);break;default:break;}break;case resume:switch (number){case backmusic:mciSendString(TEXT("resume backmusic"), NULL, 0, NULL);break;default:break;}break;case replay:switch (number){case backmusic:mciSendString(TEXT("play backmusic from 0"), NULL, 0, NULL);break;}}
}

    至此,除了按钮点击事件(如开始游戏、结束游戏、暂停、开关音乐)等简单的按键检测未叙述之外,整个游戏的核心基本全部叙述完毕。

四、总结

    这是我上大学以来第一款独立地从第一个字母撸到最后一个字母的游戏,总共花费时间断断续续差不多一个周(其实也就早上起来摸一摸,其他时间都在寝室肥宅哈哈哈哈),编写过程还是比较轻松愉快的,值得纪念一下嘻嘻~
    鞠躬~~~

团队项目(2.1) -- 飞机躲避小游戏相关推荐

  1. C语言关于飞机躲子弹的游戏,团队项目(2.1) -- 飞机躲避小游戏

    这个项目开始于2019年下半年,也就是大二上长学期的时候,当时申报了一个校级srtp项目,自拟题为"基于瞳孔检测的注意力检测方法研究",而这一部分是作为最后眼控展示的一个小平台.有 ...

  2. 飞机躲避小游戏---是男人就撑100秒的制作

    飞机躲避小游戏---是男人就撑100秒的制作 EmilMatthew(EmilMatthew@126.com) 摘要:  可以将这个游戏的整体运作看成一个粒子系统,再加上子弹和飞机的碰撞判定即可.简单 ...

  3. 飞机大战小游戏(超详细)

    偷学Python之最后的项目二:飞机大战小游戏(超详细) 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志.--苏轼 甜甜先说 这次用Python中的pygame模块来完成一个飞机大战的小游戏:基本思 ...

  4. 点击list view中一行内容可以在combox中显示_java版飞机大战小游戏详细教程(零基础小白也可以分分钟学会!)...

    一:游戏展示 飞机大战小游戏我们都玩过,通过移动飞机来打敌机,这里给大家展示一下游戏成果:呜呜呜由于gif只能上传5M大小,所以就不能给大家展示操作了,如果大家有兴趣可以自己自己做出来再玩哟. 这里面 ...

  5. 使用小程序制作一个飞机大战小游戏

    此文主要基于微信小程序制作一个飞机大战小游戏,上手即用,操作简单. 一.创建小程序 二.页面实现 三.代码块 一.创建小程序 访问微信公众平台,点击账号注册. 选择小程序,并在表单填写所需的各项信息进 ...

  6. 基于Java语言在窗体上实现飞机大战小游戏

    全套资料下载地址:https://download.csdn.net/download/sheziqiong/85594271 项目介绍 飞机大战:用 Java 语言在窗体上实现飞机大战小游戏,运行程 ...

  7. 【Java代码实现飞机大战小游戏】简单理解

    飞机大战 飞机大战小游戏历经10天完成,主要用到的就是我们面向对象部分的知识:类,封装,继承,多态,静态代码块等等内容+swing部分内容.所以即使你是java小白,也不用担心欧! 游戏说明:游戏有3 ...

  8. 【Java】Java基础飞机大战小游戏完整代码

    Java基础飞机大战小游戏完整代码 先来展示一下代码实现结果图 主函数ShootGame 初始化游戏原始背景图片,游戏人物图片,游戏开始结束图片:构建产生敌人算法:产生英雄机算法:发射子弹算法:判断是 ...

  9. 华清大作业 QT实现飞机大战小游戏

    在学习完QT后,我尝试做了一下飞机大战这个小游戏. 首先是小游戏需要实现的功能: 1.滚动的背景 2.子弹的制作和射击 3.敌人的制作 4.爆炸效果 首先我们创建好项目后,我们开始创建新的头文件,用来 ...

  10. 飞机大战小游戏源码---飞机大战初体验

    开发环境: Windows10,pycharm,python3 源码使用教程: 打开pycharm,创建一个新的项目,文件-->新建项目 项目命名:飞机大战初体验,基本解释器选择python3版 ...

最新文章

  1. Python format() 函数
  2. 手动安装android的sdk
  3. 日期处理一之NSLalendar的使用
  4. QT学习笔记(十四):QLayout的属性介绍
  5. 机器学习(十五)隐马尔科夫模型-未完待续
  6. Pycharm文档模板变量
  7. 理解promise、async 和await之间的执行关系
  8. delphi 标题栏相关操作
  9. 感谢宝贝: 带给我别样人生
  10. python notebook_Python Notebook (Jupyter Notebook) 介绍
  11. Android 测试机选购指南
  12. 完美池宇峰畅谈创业点滴 男怕入错行
  13. 智能健身动作识别:PP-TinyPose打造AI虚拟健身教练!
  14. Python应用之批量打水印
  15. 初始化之前使寄存器恢复缺省值的重要性
  16. POI-获取Excel中合并单元格问题
  17. MemSQL分布式架构介绍
  18. Ubuntu20.04安装有道词典记录
  19. 【第一个项目开发】创建domain包中的类
  20. 计算机专业 公务员发展前景,未来5年,我国待遇“最好”的4个专业,前途不输公务员...

热门文章

  1. 推荐一个免费的论文查重检测软件PaperRight
  2. git pull git_Git Pull解释
  3. 语音端点matlab,语音端点检测及其在Matlab中的实现
  4. pyecharts对于经纬度_pyecharts绘制geo地图
  5. 百度地图经纬度距离计算
  6. win10 修改用户名
  7. cio时代_成功实现数字时代CIO的6条原则
  8. Postgresql 使用 Pl/python实现邮件监控
  9. 哈里王子与魔兽圣骑士(Paladin)
  10. ethtool如何让接口闪灯_如何使用ethtool命令管理以太网卡