大一——我写的第一个小游戏

less than 1 minute read

之前说到C语言课程中,老师允许我们做大作业的形式来代替普通作业。这里就写一下我做这个大作业的完整经历。

当时老师给我们(整个班大概有三个人报了名)提的建议是,可以做游戏,可以做一个功能齐全的计算器,或者别的。于是三个人有一个人准备写一个纸牌游戏,有一个人准备写计算器。但他们都是打算写CLI界面的程序(也就是大家用C写的最多的那种小黑窗),比如纸牌的类型就用各种字母来代替,计算器的按钮都用\t和\n来排版。

我就有点不甘心,因为好不容易能够做复杂点,为什么还要做这么丑的东西。于是我就开始探索图形化手段。

当时我所有能查找资料的方式就是在百度搜索“C语言 窗口”或者类似“C语言 图形”,而且我记得当时并没有找到一个很好的概述性的入门材料(也许当时到图书馆找一本相关话题的书来看,是更好的选择),而且当时也不知道有Visual Studio这种好东西。但我很幸运地在一个贴子里找到了一个叫allegro的图形库的安装方法,而且正是在CodeBlocks里安装的,并详细给出了如何把该库添加进编译器的include目录,链接器的链接目标里。我就照猫画虎地做了,把allegro库的binary release下载下来,解压,把include目录添加到CodeBlocks里的一个地方,把lib目录添加在CodeBlocks里的另一个地方。因为教程是手把手的,所以顺利地通过了样例程序的编译。

稍微看了看样例程序的源码后,我开始着手尝试画一些简单的图形。因此,当时新建的工程项目取名为”firstdraw”,这也成了最终的游戏的名字。。

然而,样例程序能够显示出各种图形,而我的程序却会crash。显然这相对于编译时报的错误是更难分析的。在毫无经验的情况下,我最终选择了逐行注释掉代码的暴力方式来测试,最后是发现有一个很不起眼的初始化函数没有调用。

仅仅就使用一个工具而言,无论是要配置好allegro库,还是要用MPI写并行程序,还是要用CUDA写GPU计算程序,我觉得最最需要先讲清楚的事情,不是它的技术原理,不是提供包含成百上千个API的文档,也不是直接丢给你样例程序,而是要给一个tutorial,讲清楚它的work flow。Work flow相当于一个使用说明书,从头到尾告诉你一个包含其基本用法的程序应该怎么写,先调用什么后调用什么;或者告诉你各个模块之间是什么关系。这样新手就不会走弯路了。

流程跑通了,之后画各种别的图形也就简单了,因为这些绘图API的作用与格式其实很直观。其实通过读API也能学到很多原理性的东西

也就是这时,我决定准备做一个简单的射击游戏:玩家用方向键控制、敌人随机游走,并不定期发射子弹、玩家用鼠标单击来控制发射子弹。

我当时对如何把较真实的人形绘制出来这种问题不太感兴趣(当然在商业游戏中,做好人形动画和交互,以及与玩家操控方式流畅地整合起来也是十分重要的事情),就直接用蓝色实心圆来代表敌人,红色实心圆代表玩家,黄色圆表示敌人发出的子弹,绿色表示玩家发射的子弹。

最终的效果如下:

game

当然还有好多问题要解决,如获取鼠标指针的位置用哪个API、怎样让敌人隔一段随机时间后才发射一定数量的子弹、怎样检测子弹的碰撞,直接用随机数赋予敌人速度的话,敌人运动抖得很厉害怎么办(用随机数作为加速度,再来计算速度和位移。而不是直接用随机数作为速度),以及发出那么多的子弹用什么数据结构存储(就是用链表,方便删除子弹,没有随机访问的需求)。

该游戏当时有一个败笔,那就是游戏的主循环(main game loop)的两次循环之间没有任何阻塞,这就导致了CPU/GPU有多快,游戏就会跑多快。该游戏在我大一用的旧电脑上跑的速度很和谐,一旦换到Intel i3/i5上面就会快的应不暇接。

最近我花了一天的时间修改了一下代码,解决了之前的败笔,使这个游戏有固定的帧频了,同时把allegro库适配成了最新版本。顺便调了一下参数,让游戏难度提高了一点。感觉还挺有挑战的,至少我一次都没有打赢过。。

游戏的代码仍然是那么丑,毕竟是学C才两个月的时候写的,各种大大小小的函数一盘散沙地堆在main()函数上面。我不打算再改了,所以这个作品可能更适合用来玩,而不是用来学习游戏设计。(其实也不适合用来玩,玩法被室友狠狠地吐槽过。。)

你可以在这里看该小游戏的源代码,也可以直接下载程序来体验。