每天一个c语言小项目,提升你的编程能力!
【第一版】
花了一天时间,用 easyx 做了一个小游戏,程序中所有的类函数都是内联函数,大约 300 行。
【第二版】
主要做了代码优化,加强可读性。
同时改了操作方式,玩家和敌人都可以在 x、y 方向上移动,敌人每隔一段时间会随机换向。
游戏运行截图如下:
操作方式
玩家通过方向键移动,z 键射击,左 shift 进入低速移动模式提高操作精度。
代码说明
关于无阻塞延时,首先,先要 ctime 创建一个 clock_t 变量 a,初始化为 clock(),貌似是自从 1970 年到现在的毫秒数。
我们要每隔 0.5 秒执行函数 func() 一次。
那么创建主循环 while(1),调用前用 clock() - a;如果 clock() - a > 500,那么执行 func(),并把 a 重新赋值为 clock()。
如果使用 sleep(500) 的话,这个循环就只能执行 func 函数了,在此期间什么也做不了。
代码展示: (直接上源码,大家可以看注释)
/* 作者:stf(qq:2292683261)*/#include #include #include void hp_bar();void show_player();void show_enemy();void move_enemy();void draw_background();int generate_line(); // 若返回 -1,表示生成线条失败int create_p_b(); // 创建自机的子弹int create_e_b(); // 创建敌机的子弹int destroy_p_b(int index);int destroy_e_b(int index); // 删除一个子弹#define framerate 20 // 画面刷新的周期(ms)#define firerate 350 // 射击间隔时间#define e_firerate 350 // 敌人射击间隔#define bleed_time 150 // 受伤闪烁时间#define background 80 // 绘制背景线条的周期#define max_lines 75 // 最多同屏背景线条数目#define max_player_bullets 40 // 最多同屏自机子弹数目#define max_enemy_bullets 40 // 最多同屏敌机子弹数目int player_pos[2] = { 30,30 }; // 自机位置xyint enemy_bullet[max_enemy_bullets][2]; // 敌人的子弹位置int player_bullet[max_player_bullets][2]; // 自机的子弹位置int enemy_pos[2] = { 580,240 }; // 敌机位置bool p_b_slots[max_player_bullets] = { false }; // 用于判断 player_bullet 的某个位置是否可用bool e_b_slots[max_enemy_bullets] = { false };int number_p_b = 0, number_e_b = 0; // 记录自机和敌机的子弹数,减少遍历压力int player_health = 100, enemy_health = 100;bool isbleeding_p = false, isbleeding_e = false; // 用于实现命中后的闪烁效果int background_line[max_lines][3]; // 背景的线条,三个参数分别是 x、y、长度bool line_slots[max_lines] = { false };int number_lines = 0; // 记录背景线条数目clock_t begin_time = 0;int main(){ initgraph(640, 550, 4); srand((unsigned)time(null)); settextcolor(rgb(0, 254, 0)); settextstyle(30, 0, l微软雅黑); outtextxy(50, 200, l方向键移动, z 攻击, 左 shift 切换低速模式); bool win = false, dead = false; clock_t firerate = clock(); // 射击控制 clock_t e_firerate = clock(); // 控制敌机的射击 clock_t runtime = clock(); // 用于控制画面刷新频率 clock_t bleed_p = clock(), bleed_e = clock(); // 用于实现受伤闪烁 clock_t backgroundline_generate = clock(); // 用于生成背景线条 sleep(3000); beginbatchdraw(); bool leftshift = false; begin_time = clock(); while (true) { if (clock() - runtime >= framerate) { runtime = clock(); cleardevice(); draw_background(); hp_bar();// 画血条 show_player(); show_enemy(); int n_p_b = 1, n_e_b = 1; // 计数,遍历子弹,刷新位置 int p_b_toprocess = number_p_b, e_b_toprocess = number_e_b; // 需要处理的子弹数 for (int i = 0; i < max_player_bullets && (n_p_b <= p_b_toprocess || n_e_b <= e_b_toprocess); ++i) { if (n_p_b = 635) { destroy_p_b(i); // 到达了屏幕最右端 } // 碰撞检测,两个矩形 if ((player_bullet[i][0] + 5 >= enemy_pos[0] - 20 && player_bullet[i][0] - 5 <= enemy_pos[0] + 20) && (player_bullet[i][1] - 5 enemy_pos[1] - 40)) // 击中敌人 { destroy_p_b(i); enemy_health -= 8; isbleeding_e = true; bleed_e = clock(); } fillrectangle(player_bullet[i][0] - 5, player_bullet[i][1] - 5, player_bullet[i][0] + 5, player_bullet[i][1] + 5); // 画子弹 } } if (n_e_b <= e_b_toprocess) // 敌人的子弹 { if (e_b_slots[i] == true) { ++n_e_b; enemy_bullet[i][0] -= 3; setfillcolor(rgb(255, 180, 20)); if (enemy_bullet[i][0] < 5) { destroy_e_b(i); } // 碰撞检测,两个矩形 if (enemy_bullet[i][0] - 5 player_pos[0] - 25 && enemy_bullet[i][1] - 5 player_pos[1] - 25) { // 击中自机 isbleeding_p = true; destroy_e_b(i); player_health -= 8; bleed_p = clock(); } fillrectangle(enemy_bullet[i][0] - 5, enemy_bullet[i][1] - 5, enemy_bullet[i][0] + 5, enemy_bullet[i][1] + 5); } } } if (win || dead) break; flushbatchdraw(); move_enemy(); if (player_health <= 0) dead = true; if (enemy_health = 28) if (leftshift) player_pos[1] -= 2; // y 的正方向是向下的 else player_pos[1] -= 5; } if (clock() - firerate >= firerate && getasynckeystate('z') & 0x8000) // 玩家开火 { firerate = clock(); create_p_b(); } if (getasynckeystate(vk_down) & 0x8000) // 玩家移动 { if (player_pos[1] = 30) if (leftshift) player_pos[0] -= 2; else player_pos[0] -= 5; } if (getasynckeystate(vk_right) & 0x8000) // 玩家移动 { if (player_pos[0] = e_firerate) { e_firerate = clock(); create_e_b(); } if (clock() - bleed_p >= bleed_time) // 受伤时间结束后关闭受伤闪烁效果 { isbleeding_p = false; } if (clock() - bleed_e >= bleed_time) // 受伤时间结束后关闭受伤闪烁效果 { isbleeding_e = false; } if (clock() - backgroundline_generate >= background) { backgroundline_generate = clock(); generate_line(); } } } if (win) { settextcolor(rgb(0, 254, 0)); settextstyle(35, 0, l黑体); outtextxy(150, 200, l你打败了boss!你赢了!!); } else { settextcolor(rgb(254, 0, 0)); settextstyle(35, 0, l黑体); outtextxy(140, 200, l你被boss打败了!); } flushbatchdraw(); sleep(5000); endbatchdraw(); return 0;}void hp_bar(){ setlinecolor(rgb(255, 255, 255)); line(0, 481, 640, 481); // 一条分割线 settextstyle(20, 0, l黑体); outtextxy(10, 485, lboss的生命值:); outtextxy(10, 520, l玩家的生命值:); setfillcolor(rgb(0, 255, 1)); setlinecolor(white); rectangle(160, 515, 560, 540); // 血条外框 setfillcolor(rgb(0, 255, 1)); setlinecolor(rgb(255, 255, 255)); if (player_health > 0) fillrectangle(160, 515, 160 + player_health * 4, 540); // 玩家血条 setlinecolor(white); rectangle(160, 485, 560, 510); // 敌人血条外框 setfillcolor(rgb(230, 0, 1)); setlinecolor(rgb(255, 255, 255)); if (enemy_health > 0) fillrectangle(160, 485, 160 + enemy_health * 4, 510); // 敌人血条}void show_player(){ if (isbleeding_p) setfillcolor(rgb(255, 0, 0)); else setfillcolor(rgb(150, 180, 210)); fillrectangle(player_pos[0] - 25, player_pos[1] - 25, player_pos[0] + 25, player_pos[1] + 25); setfillcolor(rgb(100, 200, 180)); fillrectangle(player_pos[0], player_pos[1] + 5, player_pos[0] + 40, player_pos[1] - 5);}void show_enemy(){ if (isbleeding_e) setfillcolor(rgb(255, 0, 0)); else setfillcolor(rgb(0, 130, 125)); fillrectangle(enemy_pos[0] - 20, enemy_pos[1] - 40, enemy_pos[0] + 20, enemy_pos[1] + 40); setfillcolor(rgb(100, 200, 180)); fillrectangle(enemy_pos[0], enemy_pos[1] + 5, enemy_pos[0] - 40, enemy_pos[1] - 5);}void move_enemy(){ static bool angle_v; // 控制敌机的竖直移动方向,true 为向上,到边缘就换向 static bool angle_h; // 控制敌机的水平移动方向,true 为向左,到边缘就换向 static clock_t interval; // 定时随机换向 if (clock() - interval >= 2000) { interval = clock(); if (rand() % 2) // 一般的概率换向 angle_v = !angle_v; if (rand() % 2) angle_h = !angle_h; } if (angle_v == true) // 到了地图边缘就调头 enemy_pos[1] -= 3; else enemy_pos[1] += 3; if (angle_h == true) enemy_pos[0] -= 3; else enemy_pos[0] += 3; if (enemy_pos[1] >= 440) angle_v = true; else if (enemy_pos[1] = 580) angle_h = true; else if (enemy_pos[0] <= 380) angle_h = false;}void draw_background(){ setlinecolor(white); int n_b_l = number_lines; // 待处理线条数目 for (int i = 0; i 0); ++i) { if (line_slots[i] == true) { if (background_line[i][0] + background_line[i][2] = max_lines) return -1; ++number_lines; for (int i = 0; i max_player_bullets) // 空间不够 return -1; for (int i = 0; i max_enemy_bullets) // 空间不够 return -1; for (int i = 0; i max_player_bullets - 1) return -2; if (p_b_slots[index] == false) return -1; p_b_slots[index] = false; --number_p_b; return 0;}int destroy_e_b(int index){ if (index > max_enemy_bullets - 1) return -2; if (e_b_slots[index] == false) return -1; e_b_slots[index] = false; --number_e_b; return 0;} 大家赶紧去动手试试吧!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到c语言c++项目案例,帮助大家在学习c语言的道路上披荆斩棘!
紫光\建兴联合投资1亿美元开建SSD固态硬盘开发、制造工厂
区块链怎样打造接地气的服务平台
台积电已安装全球超过一半的EUV光刻机,7nm工艺愈发醇熟
北京市政协委员、芯盾时代创始人、董事长郭晓鹏郭晓鹏受邀参加新兴市场国家和发展中国家(EMDC)发展合作
分析法国的“太阳能公路”失败和中国的不尽人意
C/C++项目实战:2D射击游戏开发(简易版)
聚合物锂电芯优点_聚合物锂电芯缺点
基于ATMEGA16的高精度低压无功功率补偿器
LED植物照明的发展趋势如何
数字化营销服务商「直客通」宣布完成5000万美元D轮融资
5G时代的泛娱乐将实现定制化智能化和场景化的高度渗透融合
民营火箭成功首飞的背后液体火箭和固体火箭的区别详解
一文带你学会如何使用电机的开关设备
玄铁杯全球RISC-V应用创新大赛开赛,RISC-V量产硬件可使用RT-ThreadSmart!
芯片驱动内阻是不是越小越好,上升沿的斜率是不是越陡越好?
电子元器件筛选方案有哪些?
光电混合缆是光纤还是电缆?怎样使用光电混合缆呢?
下一个十年的存储趋势是怎样的(下)
苹果获“圆形显示器”专利,Apple Watch将变脸?
最全的PLC通讯电缆编程电缆自制详解(图)