大二的时候,做了大学里第一个软件课程设计,当时很兴奋,觉得自己就要接触到真正的计算机世界了,于是很早就开始问学长做个什么好,在我老乡学长的影响下,我选择了用C++语言,借助MFC中的几个函数来做一个游戏,算是一个RPG游戏吧,由于我是一个人做的,难免的剧情和设计有些不够台面......但是技术是一点点学的,代码什么的也都是从0开始写,当时老师竟然问我用了什么引擎,看来是我太年轻......这个课设里涉及的问题有:MFC如何显示图片,用重绘消息控制的重绘函数,采用双缓冲技术解决画面闪烁问题,多线程显示图片,多线程变量控制,各种flag全局标记变量的使用(这是一种简单的取巧的笨方法),任务书中计划的几个简单的算法如随机和堆排序之类,还学了点PS技术,毕竟自己做啥都得自己来......(写不下去了)
现在,也就是大三下学期,我又用另一个框架做了一个游戏雏形,是那种纯文字类型的网游,差不多95后们上初中时玩的那种,也是对游戏有点复杂情绪。游戏基本就是用PS技术和无数的判断语句堆起来的。游戏创意设计是最难的部分,程序和软件的功能设计和创新思想是最难得的,而开发技术虽然也难,但都会有局限和上限,只有人的思维不会。
把大二时第一个课设的开发日志贴在这里吧:
代码结构改变过程:
无线程无缓冲不重绘 -> 有线程无缓冲不重绘 -> 有线程有缓冲不重绘 -> 有线程有缓冲可重绘
历史版本:
1.0 剧情基本实现,无线程控制,无双缓冲,无技能,无寻路。剧情播放时点击会崩溃,人物移动过快会闪烁。
2.0 经过对代码结构的整体改动,增加了线程控制,解决了点击崩溃问题,没有解决画面闪烁问题,初步增加技能。
3.0 又一次代码结构的整体改动,增加双缓冲试图解决闪烁问题,失败。
4.0 再一次对代码结构大改,将所有的绘制都放在了OnPaint中(之前是在键鼠响应或者线程中),这次的改动使得上个版本中的双缓冲生效,画面不再闪烁。
5.0 增加技能施放,完善因为代码结构几次改动引起的剧情bug。
6.0 增加对怪物的技能攻击判定,调整技能释放位置。
7.0 写好Boss的场景和剧情,Boss自由走动的AI,Boss追人和放弃的AI,Boss选择技能的AI,杀死Boss判定。
调试心得:
将MFC里的CImage类的load、draw和destroy方法用来贴图,需要获取窗口DC,记得释放资源。
引入头文件放在 stdafx.h 和 stdafx.cpp 中。
去掉默认的东西,如菜单栏等,需要修改 MainFrm.cpp 文件。
调整窗口大小在 LandOfHonor.cpp 中。
代码主要部分在 CChildView.h 和 CChildView.cpp 中。
文件名和路径一定要正确,否则出现 h!=Bitmap 等中止异常。
语句块最后记得释放DC,画完后记得删除加载的图片,这样可以避免冲突,节省变量名空间。
按算法,按想展现的画面,去贴图,算法的展现就是贴图显示的顺序,按算法计算得到的顺序贴图显示。
游戏中进行每一步都会同时画很多图,这就需要许多标志位来判断需要贴哪些图,要注意判断条件和响应。
许多的条件,比如进入房子,进入地图,某个怪物的死活,有关是否与0、1的问题,都可以用一个标志位完成。
由于同时不断地大量贴图,而引起的画面闪动,可以加多线程和加缓冲DC解决(双缓冲)。
透明的问题,用PS将图的背景去掉(魔棒选中然后Delete),然后用函数透明。
一些重复代码的合并、封装,会让程序优化,不冗繁。
用多线程控制的话,体验和代码结构会好很多。
杀怪、怪物死亡、捡战利品,都需要线程支撑。
绘制代码全部要放在onpaint中。
文字描述可以使用MFC中的API,可以减少对外部图片的依赖,节省空间,更灵活的显示剧情。
两种处理方式:
//响应中:标记、使无效 -> OnPaint:绘制、标记、使有效
//响应中:标记、定时器 -> 定时器:使无效 -> OnPaint:绘制、标记、使有效
/*cDC = this->GetDC(); //获得当前窗口的DC
GetClientRect(&client); //获得窗口的尺寸
cacheDC.CreateCompatibleDC(NULL); //创建缓冲DC
cacheCBitmap.CreateCompatibleBitmap(cDC, client.Width(), client.Height());
cacheDC.SelectObject(&cacheCBitmap);
cacheDC.FillSolidRect(client, cDC->GetBkColor());//按原来背景填充客户区,不然会是黑色
........//填写代码
//最后将缓冲DC内容输出到窗口DC中
cDC->BitBlt(0, 0, client.Width(), client.Height(), &cacheDC, 0, 0, SRCCOPY);
ValidateRect(&client); //使绘图区变得有效
cacheDC.DeleteDC(); //释放缓冲DC
cacheCBitmap.DeleteObject(); //释放对象
ReleaseDC(cDC); //释放DC
}*/