• 【游戏专区】飞机大战


    打过飞机的人都知道,不是那么好打滴,求得麻袋,甩掉你那脑子里的黄色信息。活不多说,我们开始吧。

    1、easyX的原理

    基于Windows图形编程,将Windows下的复杂程序过程进行封装,仅给用户提供一个简单熟悉的接口。用户对于图形库中函数的调用,最终都会由Windows底层的API实现。

    2、easyX的安装

    仅支持vs系列

    点击跳转

    平常使用那个版本就点击对应的安装按钮即可。

    3,图片资源

    链接:点击获取图片
    提取码:1111

    4,创建窗口

    窗口我们需要创建多大呢,

    具体实现怎么操作,我们开始写代码

    窗口是有了,但是我们如何将图片绘制出来呢

    5,定义飞机结构

    想想我们飞机需要哪些结构,坐标,血量还有什么呢

    1. //创建飞机结构
    2. typedef struct Plane
    3. {
    4. int x;//飞机坐标
    5. int y;
    6. bool isDie;//是否健在
    7. int width;//宽度
    8. int height;//长度
    9. int frame;//当前帧
    10. int hp;//血量
    11. int type;//敌机类型
    12. }Plane;

    有了飞机的结构以及初始化,我们是不是还需要将其加载进入
    飞机图片

    6,透明贴图函数(可直接复制,使用也是可以的)

    1. #include "aircraft.h"
    2. //把像素的颜色拆解出来 ARGB
    3. typedef struct _ARGB {
    4. byte a;
    5. byte r;
    6. byte g;
    7. byte b;
    8. }ARGB;
    9. //把颜色拆分
    10. ARGB color2Argb(DWORD c) {
    11. ARGB res;
    12. res.r = (byte)c;
    13. res.g = (byte)(c >> 8);
    14. res.b = (byte)(c >> 16);
    15. res.a = (byte)(c >> 24);
    16. return res;
    17. }
    18. DWORD argb2Color(ARGB c) {
    19. DWORD t = RGB(c.r, c.g, c.b);
    20. return ((DWORD)c.a) << 24 | t;
    21. }
    22. //把色彩图转成黑白图
    23. void toGray(IMAGE* src) {
    24. DWORD* psrc = GetImageBuffer(src);
    25. for (int i = 0; i < src->getwidth() * src->getheight(); i++) {
    26. //获取每一个像素点的颜色值
    27. ARGB t = color2Argb(psrc[i]);
    28. //灰度图,求三个或者四个颜色值的均值
    29. byte arv = (t.r + t.g + t.b) / 3;
    30. ARGB res = { t.a,arv,arv,arv };
    31. psrc[i] = argb2Color(res);
    32. }
    33. }
    34. /*
    35. * @png透明贴图
    36. */
    37. void drawImg(int x, int y, IMAGE* src) {
    38. // 变量初始化
    39. DWORD* pwin = GetImageBuffer();//窗口缓冲区指针
    40. DWORD* psrc = GetImageBuffer(src);//图片缓冲区指针
    41. int win_w = getwidth();//窗口宽高
    42. int win_h = getheight();
    43. int src_w = src->getwidth();//图片宽高
    44. int src_h = src->getheight();
    45. //计算贴图的实际长宽
    46. int real_w = (x + src_w > win_w) ? win_w - x : src_w;//处理超出右边界
    47. int real_h = (y + src_h > win_h) ? win_h - y : src_h;//处理超出右边界
    48. if (x < 0) {//处理超出左边界
    49. psrc += -x;
    50. real_w -= -x;
    51. x = 0;
    52. }
    53. if (y < 0) {//处理超出右边界
    54. psrc += (src_w * -y);
    55. real_h -= -y;
    56. y = 0;
    57. }
    58. //修正贴图起始位置
    59. pwin += (win_w * y + x);
    60. //实现透明贴图
    61. for (int iy = 0; iy < real_h; iy++) {
    62. for (int ix = 0; ix < real_w; ix++) {
    63. byte a = (byte)(psrc[ix] >> 24);//计算透明通道的值[0,256] 0为完全透明 255完全不透明
    64. if (a > 100) {
    65. pwin[ix] = psrc[ix];
    66. }
    67. }
    68. //换到下一行
    69. pwin += win_w;
    70. psrc += src_w;
    71. }
    72. }

    当我们写到这里,只需要将绘制飞机的(putimage)替换成(drawLmg),就已经可以实现飞机的动态刷新了

    7,飞机的移动

    那我们要去移动飞机吧,不然他还只是一张图片,我们要写飞机的移动,就必须考虑它的边界问题。

    知道了这些,我们就可以开始写代码了

    当我们写完这个,你就会发现你的飞机走的非常快,这是我们电脑在处理帧的时候非常的迅速,所以我们还需要一个定时器,每秒刷新60帧,应该已经足够。

    1. //参数:frameRate 帧数
    2. void timerFunction(int frameRate) {
    3. clock_t startTime, currentTime;
    4. long elapsed;
    5. // 计算每一帧的毫秒数
    6. int ms_per_frame = 1000 / frameRate;
    7. // 获取初始时间
    8. startTime = clock();
    9. while (1) {
    10. // 获取当前时间
    11. currentTime = clock();
    12. // 计算已经过去的时间(以毫秒为单位)
    13. elapsed = (currentTime - startTime) * 1000;
    14. // 如果已经过去的时间超过了下一帧的时间间隔,则输出一帧
    15. if (elapsed >= ms_per_frame) {
    16. // 更新初始时间
    17. startTime = currentTime;
    18. // 暂停一段时间,使得每秒输出指定的帧率
    19. Sleep(1); // 暂停 1 毫秒
    20. break;
    21. }
    22. }
    23. }

    8,子弹的初始化绘制以及移动

    现在我们就来定义子弹的结构

    1. //子弹结构
    2. typedef struct Bullet
    3. {
    4. int x;//坐标
    5. int y;
    6. bool isDie;//是否出界面以及碰到敌机
    7. }Bullet;

    子弹的初始化,我们也可以在初始化函数中进行调用

    初始化完成后,我们还需加载资源以及绘制它

    1. //子弹图片有两张
    2. static IMAGE img_bullet[2];
    3. //加载子弹图片
    4. loadimage(img_bullet + 0, "images/bullet1.png");
    5. loadimage(img_bullet + 1, "images/bullet2.png");

    但是,当我们有了这些依旧无法发射子弹,我们设计的是需要空格去发射的,所以,我们还需要再移动飞机的函数中写一个发射子弹的判断

    这是因为我们发射子弹太快,重叠了,而且我们的子弹只会停留在我们发射的位置,不会移动,所有有了目标,接下来就好办多了。

    我们可以写一个定时器,让它隔几微妙后才能发射

    1. /*
    2. 类概述:
    3. 私有成员变量: std::vector<std::chrono::steady_clock::time_point> startTimes:存储每个计时器的起始时间,通过其ID进行标识。
    4. 构造函数:
    5. Timer(): 默认构造函数。
    6. 方法:
    7. bool hasElapsed(int ms, int id): 检查指定ID的计时器是否经过了ms毫秒。
    8. */
    9. class Timer {
    10. private:
    11. std::vector<std::chrono::steady_clock::time_point> startTimes;
    12. public:
    13. Timer() {}
    14. bool hasElapsed(int ms, int id) {
    15. if (id >= startTimes.size()) {
    16. startTimes.resize(id + 1);
    17. startTimes[id] = std::chrono::steady_clock::now();
    18. return true; // Treat as elapsed since this is the first time for this timer
    19. }
    20. auto now = std::chrono::steady_clock::now();
    21. auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTimes[id]);
    22. if (duration.count() >= ms) {
    23. startTimes[id] = now;
    24. return true;
    25. }
    26. return false;
    27. }
    28. };

    接下来就是子弹的移动

    所以呢,这样看我们要写的移动就是Y轴的递减过程,飞出界外或者碰到敌人,我们将其置为false就可以了。(很容易写吧)

    9,创建敌机

    我们现在需要什么,当然是敌人啊

    我要打十个,敌人的结构我们可以直接用本机的结构,我们直接初始化敌机,当然,我们敌机的照片也是有好几种的,我这里只加载了两种敌对飞机,如果你们想,其实可以在等主机把小飞机打完之后,绘制打飞机,大飞机的血量可以多点,大飞机也可以发射子弹,当主角解决完大飞机后,可以产生一个界面吗,问其是否要继续挑战,进入下一关,逻辑也是相当简单的。

    10,检测子弹是否打到敌机以及敌机是否碰到本机

    到这里,我们就完成了第一关的制作,后续如果可以根据你们的意愿去做其他的处理

    11,aircraft.h

    1. #pragma once
    2. #include <stdio.h>
    3. #include <string.h>
    4. #include <stdlib.h>
    5. #include <windows.h>
    6. #include <time.h>
    7. #include <easyx.h>
    8. #include <chrono>
    9. #include <vector>
    10. #define MOVE 5
    11. #define graph_height 700
    12. #define graph_width 480
    13. #define ENEMY_NUM 10//敌机数量
    14. #define BULLET_NUM 25//子弹数量
    15. //子弹图片有两张
    16. static IMAGE img_bullet[2];
    17. static IMAGE img_bk;//背景图
    18. static IMAGE img_gamer[2];//飞机图片
    19. static IMAGE img_enemy[2][2];//敌机图片
    20. //创建飞机结构
    21. typedef struct Plane
    22. {
    23. int x;//飞机坐标
    24. int y;
    25. bool isDie;//是否健在
    26. int width;//宽度
    27. int height;//长度
    28. int frame;//当前帧
    29. int hp;//血量
    30. int type;//敌机类型
    31. }Plane;
    32. //子弹结构
    33. typedef struct Bullet
    34. {
    35. int x;//坐标
    36. int y;
    37. bool isDie;//是否出界面以及碰到敌机
    38. }Bullet;
    39. //敌机类型
    40. enum enemyType
    41. {
    42. BIG,//大飞机
    43. SMALL//
    44. };
    45. //资源加载
    46. void Resource();
    47. //绘制函数
    48. void draw(Plane* gamer,Bullet* bullet, Plane* enemy);
    49. //初始化函数
    50. void init(Plane* gamer, Bullet* bullet, Plane* enemy);
    51. //透明贴图函数
    52. void drawImg(int x, int y, IMAGE* src);
    53. //定时器
    54. void timerFunction(int frameRate);
    55. //更新数据
    56. void Updata(Plane* gamer, Bullet* bullet, Plane* enemy);
    57. //void updateEnemyStatus(Plane* enemy);
    58. void checkCollision(Plane* gamer,Plane* enemy, Bullet* bullet);
    59. void createEnemy(Plane* enemy);

    12,aircraft.cpp

    1. #include "aircraft.h"
    2. class Timer {
    3. private:
    4. std::vector<std::chrono::steady_clock::time_point> startTimes;
    5. public:
    6. Timer() {}
    7. bool hasElapsed(int ms, int id) {
    8. if (id >= startTimes.size()) {
    9. startTimes.resize(id + 1);
    10. startTimes[id] = std::chrono::steady_clock::now();
    11. return true; // 重启计数器
    12. }
    13. auto now = std::chrono::steady_clock::now();
    14. auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - startTimes[id]);
    15. if (duration.count() >= ms) {
    16. startTimes[id] = now;
    17. return true;
    18. }
    19. return false;
    20. }
    21. };
    22. Timer timer;
    23. void enemyHP(int i, Plane* enemy)
    24. {
    25. int flag = rand() % 10;
    26. if (flag >= 0 && flag <= 1)
    27. {
    28. enemy[i].type = BIG;
    29. enemy[i].hp = 3;
    30. enemy[i].width = 169;
    31. enemy[i].height = 230;
    32. }
    33. else
    34. {
    35. enemy[i].type = SMALL;
    36. enemy[i].hp = 1;
    37. enemy[i].width = 57;
    38. enemy[i].height = 43;
    39. }
    40. }
    41. //资源加载
    42. void Resource()
    43. {
    44. //加载资源函数
    45. loadimage(&img_bk, "images/background.png");
    46. //加载玩家飞机图片
    47. loadimage(&img_gamer[0], "images/me1.png");
    48. loadimage(&img_gamer[1], "images/me2.png");
    49. //加载子弹图片
    50. loadimage(img_bullet + 0, "images/bullet1.png");
    51. loadimage(img_bullet + 1, "images/bullet2.png");
    52. //加载敌机图片
    53. loadimage(&img_enemy[0][0], "images/enemy1.png");
    54. loadimage(&img_enemy[0][1], "images/enemy1.png");
    55. loadimage(&img_enemy[1][0], "images/enemy2.png");
    56. loadimage(&img_enemy[1][1], "images/enemy2.png");
    57. }
    58. //绘制桌面
    59. void draw_graph()
    60. {
    61. //绘制函数
    62. putimage(0, 0, &img_bk);
    63. }
    64. //绘制飞机
    65. void draw_gamer(Plane* gamer)
    66. {
    67. //通过初始化的飞机结构,确定其位置和加载哪一张图片
    68. drawImg(gamer->x, gamer->y, &img_gamer[gamer->frame]);
    69. gamer->frame = (++(gamer->frame)) % 2;
    70. }
    71. //绘制子弹
    72. void draw_bullet(Bullet* bullet)
    73. {
    74. for (int i = 0; i < BULLET_NUM; i++)
    75. {
    76. //发射绘制第一张
    77. if (bullet[i].isDie)
    78. {
    79. drawImg(bullet[i].x, bullet[i].y, img_bullet + 0);
    80. }
    81. //碰到敌人或者墙壁我们绘制第二张(后续我们会更改)
    82. if(bullet[i].y == 0)
    83. {
    84. drawImg(bullet[i].x, bullet[i].y, img_bullet + 1);
    85. }
    86. }
    87. }
    88. 绘制敌机
    89. //void enemyDraw(Plane* enemy) {
    90. // // 绘制敌机
    91. // for (int num = 0; num < ENEMY_NUM; num++) {
    92. // if (!enemy[num].isDie) {
    93. // if (enemy[num].type == BIG) {
    94. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][0]);
    95. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][1]);
    96. // }
    97. // else if (enemy[num].type == SMALL) {
    98. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][0]);
    99. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][1]);
    100. // }
    101. // }
    102. // }
    103. //}
    104. // 创建敌机
    105. void createEnemy(Plane* enemy) {
    106. for (int i = 0; i < ENEMY_NUM; i++)
    107. {
    108. if (!enemy[i].isDie)
    109. {
    110. //创建随机坐标
    111. enemy[i].x = rand() % (getwidth() - 60);
    112. enemy[i].y = 0;
    113. enemyHP(i, enemy);
    114. enemy[i].isDie = true;//生成敌机
    115. break;
    116. }
    117. }
    118. }
    119. // 绘制敌机
    120. void enemyDraw(Plane* enemy) {
    121. //static int count = 0;
    122. for (int num = 0; num < ENEMY_NUM; num++)
    123. {
    124. if (enemy[num].isDie)
    125. {
    126. //printf("%d ", count++);
    127. if (enemy[num].type == BIG)
    128. {
    129. drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][0]);
    130. drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][1]);
    131. }
    132. else
    133. {
    134. drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][0]);
    135. drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][1]);
    136. }
    137. }
    138. }
    139. }
    140. //void enemyDraw(Plane* enemy) {
    141. // //绘制敌机
    142. // for (int num = 0; num < ENEMY_NUM; num++)
    143. // {
    144. // if (enemy[num].isDie)
    145. // {
    146. // if (enemy[num].type == BIG)
    147. // {
    148. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][0]);
    149. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[1][1]);
    150. // }
    151. // else
    152. // {
    153. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][0]);
    154. // drawImg(enemy[num].x, enemy[num].y, &img_enemy[0][1]);
    155. // }
    156. // }
    157. // }
    158. //
    159. //}
    160. //绘制函数
    161. void draw(Plane* gamer,Bullet* bullet, Plane* enemy)
    162. {
    163. draw_graph();
    164. draw_gamer(gamer);
    165. draw_bullet(bullet);
    166. enemyDraw(enemy);
    167. }
    168. void init_gamer(Plane* gamer,int x,int y)
    169. {
    170. gamer->x = x;
    171. gamer->y = y;
    172. gamer->isDie = false;
    173. gamer->frame = 0;
    174. gamer->hp = 100;
    175. gamer->width = 102;
    176. gamer->height = 126;
    177. }
    178. void init_bullet(Bullet* bullet)
    179. {
    180. for (int i = 0; i < BULLET_NUM; i++)
    181. {
    182. bullet[i].isDie = false;
    183. //bullet[i].x = x;
    184. //bullet[i].y = y;//我们这里通过按下空格键再去绘制它,所以在这里我们并不需要去更新坐标
    185. }
    186. }
    187. void init_enemy(Plane* enemy)
    188. {
    189. for (int i = 0; i < ENEMY_NUM; i++)
    190. {
    191. enemy[i].isDie = false;
    192. }
    193. }
    194. //初始化函数
    195. void init(Plane* gamer, Bullet* bullet, Plane* enemy)
    196. {
    197. //我们在初始化的时候就可以将,资源加载
    198. Resource();
    199. //初始化飞机
    200. init_gamer(gamer, ((getwidth() - img_gamer->getwidth()) / 2),
    201. (getheight() - img_gamer->getheight()));
    202. //(gamer->x) / 2, gamer->y + img_bullet->getheight()
    203. init_bullet(bullet);
    204. init_enemy(enemy);
    205. }
    206. void timerFunction(int frameRate) {
    207. clock_t startTime, currentTime;
    208. long elapsed;
    209. // 计算每一帧的毫秒数
    210. int ms_per_frame = 1000 / frameRate;
    211. // 获取初始时间
    212. startTime = clock();
    213. while (1) {
    214. // 获取当前时间
    215. currentTime = clock();
    216. // 计算已经过去的时间(以毫秒为单位)
    217. elapsed = (currentTime - startTime) * 1000;
    218. // 如果已经过去的时间超过了下一帧的时间间隔,则输出一帧
    219. if (elapsed >= ms_per_frame) {
    220. // 更新初始时间
    221. startTime = currentTime;
    222. // 暂停一段时间,使得每秒输出指定的帧率
    223. Sleep(1); // 暂停 1 毫秒
    224. break;
    225. }
    226. }
    227. }
    228. void createBullet(Plane* gamer, Bullet* bullet)
    229. {
    230. //循环遍历找到可用的子弹,进行发射
    231. for (int i = 0; i < BULLET_NUM; i++)
    232. {
    233. if (!bullet[i].isDie)
    234. {
    235. bullet[i].isDie = true;
    236. bullet[i].x = gamer->x + img_gamer->getwidth() / 2;
    237. bullet[i].y = gamer->y;
    238. break;
    239. }
    240. }
    241. }
    242. //移动飞机,发射子弹
    243. void palygamer(Plane* gamer, Bullet* bullet)
    244. {
    245. if (GetAsyncKeyState(VK_UP) && gamer->y > 0)
    246. {
    247. gamer->y -= MOVE;
    248. }
    249. if (GetAsyncKeyState(VK_DOWN) && gamer->y + img_gamer->getheight() < getheight())
    250. {
    251. gamer->y += MOVE;
    252. }
    253. if (GetAsyncKeyState(VK_LEFT) && gamer->x + img_gamer->getwidth() / 2 > 0)
    254. {
    255. gamer->x -= MOVE;
    256. }
    257. if (GetAsyncKeyState(VK_RIGHT) && gamer->x + img_gamer->getwidth() / 2 < getwidth())
    258. {
    259. gamer->x += MOVE;
    260. }
    261. if (GetAsyncKeyState(VK_SPACE) && timer.hasElapsed(100, 1))
    262. {
    263. createBullet(gamer, bullet);
    264. }
    265. }
    266. //子弹移动
    267. void movebullet(Bullet* bullet)
    268. {
    269. for (int i = 0; i < BULLET_NUM; i++)
    270. {
    271. if (bullet[i].isDie)
    272. {
    273. bullet[i].y -= MOVE;
    274. //如果子弹跑出窗口,则置为false
    275. if (bullet[i].y < 0)
    276. {
    277. bullet[i].isDie = false;
    278. }
    279. }
    280. }
    281. }
    282. //void moveEnemy(Plane* enemy)
    283. //{
    284. // for (int i = 0; i < ENEMY_NUM; i++)
    285. // {
    286. // if (enemy[i].isDie)
    287. // {
    288. // enemy[i].y += 3;
    289. // if (enemy[i].y > getheight() || enemy[i].hp <= 0)
    290. // {
    291. // enemy[i].isDie = false;
    292. // }
    293. // }
    294. // }
    295. //}
    296. // 移动敌机
    297. void moveEnemy(Plane* enemy) {
    298. for (int i = 0; i < ENEMY_NUM; i++)
    299. {
    300. if (enemy[i].isDie)
    301. {
    302. enemy[i].y += 3;
    303. if (enemy[i].y > getheight())
    304. {
    305. enemy[i].isDie = false;
    306. }
    307. }
    308. }
    309. }
    310. //碰撞检测
    311. void checkCollision(Plane* gamer,Plane* enemy, Bullet* bullet)
    312. {
    313. for (int i = 0; i < ENEMY_NUM; i++)
    314. {
    315. if (!enemy[i].isDie)
    316. continue;
    317. for (int j = 0; j < BULLET_NUM; j++)
    318. {
    319. if (!bullet[j].isDie)
    320. continue;
    321. if (bullet[j].x > enemy[i].x &&
    322. bullet[j].x < enemy[i].x + enemy[i].width &&
    323. bullet[j].y > enemy[i].y &&
    324. bullet[j].y < enemy[i].y + enemy[i].height)
    325. {
    326. bullet[j].isDie = false;
    327. enemy[i].hp--;
    328. }
    329. }
    330. if (enemy[i].hp <= 0) enemy[i].isDie = false;
    331. }
    332. for (int i = 0; i < ENEMY_NUM; i++)
    333. {
    334. if (gamer->x + gamer->width >= enemy[i].x &&
    335. gamer->x <= enemy[i].x + enemy[i].width &&
    336. gamer->y <= enemy[i].y + enemy[i].height &&
    337. gamer->y + gamer->height >= enemy[i].y)
    338. {
    339. //可以给一个窗口,问是否需要重来,或者可以加一些关机操作,都是没有问题的,根据你们想要的逻辑去改代码即可
    340. exit(1);
    341. }
    342. }
    343. }
    344. //void checkCollision(Plane* enemy, Bullet* bullet) {
    345. // if (!enemy || !bullet) {
    346. // // 参数验证失败,输出错误信息并返回
    347. // printf("Error: Invalid parameters in checkCollision function.\n");
    348. // return;
    349. // }
    350. //
    351. // for (int j = 0; j < ENEMY_NUM; j++) {
    352. // if (!enemy[j].isDie) {
    353. // continue;
    354. // }
    355. // for (int i = 0; i < BULLET_NUM; i++) {
    356. // if (!bullet[i].isDie) {
    357. // continue;
    358. // }
    359. //
    360. // if (bullet[i].x > enemy[j].x && bullet[i].x < (enemy[j].x + enemy[j].width)
    361. // && bullet[i].y > enemy[j].y && (bullet[i].y < enemy[j].y + enemy[j].height)) {
    362. // bullet[i].isDie = false;
    363. // enemy[j].hp--;
    364. // }
    365. // }
    366. // }
    367. //}
    368. //void updateEnemyStatus(Plane* enemy) {
    369. // if (!enemy) {
    370. // // 参数验证失败,输出错误信息并返回
    371. // printf("Error: Invalid parameters in updateEnemyStatus function.\n");
    372. // return;
    373. // }
    374. //
    375. // for (int j = 0; j < ENEMY_NUM; j++) {
    376. // if (enemy[j].hp == 0) {
    377. // enemy[j].isDie = false;
    378. // }
    379. // }
    380. //}
    381. //更新数据
    382. void Updata(Plane* gamer,Bullet* bullet, Plane* enemy)
    383. {
    384. //玩家移动
    385. palygamer(gamer, bullet);
    386. //子弹移动
    387. movebullet(bullet);
    388. //创建敌机
    389. if (timer.hasElapsed(1000, 1))
    390. {
    391. //printf("6");
    392. createEnemy(enemy);
    393. }
    394. //移动敌机
    395. moveEnemy(enemy);
    396. //子弹打到飞机
    397. checkCollision(gamer,enemy, bullet);
    398. }

    13,tools.cpp

    1. #include "aircraft.h"
    2. //把像素的颜色拆解出来 ARGB
    3. typedef struct _ARGB {
    4. byte a;
    5. byte r;
    6. byte g;
    7. byte b;
    8. }ARGB;
    9. //把颜色拆分
    10. ARGB color2Argb(DWORD c) {
    11. ARGB res;
    12. res.r = (byte)c;
    13. res.g = (byte)(c >> 8);
    14. res.b = (byte)(c >> 16);
    15. res.a = (byte)(c >> 24);
    16. return res;
    17. }
    18. DWORD argb2Color(ARGB c) {
    19. DWORD t = RGB(c.r, c.g, c.b);
    20. return ((DWORD)c.a) << 24 | t;
    21. }
    22. //把色彩图转成黑白图
    23. void toGray(IMAGE* src) {
    24. DWORD* psrc = GetImageBuffer(src);
    25. for (int i = 0; i < src->getwidth() * src->getheight(); i++) {
    26. //获取每一个像素点的颜色值
    27. ARGB t = color2Argb(psrc[i]);
    28. //灰度图,求三个或者四个颜色值的均值
    29. byte arv = (t.r + t.g + t.b) / 3;
    30. ARGB res = { t.a,arv,arv,arv };
    31. psrc[i] = argb2Color(res);
    32. }
    33. }
    34. /*
    35. * @png透明贴图
    36. */
    37. void drawImg(int x, int y, IMAGE* src) {
    38. // 变量初始化
    39. DWORD* pwin = GetImageBuffer();//窗口缓冲区指针
    40. DWORD* psrc = GetImageBuffer(src);//图片缓冲区指针
    41. int win_w = getwidth();//窗口宽高
    42. int win_h = getheight();
    43. int src_w = src->getwidth();//图片宽高
    44. int src_h = src->getheight();
    45. //计算贴图的实际长宽
    46. int real_w = (x + src_w > win_w) ? win_w - x : src_w;//处理超出右边界
    47. int real_h = (y + src_h > win_h) ? win_h - y : src_h;//处理超出右边界
    48. if (x < 0) {//处理超出左边界
    49. psrc += -x;
    50. real_w -= -x;
    51. x = 0;
    52. }
    53. if (y < 0) {//处理超出右边界
    54. psrc += (src_w * -y);
    55. real_h -= -y;
    56. y = 0;
    57. }
    58. //修正贴图起始位置
    59. pwin += (win_w * y + x);
    60. //实现透明贴图
    61. for (int iy = 0; iy < real_h; iy++) {
    62. for (int ix = 0; ix < real_w; ix++) {
    63. byte a = (byte)(psrc[ix] >> 24);//计算透明通道的值[0,256] 0为完全透明 255完全不透明
    64. if (a > 100) {
    65. pwin[ix] = psrc[ix];
    66. }
    67. }
    68. //换到下一行
    69. pwin += win_w;
    70. psrc += src_w;
    71. }
    72. }

    14,main.cpp

    1. #include "aircraft.h"
    2. int main()
    3. {
    4. Plane gamer;
    5. Bullet bullet[BULLET_NUM];
    6. Plane enemy[ENEMY_NUM];
    7. //创建窗口函数
    8. initgraph(graph_width, graph_height, 1);
    9. //获取当前时间
    10. init(&gamer, bullet, enemy);
    11. BeginBatchDraw();//双缓冲
    12. while (1)
    13. {
    14. draw(&gamer, bullet, enemy);
    15. FlushBatchDraw();//立即刷新缓冲区
    16. Updata(&gamer, bullet, enemy);
    17. timerFunction(60);
    18. //checkCollision(enemy, bullet);
    19. }
    20. EndBatchDraw();//结束缓冲
    21. return 0;
    22. }

    15,每期一问

    1. 上期答案:
    2. #define MY_OFFSETOF(s, m) ((size_t)(&(((s*)0)->m)))

    本期问题:

    环形链表的约瑟夫问题_牛客题霸_牛客网

    下期再见!

  • 相关阅读:
    软件设计师_面向对象_学习笔记
    股价暴跌了74.5%后,乐信第三季度财报可能会低于市场预期
    基于Three.js实现三维空间中的箭头移动动画
    IE退役倒计时, Edge接棒
    java计算机毕业设计机械生产企业办公设备管理系统MyBatis+系统+LW文档+源码+调试部署
    工作中一些计算日期的要求
    数据结构中常见的排序及其代码C语言版本
    【MySQL】Java的JDBC编程
    webpack5零基础入门-10babel的使用
    弱监督下的学习对象检测
  • 原文地址:https://blog.csdn.net/HH_KZ1314/article/details/137557239