C语言 FlappyBird×马里奥

在这里插入图片描述

《C语言 FlappyBird打马里奥》

(项目效果展示地址,源码也在此B站视频的介绍中!!!https://www.bilibili.com/video/BV1wC4y1Y7na

期 末 项 目 设 计

摘要:
《FlappBird》是一款形式简易但难度颇高的休闲游戏。玩家需要不断控制点击屏幕的频率来调节小鸟的飞行高度和降落速度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟不小心擦碰到了管子的话,游戏便宣告结束。通过EasyX图形库让界面变得友好,程序通过图形更加美观。为了增加创新性,结合了《马里奥耀西的复仇》这款游戏的一些元素加载进入,降低了游戏的难度。小鸟将拥有子弹,血量等元素,获取的积分不再是通关管道数,而是要吃到空中的金币。地图新增怪物提高游戏的新鲜感,并且以马里奥作为小Boss阻扰小鸟的前进。

关键词:EasyX;创新元素;小鸟;马里奥;

目 录

绪 论

一.程序分析

二.开发平台及技术基础

三.系统实现

四.重难点分析及解决方案

五.系统不足与展望

六.结 论

七.参考文献

八.致 谢

绪论

开发背景

《flappy bird》是一款由来自越南的独立游戏开发者Dong
Nguyen所开发的作品,游戏于2013年5月24日上线,并在2014年2月突然暴红。2014年2月,《FlappyBird》被开发者本人从苹果及谷歌应用商店撤下。2014年8月份正式回归APP
STORE,正式加入Flappy迷们期待已久的多人对战模式。游戏中玩家必须控制一只小鸟,跨越由各种不同长度水管所组成的障碍。

研究意义

这是一款简单又困难的手机游戏,游戏中玩家必须控制一只胖乎乎的小鸟,跨越由各种不同长度水管所组成的障碍。上手容易,但是想通关可不简单。Flappybird 于2013年5月在苹果Appstore上线,2014年2月份在100多个国家/地区的榜单一跃登顶,尽管没有精细的动画效果,没有有趣的游戏规则,没有众多的关卡,却突然大火了一把,下载量突破5000万次。

国内外研究现状

目前网上很少有该款游戏与其他游戏相结合,所以用《FlappyBird》与《马里奥耀西的复仇》联合制作新鲜感相对不少。

本文的研究内容及主要解决的问题

游戏利用现在比较流行以EasyX图形库和MySQL数据库的架构实现的。包含数据库的读取,删除,修改,查找;EasyX图形库打印输出函数,鼠标操作,按键处理,输入等大部分函数。结合了C语言的指针,结构体,数组等等应用。

论文的组织结构

第1章,程序可行性分析:技术可行性和操作可行性。

第2章,介绍系统的开发平台和一些关键技术的说明。

第3章,大致程序的各个模块已经整体架构。

第4章,重难点分析:对程序的几个模块进行分析以及处理方法。

第5章,思考程序存在的不足,整理相应的解决方案。

一.程序分析

1.1 需求分析

(一).程序界面基础框架的实现:玩家选择:“开始游戏”,“查看排行榜”。

开始游戏:玩家通过鼠标点击,进入游戏界面。

查看排行榜:通过后台连接MySQL数据库,读取数据并显示到图形界面上。

  1. .游戏的运行:不断打印出图形(小鸟,柱子,路,背景等等),进行图形之间的交互,不断反馈给程序函数,根据不同的结果操作调用不同的函数。为防止闪屏,可使用批量绘图函数来处理。

  2. .其他功能:为增加界面的友好性与游戏体验效果,对一些细节进行处理。增加多线程音效,鼠标按钮的灰暗程序,路不断滑动等等细节。

二.开发平台及技术基础

2.1.1 Visual Studio

Microsoft Visual
Studio
(简称VS)是美国微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等。所写的目标代码适用于微软支持的所有平台,包括Microsoft Windows、Windows
Mobile、Windows CE、.NET Framework、.NET Compact Framework和Microsoft Silverlight 及Windows Phone。Visual
Studio
是最流行的Windows平台应用程序的集成开发环境。最新版本为Visual Studio 2019 版本,基于.NET Framework 4.8 。

2.1.1 MySQL

MySQL是一个开放源码的小型关联式数据库管理系统,开发者为瑞典MySQL
AB公司。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。

MySQL的特性:使用C和C++编写,并使用了多种编译器进行测试,保证源代码的可移植性,支持多种操作系统。为多种编程语言提供API。这些编程语言包括C、C++、Eiffel、Java、Perl、PHP、Python和Ruby等。支持多线程充分利用CPU资源。优化的SQL查询算法,有效地提高查询速度。既能够作为一个单独的应用程序应用在客户端服务器网络环境中,也能够作为一个库而嵌入到其他的软件中提供多语言支持,常见的编码如中文的GB2312、BIG5都可以用作数据表名和数据列名。提供TCP/IP、ODBC和JDBC等多种数据库连接途径。提供用于管理、检查、优化数据库操作的管理工具。可以处理拥有上千万条记录的大型数据库。

MySQL的应用:与其他的大型数据库例如Oracle、DB2、SQLServer等相比,MySQL自有它的不足之处,如规模小、功能有限(MySQLCluster的功能和效率都相对比较差)等,但是这丝毫也没有减少它受欢迎的程度。对于一般的个人使用者和中小型企业来说,MySQL提供的功能已经绰绰有余,而且由于MySQL是开放源码软件,因此可以大大降低总体成本。

2.2.1 EasyX图形库

EasyX 是针对 C++ 的图形库,可以帮助 C/C++ 初学者快速上手图形和游戏编程。

比如,可以基于 EasyX图形库很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏,可以练习图形学的各种算法,等等。

许多人学编程都是从 C 语言入门的,而目前的现状是:

1. 有些学校以 Turbo C 为环境学习 C 语言,只是 Turbo C
实在太老了,复制粘贴都很不方便。

2. 有些学校直接拿 VC 来讲 C 语言,因为 VC 的编辑和调试环境都很优秀,并且 VC有适合教学的免费版本。可惜在 VC里面只能做一些文字性的练习题,想画条直线或一个圆都很难,例如需要注册窗口类、建消息循环等等,初学者会受严重打击的。初学编程想要绘图就得用
TC,很是无奈。

3. 还有计算机图形学,这门课程的重点是绘图算法,而不是 Windows编程。所以,许多老师不得不用 TC 教学,因为 Windows绘图太复杂了,会偏离教学的重点。新的图形学的书有不少是用的OpenGL,可是门槛依然很高。

2.3 本章小结

本章主要介绍了系统的开发平台和相关基础技术,从技术层面来说明开发本系统的可行性是成立的。

三.系统实现

3.1 游戏整体框架设计

1.初始化游戏界面:不断打印小鸟和路,实现小鸟的飞行模拟和路的不断移动。

在这里插入图片描述

图3-1 初始界面
  1. 进入游戏界面的初始动画:同样小鸟和路不断打印,实现动态效果,由于右边要出现敌人,所以将小鸟放在界面偏左边一点,防止玩家反应过慢而导致游戏直接结束。

在这里插入图片描述

图3-2 游戏开始动画
  1. 查看排行榜数据:本系统采用MySQL作为后台数据库系统。从技术性能上讲,MySQL也是相当出色,一向以高性能和高稳定著称。相关表是设计:
物理字段逻辑字段类型约束小数点
主键ididvarchar(255)主键0
玩家签名namevarchar(255)非空0
所得分数scoreint非空0
表3-3 玩家数据设计

在这里插入图片描述

3-4 查看玩家排行榜

4. 游戏模块:进行游戏。

在这里插入图片描述

3-5 开始游戏

3.4 本章小结

本章介绍了程序各个模块,大致实现效果。

四.重难点分析及解决方案

4.1 游戏界面设计

游戏界面比较难的是对游戏鼠标的处理,因为当鼠标出现在图标选择上面的时候,要是图标出现灰色按钮,如图4-1。实际上是重新打印这张图片,但是当鼠标移开的时候,需要打印原来那种图片,所以这里需要用到循环语句,不断判断鼠标当前的位置,从而给相应的变量赋值,当退出鼠标代码处理模块的时候,用if条件语句判断是否打印原来的图片。

在这里插入图片描述

图4-1 图标选择

鼠标操作部分代码(其他界面同样应用该原理,不再复述):

1.  //鼠标操作

2.  while (MouseHit())

3.  {

4.  MOUSEMSG mouse = GetMouseMsg();

5.  //是否出现灰色按钮

6.  switch (mouse.uMsg)

7.  {

8.  case WM_LBUTTONDOWN://左键按下

9.  if (25 \<= mouse.x&& mouse.x \<= 129 && 449 \<= mouse.y && mouse.y \<=
    511)//判断是否为开始游戏按钮

10. {

11. chooseButton = 1; //执行游戏代号

12. }

13. else if (145 \<= mouse.x&& mouse.x \<= 249 && 449 \<= mouse.y && mouse.y \<=
    511)//判断是否为开始游戏按钮

14. {

15. chooseButton = 2;//查看游戏排行榜代号

16. }

17. break;

18. }

19. }

代码解释:

第4行:声明一个鼠标句柄。

第6-16行:判断鼠标是否按下键,并给功能键选择一个功能编号,以便于进入下一个模块。

主体界面:

在这里插入图片描述

图4-2主体界面

当小鸟死亡时,出现的计分的界面(左图为正常情况,右图为刷新纪录时):
在这里插入图片描述
在这里插入图片描述

图4-3 死亡界面

PS:图4-3右边那张背景是当小鸟的分数为10的倍数时间接打印,例如分数区间在1-10为白天,11-20为黑夜,21-30为白天…依次循环下去。

4.2 小鸟相关功能

小鸟系统是整个游戏的核心点,在整个代码中占有约20%。在玩家手中,小鸟主要有两个操作:飞行和发射子弹。通过按下“空格键”使小鸟获得一个向上的位移,参照了重力加速等理论,改良小鸟上升和下坠的视觉效果体验。通过“z/Z”字母发射子弹,用了一个数组结构体来存储子弹。为限制玩家无限使用子弹,设置了子弹上限数量为5,也就是说,一个屏幕最多出现5颗子弹。

在这里插入图片描述

图4-4 小鸟系统

小鸟拥有血量属性,并且在敌人中设置了一个天鹅,如果玩家把天鹅消灭,则天鹅会爆出一颗蛋。如果玩家再次将蛋消灭,那么玩家将升级,由原先的2滴血升级为3滴血,提高生存概率。但是游戏保留了原版《Flappy Bird》中小鸟撞击柱子或者上下边界,将直接死亡的特点。如果玩家被敌人撞击,将失去1滴血,知道没有血将直接死亡。同时,为增强小鸟的生存性,当小鸟被敌人碰到,但没有死亡时,小鸟将出现短暂的无敌状态,并且不断出现闪烁效果,利用了大多数游戏的特点。

在这里插入图片描述

图4-5 升级蛋

为了不让游戏感觉生硬,小鸟实际上有3张图,主要的区别在翅膀上面。不断打印这三张图,可让玩家感觉小鸟真的在扇动翅膀飞行。

在这里插入图片描述

图4-6 小鸟

小鸟死亡坠落时,头应该向下,所以要重新绘图。不断调整小鸡结构体的y坐标,从而实现下坠动作。为防止出现批量打印时,小鸟下坠出边界线,增加了一个循环,判断当小鸟接近下边界时,出现在412-512像素内是,直接打印小鸟坐标到刚好接触边界线的位置。

图4-7 小鸟坠落

4.3 柱子移动循环

柱子实际上是通过一个数组结构体,数组下标为3来存储打印。初始化时随机初始柱子的x坐标,柱子的y坐标移动速度是10,向并右。

1.  for (int i = 0; i \< 3; i++) //加载柱子和金币,花的坐标

2.  {

3.  initPillar(Array, goldArray, i, flowerArray1, flowerArray2);

4.  Array[i].x = 275 + i \* 200;

5.  goldArray[i].x = 275 + 21 + i \* 200; //定义金币的x坐标

6.  flowerArray1[i].x = 275 + 11+i\*200; //定义食人花1

7.  flowerArray2[i].x = 275 + 11 + i \* 200; //定义食人花2

8.  }

代码解释说明:

第3行代码:初始化柱子的坐标,并且加载食人花,金币的坐标,因为食人花会有一定的概率从柱子中慢慢出来,金币切好在上下柱子的正中间,所以这里一并初始化。

第4-7行代码:同上,初始化食人花,柱子,金币的坐标。因为这是游戏开始之前的初始化加载,当游戏进行时,还需要调用initPillar()函数,所以这里要重新初始化一遍。

在这里插入图片描述

图4-8 柱子的颜色

这里在初始化柱子坐标的时候,随便初始化柱子的颜色,增加界面的美观性,显得不是那么单调。同理游戏一些其他图形做了一些简单的修饰,不再复述。

柱子的核心移动:当柱子x移动到(-52-272)像素的时候,则初始化柱子的坐标,调用initPillar()函数,并传入相应的数据。每个柱子相差的像素是200px,柱子宽52px,柱子中间有一定概率出现怪物,但小鸟碰撞到这里的怪物几乎不大可能,只能作为一种装饰。

4.4 怪物随机出现

普通怪物有乌龟,导弹,天鹅,幽灵,精灵等等,分别有不同的血量。这里的怪物都不会发射子弹,并且如果碰撞到小鸟,那么小鸟将失去1滴血。同理,若小鸟的子弹碰撞到怪物,则会减少怪物的血量,直到怪物血量为0,则出现死亡特效,否则当到达左边界的时候,会初始化怪物的属性。

1.  struct Missile \*pMissile = &missileStruct; //指针结构体

2.  //先判断是否有boss

3.  if (BossButton != 'y' \|\| pMissile-\>x \> -30)

4.  {

5.  if (BossButton != 'y') //在没有boss的情况下才出现

6.  {

7.  pMissile-\>fireMissile++;//增加子弹发射的几率

8.  }

9.  //打印出导弹,满足一定的条件时

10. if (pMissile-\>fireMissile % 60 == 0)

11. {

12. int choose = rand() % 100;

13. if (choose \<= 50) //判断到达条件则发射导弹

14. {

15. missileStruct = { 275,200,0,1,15,'n',0 }; //导弹结构体

16. pMissile-\>y = rand() % 265 + 150; //导弹初始化的y坐标为[150,415]

17. pMissile-\>color = rand() % 4; //初始化导弹的颜色

18. pMissile-\>key = 1; //要打导弹

19. pMissile-\>fireMissile = 1; //初始化

20. }

21. }

22. //是否要打印导弹

23. if (pMissile-\>key == 1)

24. {

25. drawMissile(); //画导弹

26. pMissile-\>x -= pMissile-\>speed; //移动导弹

27. if (pMissile-\>x \<= -30) //初始化导弹坐标

28. {

29. pMissile-\>key = 0;

30. pMissile-\>x = -30;

31. }

32. }

代码解释:

第1行代码:这里利用指针引用导弹结构体;

第3行代码:判断是否满足发射导弹的条件,不断增加概率;

第25行代码:画导弹图形。

在这里插入图片描述在这里插入图片描述

图4-9 导弹和食人花

其他怪物和这里类似,同样利用指针技术,进行相应赋值,处理,条件判断。然后对于怪物碰撞小鸟用一个if条件判断语句就够了:

1.  if ((missileStruct.x \<= flayBird.x + 34 && missileStruct.x + 30 \>=
    flayBird.x)

2.  && (missileStruct.y + 26 \>= flayBird.y && missileStruct.y \<= flayBird.y +
    24))

3.  {

4.  missileStruct.eatChoose = 'y'; //表示导弹撞到小鸟,导弹撞开嘴巴

5.  return 1;//返回给调用该函数结果

6.  }

7.  else

8.  {

9.  return 0;//返回给调用该函数结果

10. }

代码解释:

第1-2行代码:判断导弹是否撞击小鸟,小鸟长34px,宽24px。这里判断代码已经说得比较详细。

其他怪物大多如此,有些的判断与此处有点差异,但原理都是如此。

在这里插入图片描述
在这里插入图片描述

图4-10 幽灵和蛋

4.5 Boss相关处理

以马里奥作为Boss,但不会只出现一次。游戏调整为大约小鸟每越过大约30个柱子,就会出现马里奥。马里奥拥有10滴血,并且有4个动作,每个动作出现的概率都是25%。但是每个动作作用的时间不同,“子弹”和“正常”两个模块的时间较短,跳跃的时间最长。

在这里插入图片描述

图4-11 Boss系统

比较难处理的是马里奥的出场与入场。因为当判断Boss应该出现时,此时应该还有柱子没有完全像左移出边界,并且还有一些怪物之类的。所以这里要进行判断,当柱子和怪物完全移出左边界的时候,此时Boss应该出现,中间不会出现让柱子和怪物突然消失的bug,进行完美的衔接。

如图4-12,展示Boss在发射子弹后,会进行下一个动作,在完成一个模块动作之后同样不会停留。

在这里插入图片描述
在这里插入图片描述

图4-12 Boss躲避和跳跃

在处理Boss死亡时,在马里奥下面和上面的柱子应该向右移出。之后,重新初始化普通柱子,并逐渐向左移动。重点在于初始化的时候只进行一次,如果仅仅根据判断Boss是否死亡,条件是不充分的。因为在Boss死亡后,还有Boss上下的柱子移出,也要花一定的时间,在此时间段,会不断初始化普通柱子的坐标,导致出现卡屏。所以这里的解决方案是在此判断Boss死亡条件基础上,再增加判断死亡后的柱子是否移出右边界的情况,
以此解决出现的bug。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

图4-13 马里奥动作

4.6游戏音效加载

由于游戏的怪物,小鸟的跳跃等等都需要音效,用多线程能更好解决此问题。这里利用了简单的多线程知识。mciSendString字段是调用相关的音频处理语句,需要用到

#include <mmsystem.h>
#pragma comment(lib,"libmysql.lib")

两个编译预处理。

部分播放音效代码(其他音效同理):

1.  //播放小鸟升级音乐

2.  DWORD WINAPI playMusicEgg(LPVOID lpParame)

3.  {

4.  mciSendString("open Resources/egg.mp3 alias music", 0, 0,
    0);//''alias''给音乐文件起别名

5.  mciSendString("play music wait", 0, 0, 0);//等待音乐播放完

6.  mciSendString("close music", 0, 0, 0);//关闭文件

7.  return 0;

8.  }

4.7 数据库操作

在连接数据库之后,进行数据库相关处理。在开始游戏之后,程序会连接数据库,并获取数据库中玩家最高的分数。当小鸟死亡的时候,会出现“BEST”表示游戏记录的最高分数,若玩家刷新记录,会出现“new”和金牌而不是铜牌。在每次游戏结束后,都会自动保存玩家的数据,获取的分数。并将此分数拿到数据库进行比较,若玩家的分数在前五,且签名已有,说明是同一个玩家,只需要更新分数的操作,对数据进行处理即可。

在这里插入图片描述

图4-14 游戏结束分数

其中中间的“NAME”是用于玩家修改签名,暂时只支持英文。玩家点击它,会弹出一个小窗口,玩家根据提示信息输入相关数据,也可以取消。默认玩家的名字为“Player”,只有玩家的记录进入前五才会保存到数据库,否则会不保存,进行删除操作。

在这里插入图片描述

图4-15 修改签名窗口

4.8本章小结

本章就详细设计一章中的模块里重难点进行了单独讨论,更加细致,清楚的展现实现原理和过程。

六.系统不足与展望

由于刚开始做,不是很有经验,写了4500多行代码,其中有很多重复累赘的代码,没有进行更好的优化。有几次把电脑写死机了,苦笑不得,其中的while循环用了很多,导致许多变量没有得到释放,内存占用过大,在进行断点处理CPU过高,导致程序崩溃。后期不断进行改良,主体用一个while循环,用switch语句来调用相关模块,并返回。

反馈给一些朋友进行建议,说Boss有点傻。的确如此,Boss怎么才有四个动作,感觉有点机械一样。对此没有进行更好的优化,比如Boss可以飞行或者召唤小怪兽,继续增加创新性。

普通怪物并没有写很多,感觉就只是换了一个图形,还需要一定新鲜元素。比如增加小鸟通过管道的元素,小鸟外观的升级,界面功能选择多一点,增加背景音乐,调节音乐的大小等等。其实还有需要完善的地方,可借鉴的一些手机单机游戏的一些元素,丰富游戏的可玩性。

七.结 论

本次期末项目设计,陆陆续续大概花了一个月左右的时间,每天花一定的时间完成某项功能。此次项目是写的时间最长,代码量最大,耗费的精力也最多。利用了指针,数据库,数组,结构体等等重点。

在完成此项目之后,感觉受益颇多。对知识点不断巩固与强化,综合运用所学的知识,对整个项目代码管理也有了许多的经验。对功能模块化繁为简,优化处理,有更多的了解。对项目流程设计与文档编写也更加熟悉。

总体来说,在编写代码之前应该有一个思考的过程,不能盲目编写代码,否则很容易导致后期返工,浪费大量时间。

八.参考文献

  1. 叶胜安,鄢涛.C语言综合项目实战.科学出版社,2015

  2. https://www.baidu.com/

  3. https://easyx.cn/

九.致 谢

首要感谢各位老师网课拍摄的教程视频,学会了很多东西。也感谢EasyX库文档编写者的技术文档支持。以及网友分享的经验。

其次,感谢百度,CNSD的等资源的提供,有了素材等等制作项目。 最后也感谢自己,坚持也是一种习惯,不然完成不了这个项目。

  • 6
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值